#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  Makefile README gdpd-hp.c gdpd.8 gdpd.c irdpd.c
# Wrapped by pst@lager on Mon Jan 20 12:05:32 1992
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'Makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Makefile'\"
else
echo shar: Extracting \"'Makefile'\" \(157 characters\)
sed "s/^X//" >'Makefile' <<'END_OF_FILE'
X
XSOURCES = gdpd.c gdpd-hp.c gdpd.8 README Makefile
XCLEAN	= *.o *~ gdpd gdpd.shar
X
Xdefault: gdpd
X
Xshar:
X	shar -o gdpd.shar $(SOURCES)
X
Xclean:
X	rm -f $(CLEAN)
END_OF_FILE
if test 157 -ne `wc -c <'Makefile'`; then
    echo shar: \"'Makefile'\" unpacked with wrong size!
fi
# end of 'Makefile'
fi
if test -f 'README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(607 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
XThis is an Alpha release of the cisco GDP daemon for Berkeley Un*x.  So
Xfar this program has only been tested on SunOS 3.5.  It will probably
Xneed some work to run on other platforms.  See the man page for details
Xon using the daemon.  It is expected to run standalone and not from
Xinetd.
X
XIf you find any bugs, please report them to customer-service@cisco.com.
XIt will greatly speed up the process if you could include a bug fix
Xwith the bug report.  Send any modifications or new OS ports to me so I
Xcan update it for the benefit of our other customers.
X
XGreg Satz <satz@cisco.com>
Xcisco
XDecember 4, 1989
END_OF_FILE
if test 607 -ne `wc -c <'README'`; then
    echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test -f 'gdpd-hp.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'gdpd-hp.c'\"
else
echo shar: Extracting \"'gdpd-hp.c'\" \(18445 characters\)
sed "s/^X//" >'gdpd-hp.c' <<'END_OF_FILE'
X/*
X * Gateway Discovery Protocol daemon suitable for using on Un*x systems.
X *
X * September 1989, Greg Satz
X *
X * Copyright (c) 1989 by cisco Systems, Inc.
X * All rights reserved.
X */
X
X#include <sys/types.h>
X#include <sys/socket.h>
X#include <sys/ioctl.h>
X#include <sys/file.h>
X#include <sys/mbuf.h>
X
X#ifdef FD_SETSIZE
X#define getdtablesize() FD_SETSIZE
X#endif 
X
X#include <net/if.h>
X#include <net/route.h>
X#include <netinet/in.h>
X#include <netinet/if_ether.h>
X#include <netinet/arp.h>
X
X/* required for HP vna_table processing  */
X#include <net/probe_gdp.h> 
X#include <net/raw8023.h>
X#include <net/lan_802.h> 
X#include <netinet/probe_2.h>
X#include <fcntl.h> 
X#include <memory.h> 
X
X#include <stdio.h>
X#include <signal.h>
X#include <errno.h>
X#include <netdb.h>
X#include <syslog.h>
X#include <nlist.h>
X
X/*
X * Gateway Discovery Protocol definitions
X */
X
X#define	GDP_VERSION	1
X
X/*
X * Operations
X */
X
X#define	GDP_REPORT	1
X#define	GDP_QUERY	2
X
X/*
X * GDP listener port
X */
X
X#define	GDP_PORT	1997
X
X/*
X * GDP packet format
X */
X
Xstruct gdppkt {
X    unsigned char version;
X    unsigned char code;
X    unsigned char count;
X    unsigned char reserved;
X    struct addrgrp {
X	struct in_addr ip;
X	unsigned short priority;
X	unsigned short holdtime;
X    } addrs[1];
X};
X
X#define	ALARM_INTERVAL		1
X
X#define TIOCNOTTY       _IO('t', 113)           /* void tty association */
X
X#define	KERNEL		"/hp-ux"
X#define	MEM		"/dev/kmem"
X
Xstruct nlist nl[] = {
X#define	X_PR_VNATAB	0
X	{ "_pr_vnatab" },
X#define	N_RTHOST	1
X	{ "_rthost" },
X#define	N_RTNET		2
X	{ "_rtnet" },
X#define	X_SPACE		3
X        { " " },
X	{ "" },
X};
X
Xstruct iface {
X    char name[IFNAMSIZ];
X    short flags;
X    struct in_addr ipaddress;
X    struct in_addr ipmask;
X    struct in_addr ipbroadcast;
X    struct iface *next;
X} *iflist;
X
Xstruct neighbor {
X    struct in_addr ip;
X    unsigned short priority;
X    unsigned short holdtime;
X    struct neighbor *next;
X};
X
Xstruct neighbor *rcvd_neighbors;
Xstruct neighbor *sent_neighbors;
X
Xstruct neighbor *default_neighbor;
X
X#define	DEFAULT_PRIORITY	100
X#define	DEFAULT_HOLDTIME	15
X
Xint debug;				/* debugging flag */
Xint flush;				/* flush routing table flag */
Xint logging;				/* syslog logging flag */
Xint hold_time;				/* tell others how often to hold */
Xint metric;				/* how do we run */
Xint priority;				/* what priority do we advertise */
Xint query_time;				/* how often to send queries */
Xint query;
Xint report_time;			/* how often to send reports */
Xint report;
Xint round_robin;			/* how often to cycle parallel gws */
Xint round;
X
Xint m;
Xint s;
Xstruct sockaddr_in from;
Xint fromlen;
Xstruct hostent *hp;
Xstruct servent *sp;
Xunsigned char buf[BUFSIZ];
X
Xint timer();
X
X/*
X * main
X * Perform GDP processing depending on what we were told
X */
X
Xmain (argc, argv)
X    int argc;
X    char *argv;
X{
X    int c, status, on = 1;
X    struct gdppkt *gdp;
X    struct addrgrp ag;
X    struct in_addr bip;
X    extern int errno;
X    extern char *optarg;
X    extern int optind;
X
X    debug = 0;
X    flush = 0;
X    logging = 0;
X    metric = 1;				/* default to one hop */
X    priority = DEFAULT_PRIORITY;
X    hold_time = DEFAULT_HOLDTIME;
X    query_time = 0;
X    report_time = 0;
X    round_robin = 0;
X    iflist = NULL;
X    rcvd_neighbors = NULL;
X    sent_neighbors = NULL;
X    default_neighbor = NULL;
X    bip.s_addr = 0L;
X#ifdef LOG_DAEMON
X    openlog("gdpd", LOG_PID, LOG_DAEMON);
X#else
X    openlog("gdpd", LOG_PID);
X#endif
X    while ((c = getopt(argc, argv, "dfh:lm:p:q:r:t:")) != EOF)
X	switch (c) {
X	case 'd':			/* debug */
X	    debug = 1;
X	    break;
X	case 'f':			/* flush  */
X	    flush = 1;
X	    break;
X	case 'h':			/* hold time */
X	    hold_time = atoi(optarg);
X	    if (hold_time < 0) {
X		syslog(LOG_INFO, "%s: illegal hold time value - %d",
X		    argv[0], hold_time);
X		exit(1);
X	    }
X	    break;
X	case 'l':			/* logging */
X	    logging = 1;
X	    break;
X	case 'm':			/* metric */
X	    metric = atoi(optarg);
X	    if (metric < 0) {
X		syslog(LOG_INFO, "%s: illegal metric value - %d",
X		    argv[0], metric);
X		exit(1);
X	    }
X	    break;
X	case 'p':			/* priority */
X	    priority = atoi(optarg);
X	    if (priority < 0) {
X		syslog(LOG_INFO, "%s: illegal priority value - %d",
X		    argv[0], priority);
X		exit(1);
X	    }
X	    break;
X	case 'q':			/* query */
X	    query_time = atoi(optarg);
X	    if (query_time < 0) {
X		syslog(LOG_INFO, "%s: illegal querying value - %d",
X		    argv[0], query_time);
X		exit(1);
X	    }
X	    break;
X	case 'r':			/* report */
X	    report_time = atoi(optarg);
X	    if (report_time < 0) {
X		syslog(LOG_INFO, "%s: illegal reporting value - %d",
X		    argv[0], report_time);
X		exit(1);
X	    }
X	    break;
X	case 't':			/* time */
X	    round_robin = atoi(optarg);
X	    if (round_robin < 0) {
X		syslog(LOG_INFO, "%s: illegal round robin value - %d",
X		    argv[0], round_robin);
X		exit(1);
X	    }
X	    round_robin *= 60;		/* make seconds */
X	    break;
X	default:
X	    syslog(LOG_INFO, "%s: illegal switch -%s", argv[0], optarg);
X	    exit(1);
X	}
X
X    if (query_time != 0 && report_time != 0) {
X	syslog(LOG_INFO, "%s: cannot report and query simultaneously.\n",
X	    argv[0]);
X	exit(1);
X    }
X    bzero(&ag, sizeof(struct addrgrp));
X    while (argc != optind) {
X	ag.ip.s_addr = inet_addr(argv[optind]);
X	if (ag.ip.s_addr == -1) {
X	    hp = gethostbyname(argv[optind]);
X	    if (hp == NULL) {
X		syslog(LOG_INFO, "%s: %s: unknown host\n", argv[0],
X		    argv[optind]);
X		exit(1);
X	    }
X	    bcopy(hp->h_addr, &ag.ip, sizeof(ag.ip));
X	}
X	enter_neighbor(&sent_neighbors, &ag);
X	optind++;
X    }
X    query = query_time;
X    report = report_time;
X    round = round_robin;
X    if (!debug) {
X        status = fork();
X	if (fork() != 0) { 
X            syslog(LOG_ERR, " %i, fork kills the parent",status);
X	    exit(0);
X        }
X	for (c = 0; c < getdtablesize(); c++) {    
X	    (void) close(c);
X        }    
X	(void) open("/", O_RDONLY);
X	(void) dup2(0, 1);
X	(void) dup2(0, 2);
X	c = open("/dev/tty", O_RDWR);
X	if (c >= 0) {
X	    ioctl(c, TIOCNOTTY, (char *)0);
X	    (void) close(c);
X	} 
X
X    if (metric == 0 || flush) {
X	nlist(KERNEL, nl);
X	if (nl[X_PR_VNATAB].n_value == 0) {
X            syslog(LOG_INFO," failed vnatab nlist ");
X	}
X	if (nl[N_RTHOST].n_value == 0) {
X            syslog(LOG_INFO," failed rthost nlist ");
X	    exit(1);
X	}
X	if (nl[N_RTNET].n_value == 0) {
X            syslog(LOG_INFO," failed rtnet nlist ");
X	    exit(1);
X	}
X	m = open(MEM, O_RDONLY);
X	if (m < 0) {
X	    exit(1);
X	}
X    }
X    if (debug)
X	syslog(LOG_DEBUG, "server starting");
X
X#ifdef LOG_DAEMON
X	openlog("gdpd", LOG_PID, LOG_DAEMON);
X#else
X	openlog("gdpd", LOG_PID);
X#endif
X    }
X
X    /*
X     * Getgetd listener socket
X     */
X    if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
X	syslog(LOG_ERR, "socket: %m");
X	exit(1);
X    }
X
X#ifdef SO_BROADCAST
X    if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0) {
X	syslog(LOG_ERR, "setsockopt: %m");
X	exit(1);
X    }
X#endif
X
X    /*
X     * Get port we need to pay attention to
X     */
X    bzero((caddr_t)&from, sizeof(from));
X    from.sin_family = AF_INET;
X    from.sin_addr.s_addr = INADDR_ANY;
X    sp = getservbyname("gdp", "udp");
X    if (sp == NULL)
X	from.sin_port = htons(GDP_PORT);
X    else
X	from.sin_port = htons(sp->s_port);
X
X    if (bind(s, &from, sizeof(from)) < 0) {
X	syslog(LOG_ERR, "bind: %m");;
X	exit(1);
X    }
X
X    build_iflist();
X    send_query(bip);
X    signal(SIGALRM, timer);
X    timer();
X
X    /*
X     * Now do the work
X     */
X
X    for (;;) {
X       syslog(LOG_ERR, "in for loop");
X	fromlen = sizeof(from);
X	c = recvfrom(s, buf, sizeof(buf), 0, (caddr_t)&from, &fromlen);
X	if (c <= 0) {
X	    if (errno == EINTR)
X		continue;
X	    syslog(LOG_ERR, "recvfrom: %m");
X	    exit(1);
X	}
X	gdp = (struct gdppkt *)buf;
X	if (gdp->version != GDP_VERSION)
X	    continue;
X	if (debug) {
X	    hp = gethostbyaddr(&from.sin_addr, sizeof(struct in_addr),
X		AF_INET);
X	    syslog(LOG_DEBUG, "%s received from %s", (gdp->code == GDP_REPORT
X		? "REPORT" : (gdp->code == GDP_QUERY ? "QUERY" : "UNKNOWN")),
X		hp ? hp->h_name : (char *)inet_ntoa(from.sin_addr));
X	}
X	switch (gdp->code) {
X	case GDP_REPORT:
X	    if (report_time == 0)
X		process_report(&from, gdp);
X	    break;
X	case GDP_QUERY:
X	    if (report_time != 0)
X		process_query(&from, gdp);
X	    break;
X	default:
X	    break;
X	}
X    }
X}
X
X/*
X * find_neighbor
X * Look for a given neighbor in the list and return ptr or NULL
X */
X
Xstruct neighbor *find_neighbor (nt, ip)
X    struct neighbor **nt;
X    struct in_addr ip;
X{
X    struct neighbor *p;
X
X    for (p = *nt; p != NULL; p = p->next)
X	if (p->ip.s_addr == ip.s_addr)
X	    break;
X    return(p);
X}
X
X/*
X * enter_neighbor
X * Enter a new neighbor into the table in priority order
X */
X
Xenter_neighbor (nt, ag)
X    struct neighbor **nt;
X    struct addrgrp *ag;
X{
X    struct neighbor *p, *pp, *newp;
X
X    newp = (struct neighbor *)malloc(sizeof(struct neighbor));
X    if (newp == NULL)
X	return;
X
X    newp->ip = ag->ip;
X    newp->priority = ag->priority;
X    newp->holdtime = ag->holdtime;
X    newp->next = NULL;
X    for (p = pp = *nt; p != NULL; pp = p, p = p->next)
X	if (p->priority >= newp->priority)
X	    continue;
X    if (p == NULL) {
X	if (*nt == NULL)
X	    *nt = newp;
X	else
X	    pp->next = newp;
X    } else if (p == pp) {
X	newp->next = *nt;
X	*nt = newp;
X    } else {
X	pp->next = newp;
X	newp->next = p;
X    }
X}
X
X/*
X * delete_neighbor
X * Remove neighbor from the list
X */
X
Xdelete_neighbor (nt, dp)
X    struct neighbor **nt;
X    struct neighbor *dp;
X{
X    struct neighbor *p, *pp;
X
X    for (p = pp = *nt; p != NULL; pp = p, p = p->next)
X	if (p == dp)
X	    break;
X    if (p == pp)
X	*nt = p->next;
X    else
X	pp->next = p->next;
X    free(p);
X
X}
X
X/*
X * robin_neighbor
X * Perform round robin on received neighbors of equal priority
X */
X
Xrobin_neighbor ()
X{
X    struct neighbor *p, *pp;
X
X    /*
X     * Find where next lower priorty starts
X     */
X    for (p = pp = rcvd_neighbors; p != NULL; p = p->next)
X	if (default_neighbor->priority > p->priority)
X	    break;
X    /*
X     * If there is only a single entry, then don't bother
X     */
X    if (default_neighbor == pp)
X	return;
X
X    /*
X     * Splice old one at end of equal priority list
X     */
X    rcvd_neighbors = default_neighbor->next;
X    pp->next = default_neighbor;
X    default_neighbor->next = p;
X    update_routes();
X}
X
X/*
X * process_report
X * handle processing of GDP report messages
X */
X
Xprocess_report (from, gdp)
X    struct sockaddr_in *from;
X    struct gdppkt *gdp;
X{
X    struct neighbor *p;
X    struct addrgrp *a;
X
X    a = gdp->addrs;
X    while (gdp->count-- > 0) {
X	if (valid_address(a->ip)) {
X	    p = find_neighbor(&sent_neighbors, a->ip);
X	    if (p != NULL)
X		p->holdtime = a->holdtime;
X	    p = find_neighbor(&rcvd_neighbors, a->ip);
X	    if (p == NULL || p->priority != a->priority) {
X		if (p != NULL) {
X		    if (flush) {
X                        flush_routes(p->ip);
X                    }
X		    delete_neighbor(&rcvd_neighbors, p);
X		}
X		enter_neighbor(&rcvd_neighbors, a);
X		update_routes();
X		round = round_robin;		/* restart timer */
X	    } else
X		p->holdtime = a->holdtime;
X	} else if (debug)
X	    syslog(LOG_DEBUG, "invalid IP address: %s",
X		inet_ntoa(a->ip));
X	a++;
X    }
X}
X
X/*
X * process_query
X * Process a QUERY and return a REPORT
X */
X
Xprocess_query (from, gdp)
X    struct sockaddr_in *from;
X    struct gdppkt *gdp;
X{
X}
X
X/*
X * timer
X * Wake up once in a while and process running timers, etc.
X */
X
Xtimer ()
X{
X    struct neighbor *p, *dp;
X    struct in_addr bip;
X
X    bip.s_addr = 0L;
X    if (report_time != 0) {
X	if (report <= 0) {
X	    send_report(bip);
X	    report = report_time;
X	} else
X	    report -= ALARM_INTERVAL;
X    } else {
X	if (query_time != 0) {
X	    query -= ALARM_INTERVAL;
X	    if (query <= 0) {
X		for (p = sent_neighbors; p != NULL; p = p->next)
X		    send_query(p->ip);
X		query = query_time;
X	    }
X	}
X	for (p = rcvd_neighbors; p != NULL; ) {
X	    dp = p;
X	    p = p->next;
X	    dp->holdtime -= ALARM_INTERVAL;
X	    if (dp->holdtime <= 0) {
X		if (flush) {
X		    flush_routes(dp->ip); 
X                }
X    		delete_neighbor(&rcvd_neighbors, dp);
X		update_routes();
X		round = round_robin;		/* restart timer */
X	    }
X	}
X    }
X    if (round_robin != 0) {
X	round -= ALARM_INTERVAL;
X	if (round <= 0) {
X	    if (default_neighbor != NULL)
X		robin_neighbor();
X	    round = round_robin;
X	}
X    }
X    alarm(ALARM_INTERVAL);
X}
X
X/*
X * send_query
X * Send a GDP query message
X */
X
Xsend_query (ip)
X    struct in_addr ip;
X{
X    struct gdppkt gdp;
X    struct sockaddr_in sin;
X    struct iface *ifp;
X    struct neighbor *p;
X
X    bzero(&gdp, sizeof(gdp));
X    gdp.version = GDP_VERSION;
X    gdp.code = GDP_QUERY;
X    bzero(&sin, sizeof(sin));
X    sin.sin_family = AF_INET;
X    sin.sin_addr = ip;
X    if (sp == NULL)
X	sin.sin_port = htons(GDP_PORT);
X    else
X	sin.sin_port = htons(sp->s_port);
X    if (ip.s_addr == 0L) {
X	for (ifp = iflist; ifp != NULL; ifp = ifp->next) {
X	    if ((ifp->flags & IFF_BROADCAST) == 0)
X		continue;
X	    sin.sin_addr = ifp->ipbroadcast;
X	    (void) sendto(s, &gdp, sizeof(gdp) - sizeof(struct addrgrp), 0,
X		&sin, sizeof(sin));
X	}
X	for (p = sent_neighbors; p != NULL; p = p->next)
X	    send_query(p->ip);
X    } else
X	(void) sendto(s, &gdp, sizeof(gdp) - sizeof(struct addrgrp), 0,
X	    &sin, sizeof(sin));
X}
X
X/*
X * send_report
X * Send a GDP REPORT message
X */
X
Xsend_report (ip)
X    struct in_addr ip;
X{
X}
X
X/*
X * build_iflist
X * Build a list of interfaces and accompaning information
X */
X
Xbuild_iflist ()
X{
X    int n;
X    char ifbuf[BUFSIZ];
X    struct ifconf ifc;
X    struct ifreq *ifr, ifreq;
X    struct iface *ifp;
X    struct sockaddr_in *sa;
X    short flags;
X
X    ifc.ifc_len = sizeof(ifbuf);
X    ifc.ifc_buf = ifbuf;
X    if (ioctl(s, SIOCGIFCONF, &ifc) < 0) {
X	syslog(LOG_ERR, "ioctl(IFCONF): %m");
X	exit(1);
X    }
X    ifr = ifc.ifc_req;
X    for (n = ifc.ifc_len / sizeof(struct ifreq); n > 0; n--, ifr++) {
X	/*
X	 * Ignore the loopback interface
X	 */
X	if (strncmp(ifr->ifr_name, "lo", 2) == 0)
X	    continue;
X	/*
X	 * Ignore all interfaces which aren't running
X	 */
X	strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
X	if (ioctl(s, SIOCGIFFLAGS, &ifreq) < 0)
X	    continue;
X	else
X	    flags = ifreq.ifr_flags;
X	if ((flags & IFF_RUNNING) == 0)
X	    continue;
X	sa = (struct sockaddr_in *)&ifr->ifr_addr;
X	/*
X	 * Ignore 0.0.0.0
X	 */
X	if (sa->sin_addr.s_addr == 0L)
X	    continue;
X	ifp = (struct iface *)malloc(sizeof(struct iface));
X	if (ifp == NULL)
X	    break;
X	bzero(ifp, sizeof(struct iface));
X	strncpy(ifp->name, ifr->ifr_name, sizeof(ifp->name));
X	ifp->ipaddress = sa->sin_addr;
X	ifp->flags = flags;
X	strncpy(ifreq.ifr_name, ifp->name, sizeof(ifp->name));
X	if (ioctl(s, SIOCGIFNETMASK, &ifreq) >= 0) {
X	    sa = (struct sockaddr_in *)&ifreq.ifr_addr;
X	    ifp->ipmask = sa->sin_addr;
X	}
X	if (ifp->flags & IFF_BROADCAST) {
X	    strncpy(ifreq.ifr_name, ifp->name, sizeof(ifp->name));
X	    if (ioctl(s, SIOCGIFBRDADDR, &ifreq) >= 0) {
X		sa = (struct sockaddr_in *)&ifreq.ifr_addr;
X		ifp->ipbroadcast = sa->sin_addr;
X	    }
X	}
X	if (iflist == NULL)
X	    iflist = ifp;
X	else {
X	    ifp->next = iflist;
X	    iflist = ifp;
X	}
X    }
X}
X
X/*
X * valid_address
X * Determine if give IP address is something we grok.
X */
X
Xvalid_address (ip)
X    struct in_addr ip;
X{
X    struct iface *ifp;
X
X    for (ifp = iflist; ifp != NULL; ifp = ifp->next) {
X	if ((ip.s_addr & ifp->ipmask.s_addr) ==
X	    (ifp->ipaddress.s_addr & ifp->ipmask.s_addr))
X	    return(1);
X    }
X    return(0);
X}
X
X/*
X * update_routes
X * Update default route if necessary when something changes
X */
X
Xupdate_routes ()
X{
X    struct rtentry rt;
X    struct sockaddr_in *sa;
X    struct in_addr inet_makeaddr();
X
X    if (default_neighbor == rcvd_neighbors)
X	return;
X
X    bzero(&rt, sizeof(rt));
X    rt.rt_flags = RTF_UP;
X    if (metric > 0)
X	rt.rt_flags |= RTF_GATEWAY;
X    sa = (struct sockaddr_in *)&rt.rt_dst;
X    sa->sin_family = AF_INET;
X    sa->sin_addr = inet_makeaddr(0, INADDR_ANY);
X    sa = (struct sockaddr_in *)&rt.rt_gateway;
X    sa->sin_family = AF_INET;
X    if (default_neighbor != NULL) {
X	sa->sin_addr = default_neighbor->ip;
X	if (metric == 0)
X	    flush_vna();
X	if (logging)
X	    syslog(LOG_INFO, "deleting old default: %s",
X		inet_ntoa(sa->sin_addr));
X	if (!debug)
X	    (void) ioctl(s, SIOCDELRT, &rt);
X    }
X    default_neighbor = rcvd_neighbors;
X    if (default_neighbor == NULL)
X	return;
X    sa->sin_addr = default_neighbor->ip;
X    if (logging)
X	syslog(LOG_INFO, "adding new default: %s",
X	    inet_ntoa(sa->sin_addr));
X    if (!debug)
X	(void) ioctl(s, SIOCADDRT, &rt);
X}
X
X
X/*
X * flush_routes
X * Flush the routing table. We do this when asked.
X */
X
Xflush_routes (ip)
X    struct in_addr ip;
X{
X    struct in_addr in;
X    struct mbuf mb;
X    register struct rtentry *rt;
X    register struct mbuf *mbp;
X    struct mbuf **routehash;
X    int rthashsize, i, doinghost = 1;
X
X    if (logging)
X	syslog(LOG_INFO, "flushing routes via %s", inet_ntoa(ip));
X    lseek(m, nl[X_SPACE].n_value, 0);
X    read(m, &rthashsize, sizeof (rthashsize));
X    routehash = (struct mbuf **)malloc(rthashsize*sizeof (struct mbuf *));
X    lseek(m, nl[N_RTHOST].n_value, 0);
X    read(m, routehash, rthashsize*sizeof (struct mbuf *));
Xagain:
X    for (i = 0; i < rthashsize; i++) {
X        syslog(LOG_INFO, "entered again ");
X	if (routehash[i] == 0)
X	    continue;
X       syslog(LOG_INFO, "passed again ");
X	mbp = routehash[i];
X	    while (mbp) {
X		lseek(m, mbp, 0);
X		read(m, &mb, sizeof (mb));
X		rt = mtod(&mb, struct rtentry *);
X		if ((rt->rt_flags & RTF_GATEWAY) &&
X		    rt->rt_gateway.sa_family == AF_INET) {
X		    in = ((struct sockaddr_in *)&rt->rt_gateway)->sin_addr;
X		    if (in.s_addr == ip.s_addr) {
X			if (logging) {
X			    in = ((struct sockaddr_in *)&rt->rt_dst)->sin_addr
X;
X			    syslog(LOG_INFO, "flushing route %s",
X				inet_ntoa(in));
X			}
X			if (!debug)
X			    (void) ioctl(s, SIOCDELRT, (caddr_t)rt);
X		    }
X		}
X		mbp = mb.m_next;
X	    }
X    }
X    if (doinghost) {
X	lseek(m, nl[N_RTNET].n_value, 0);
X	read(m, routehash, rthashsize*sizeof (struct mbuf *));
X	doinghost = 0;
X	goto again;
X    }
X    free(routehash);
X}
X
Xflush_vna()
X
X{
X
Xint n, status;
X
Xextern int errno;
X
Xstruct vnatab pr_vnatab[VNATAB_SIZE];
X
Xstruct vnatab vna_entry;
X
Xsyslog(LOG_ERR,"flushing vnatab");
X
Xn = open(MEM,O_RDWR);
X
Xif (n == -1) {
X    syslog(LOG_ERR,"%i, mem open failed",errno);
X    exit(1);
X    }
X
X(void) memset(pr_vnatab, 0, sizeof(pr_vnatab));
X
Xstatus =  (lseek(n, (long) nl[X_PR_VNATAB].n_value, 0));
Xif  (status == -1) {
X    syslog(LOG_ERR,"%i, lseek failed",errno);
X    exit(1);
X   }    
X
X(void) write(n, pr_vnatab, sizeof(pr_vnatab));
X(void) close(n);
X
X}
END_OF_FILE
if test 18445 -ne `wc -c <'gdpd-hp.c'`; then
    echo shar: \"'gdpd-hp.c'\" unpacked with wrong size!
fi
# end of 'gdpd-hp.c'
fi
if test -f 'gdpd.8' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'gdpd.8'\"
else
echo shar: Extracting \"'gdpd.8'\" \(3538 characters\)
sed "s/^X//" >'gdpd.8' <<'END_OF_FILE'
X.TH GDPD 8 "20 September 1989"
X.SH NAME
Xgdpd \- Gateway Discover Protocol Daemon
X.SH SYNOPSIS
Xgdpd
X[
X.B \-d
X] 
X[
X.B \-f
X] 
X[
X.B \-h hold-time
X]
X[
X.B \-l
X] 
X[
X.B \-m metric
X] 
X[
X.B \-p priority
X] 
X[
X.B \-q query-time
X] 
X[
X.B \-r report-time
X] 
X[
X.B \-t cycle-time
X] 
X[ 
X.I IP-address .\|.\|.
X]
X.br
X.SH DESCRIPTION
XThe
X.I gdpd
Ximplements the
X.B cisco
X.I Gateway Discovery Protocol.
XThis protocol permits hosts to discover routers on a connected network.
XMultiple routers can be running the
X.B GDP
Xand hosts can choose to use one or more of them to forward traffic. Hosts
Xlistening for
X.B GDP
Xmessages can learn when a router goes down or when a new router
Xcomes up.
XThe
X.B GDP
Xis implemented above the
X.B UDP
Xand listens on port number 1997 decimal.
X.LP
XThis implementation will act as both
X.B GDP
Xserver and client. That is, it can perform both router and host functions
Xbut not simultaneously. The switches described below will determine
Xwhether the daemon is acting as a listener or server.
X.LP
XWhen acting as a server,
X.B GDP
X.I REPORT
Xmessages are sent at regular intervals and
X.I QUERY
Xmessages are answered. All network interfaces that are up and running
Xand are assigned an
X.B IP
Xaddress will participate in the protocol. When acting as a client, all
Xnetwork interfaces that are up and running and are assigned
X.B IP
Xaddresses will receive
X.B GDP
Xmessages. A
X.B GDP
X.I QUERY
Xmessage is sent to each interface's broadcast address when the daemon
Xfirst starts up.
X.B GDP
X.I REPORT
Xmessages are processed but
X.I QUERY
Xmessages are ignored.
X.B IP
Xaddresses can be specified and
X.B GDP
X.I QUERY
Xmessages will be sent directly to that address at periodic intervals.
XThe best router or collection of routers will be used as the default
Xroute.
X.br
X.SH OPTIONS
X.IP \fB\-d\fP
XEnable debugging information via
X.IR syslog(8)
Xmessages.
X.IP \fB\-f\fP
XWill flush all routes via router that times out or stops sending reports.
XThis makes sure redirects are removed from the routing table so new routes
Xcan be learned.
X.IP \fB\-h\ hold-time\fP
XSets the holding time value in the
X.B GDP
X.I REPORT
Xmessages when \fB\-r\fP is used. The default value is 15 seconds.
X.IP \fB\-l\fP
XEnable logging of interesting events via
X.IR syslog(8).
XInteresting events are changing routes, flushing the
X.B ARP
Xcache, etc. Normally
X.B gdpd
Xruns silently.
X.IP \fB\-m\ metric\fP
XWhen setting the default route, use this value as the metric. If
Xzero is specified,
X.B proxy ARP
Xis presumed to be in use and the
X.B ARP
Xcache will be cleared when the default route changes. The default
Xmetric is 1.
X.IP \fB\-p\ priority\fP
XSpecifies the priority value in the
X.B GDP
X.I REPORT
Xmessages when \fB\-r\fP is used. The default value is 100.
X.IP \fB\-q\ query-time\fP
XWhen running over interfaces which do not support broadcast or multicast,
Xa query interval can be specified so
X.I QUERY
Xmessages can be sent directly to specified
X.B IP
Xpeers. By default, this value is not set.
X.IP \fB\-r\ report-time\fP
XForce the daemon to send
X.I REPORT
Xmessages at the specified interval in seconds. This flag should
Xbe used when the host is acting as a router. By default, this value is
Xnot set.
X.IP \fB\-t\ cycle-time\fP
XWhen multiple routers are using the same priority value, normally the first
Xrouter learned will be used as default. If this flag is used, each router at
Xthe highest priority will be used in a round-robin fashion for
X.B cycle-time
Xminutes.
X.SH "SEE ALSO"
X.I "cisco Systems Release 8.0 Beta Notes"
X.SH BUGS
XThe
X.B \-r
Xoption for sending
X.I REPORT
Xmessages isn't finished.
END_OF_FILE
if test 3538 -ne `wc -c <'gdpd.8'`; then
    echo shar: \"'gdpd.8'\" unpacked with wrong size!
fi
# end of 'gdpd.8'
fi
if test -f 'gdpd.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'gdpd.c'\"
else
echo shar: Extracting \"'gdpd.c'\" \(19941 characters\)
sed "s/^X//" >'gdpd.c' <<'END_OF_FILE'
X/*
X * Gateway Discovery Protocol daemon suitable for using on Un*x systems.
X *
X * September 1989, Greg Satz
X *
X * Copyright (c) 1989 by cisco Systems, Inc.
X * All rights reserved.
X */
X
X#include <sys/types.h>
X#include <sys/socket.h>
X#include <sys/ioctl.h>
X#include <sys/file.h>
X#include <sys/mbuf.h>
X
X#include <net/if.h>
X#include <net/route.h>
X#include <netinet/in.h>
X#ifndef pyr
X#include <netinet/if_ether.h>
X#else
X#include <net/if_ether.h>
X#endif
X
X#include <stdio.h>
X#include <signal.h>
X#include <errno.h>
X#include <netdb.h>
X#include <syslog.h>
X#include <nlist.h>
X
X/*
X * Gateway Discovery Protocol definitions
X */
X
X#define	GDP_VERSION	1
X
X/*
X * Operations
X */
X
X#define	GDP_REPORT	1
X#define	GDP_QUERY	2
X
X/*
X * GDP listener port
X */
X
X#define	GDP_PORT	1997
X
X/*
X * GDP packet format
X */
X
Xstruct gdppkt {
X    unsigned char version;
X    unsigned char code;
X    unsigned char count;
X    unsigned char reserved;
X    struct addrgrp {
X	struct in_addr ip;
X	unsigned short priority;
X	unsigned short holdtime;
X    } addrs[1];
X};
X
X#define	ALARM_INTERVAL		1
X
X#define	KERNEL		"/vmunix"
X#define	MEM		"/dev/kmem"
X
Xstruct nlist nl[] = {
X#define	X_ARPTAB	0
X	{ "_arptab" },
X#define	X_ARPTAB_SIZE	1
X	{ "_arptab_size" },
X#define	N_RTHOST	2
X	{ "_rthost" },
X#define	N_RTNET		3
X	{ "_rtnet" },
X#define	N_RTHASHSIZE	4
X	{ "_rthashsize" },
X	{ "" },
X};
X
Xstruct iface {
X    char name[IFNAMSIZ];
X    short flags;
X    struct in_addr ipaddress;
X    struct in_addr ipmask;
X    struct in_addr ipbroadcast;
X    struct iface *next;
X} *iflist;
X
Xstruct neighbor {
X    struct in_addr ip;
X    unsigned short priority;
X    unsigned short holdtime;
X    struct neighbor *next;
X};
X
Xstruct neighbor *rcvd_neighbors;
Xstruct neighbor *sent_neighbors;
X
Xstruct neighbor *default_neighbor;
X
X#define	DEFAULT_PRIORITY	100
X#define	DEFAULT_HOLDTIME	15
X
Xint debug;				/* debugging flag */
Xint flush;				/* flush routing table flag */
Xint logging;				/* syslog logging flag */
Xint hold_time;				/* tell others how often to hold */
Xint metric;				/* how do we run */
Xint priority;				/* what priority do we advertise */
Xint query_time;				/* how often to send queries */
Xint query;
Xint report_time;			/* how often to send reports */
Xint report;
Xint round_robin;			/* how often to cycle parallel gws */
Xint round;
X
Xint s;
Xstruct sockaddr_in from;
Xint fromlen;
Xstruct hostent *hp;
Xstruct servent *sp;
Xunsigned char buf[BUFSIZ];
X
Xint timer();
X
X/*
X * main
X * Perform GDP processing depending on what we were told
X */
X
Xmain (argc, argv)
X    int argc;
X    char *argv;
X{
X    int c, on = 1;
X    struct gdppkt *gdp;
X    struct addrgrp ag;
X    struct in_addr bip;
X    int oldmask;
X    extern char *optarg;
X    extern int optind;
X    extern int errno;
X
X    debug = 0;
X    flush = 0;
X    logging = 0;
X    metric = 1;				/* default to one hop */
X    priority = DEFAULT_PRIORITY;
X    hold_time = DEFAULT_HOLDTIME;
X    query_time = 0;
X    report_time = 0;
X    round_robin = 0;
X    iflist = NULL;
X    rcvd_neighbors = NULL;
X    sent_neighbors = NULL;
X    default_neighbor = NULL;
X    bip.s_addr = 0L;
X#ifdef LOG_DAEMON
X    openlog("gdpd", LOG_PID, LOG_DAEMON);
X#else
X    openlog("gdpd", LOG_PID);
X#endif
X    while ((c = getopt(argc, argv, "dfh:lm:p:q:r:t:")) != EOF)
X	switch (c) {
X	case 'd':			/* debug */
X	    debug = 1;
X	    break;
X	case 'f':			/* flush  */
X	    flush = 1;
X	    break;
X	case 'h':			/* hold time */
X	    hold_time = atoi(optarg);
X	    if (hold_time < 0) {
X		fprintf(stderr, "%s: illegal hold time value - %d",
X		    argv[0], hold_time);
X		exit(1);
X	    }
X	    break;
X	case 'l':			/* logging */
X	    logging = 1;
X	    break;
X	case 'm':			/* metric */
X	    metric = atoi(optarg);
X	    if (metric < 0) {
X		fprintf(stderr, "%s: illegal metric value - %d",
X		    argv[0], metric);
X		exit(1);
X	    }
X	    break;
X	case 'p':			/* priority */
X	    priority = atoi(optarg);
X	    if (priority < 0) {
X		fprintf(stderr, "%s: illegal priority value - %d",
X		    argv[0], priority);
X		exit(1);
X	    }
X	    break;
X	case 'q':			/* query */
X	    query_time = atoi(optarg);
X	    if (query_time < 0) {
X		fprintf(stderr, "%s: illegal querying value - %d",
X		    argv[0], query_time);
X		exit(1);
X	    }
X	    break;
X	case 'r':			/* report */
X	    report_time = atoi(optarg);
X	    if (report_time < 0) {
X		fprintf(stderr, "%s: illegal reporting value - %d",
X		    argv[0], report_time);
X		exit(1);
X	    }
X	    break;
X	case 't':			/* time */
X	    round_robin = atoi(optarg);
X	    if (round_robin < 0) {
X		fprintf(stderr, "%s: illegal round robin value - %d",
X		    argv[0], round_robin);
X		exit(1);
X	    }
X	    round_robin *= 60;		/* make seconds */
X	    break;
X	default:
X	    fprintf(stderr, "%s: illegal switch -%s", argv[0], optarg);
X	    exit(1);
X	}
X
X    if (query_time != 0 && report_time != 0) {
X	fprintf(stderr, "%s: cannot report and query simultaneously.\n",
X	    argv[0]);
X	exit(1);
X    }
X    bzero(&ag, sizeof(struct addrgrp));
X    while (argc != optind) {
X	ag.ip.s_addr = inet_addr(argv[optind]);
X	if (ag.ip.s_addr == -1) {
X	    hp = gethostbyname(argv[optind]);
X	    if (hp == NULL) {
X		fprintf(stderr, "%s: %s: unknown host\n", argv[0],
X		    argv[optind]);
X		exit(1);
X	    }
X	    bcopy(hp->h_addr, &ag.ip, sizeof(ag.ip));
X	}
X	enter_neighbor(&sent_neighbors, &ag);
X	optind++;
X    }
X    query = query_time;
X    report = report_time;
X    round = round_robin;
X    if (metric == 0 || flush) {
X	nlist(KERNEL, nl);
X	if (nl[X_ARPTAB].n_value == 0) {
X	    fprintf(stderr, "%s: %s: bad namelist\n", argv[0], KERNEL);
X	    exit(1);
X	}
X	if (nl[X_ARPTAB_SIZE].n_value == 0) {
X	    fprintf(stderr, "%s: %s: bad namelist\n", argv[0], KERNEL);
X	    exit(1);
X	}
X	if (nl[N_RTHOST].n_value == 0) {
X	    fprintf(stderr, "%s: %s: bad namelist\n", argv[0], KERNEL);
X	    exit(1);
X	}
X	if (nl[N_RTNET].n_value == 0) {
X	    fprintf(stderr, "%s: %s: bad namelist\n", argv[0], KERNEL);
X	    exit(1);
X	}
X	if (nl[N_RTHASHSIZE].n_value == 0) {
X	    fprintf(stderr, "%s: %s: bad namelist\n", argv[0], KERNEL);
X	    exit(1);
X	}
X    }
X    if (debug)
X	syslog(LOG_DEBUG, "server starting");
X
X    if (!debug) {
X	if (fork())
X	    exit(0);
X	for (c = 0; c < getdtablesize(); c++)
X	    (void) close(c);
X	(void) open("/", O_RDONLY);
X	(void) dup2(0, 1);
X	(void) dup2(0, 2);
X	c = open("/dev/tty", O_RDWR);
X	if (c >= 0) {
X	    ioctl(c, TIOCNOTTY, (char *)0);
X	    (void) close(c);
X	}
X#ifdef LOG_DAEMON
X	openlog("gdpd", LOG_PID, LOG_DAEMON);
X#else
X	openlog("gdpd", LOG_PID);
X#endif
X    }
X
X    /*
X     * Get listener socket
X     */
X    if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
X	syslog(LOG_ERR, "socket: %m");
X	exit(1);
X    }
X
X#ifdef SO_BROADCAST
X    if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0) {
X	syslog(LOG_ERR, "setsockopt: %m");
X	exit(1);
X    }
X#endif
X
X    /*
X     * Get port we need to pay attention to
X     */
X    bzero((caddr_t)&from, sizeof(from));
X    from.sin_family = AF_INET;
X    from.sin_addr.s_addr = INADDR_ANY;
X    sp = getservbyname("gdp", "udp");
X    if (sp == NULL)
X	from.sin_port = htons(GDP_PORT);
X    else
X	from.sin_port = htons(sp->s_port);
X
X    if (bind(s, &from, sizeof(from)) < 0) {
X	syslog(LOG_ERR, "bind: %m");
X	exit(1);
X    }
X
X    build_iflist();
X    send_query(bip);
X    signal(SIGALRM, timer);
X    timer();
X
X    /*
X     * Now do the work
X     */
X
X    for (;;) {
X	fromlen = sizeof(from);
X	c = recvfrom(s, buf, sizeof(buf), 0, (caddr_t)&from, &fromlen);
X	if (c <= 0) {
X	    if (errno == EINTR)
X		continue;
X	    syslog(LOG_ERR, "recvfrom: %m");
X	    exit(1);
X	}
X	gdp = (struct gdppkt *)buf;
X	if (gdp->version != GDP_VERSION)
X	    continue;
X	if (debug) {
X	    hp = gethostbyaddr(&from.sin_addr, sizeof(struct in_addr),
X		AF_INET);
X	    syslog(LOG_DEBUG, "%s received from %s", (gdp->code == GDP_REPORT
X		? "REPORT" : (gdp->code == GDP_QUERY ? "QUERY" : "UNKNOWN")),
X		hp ? hp->h_name : (char *)inet_ntoa(from.sin_addr));
X	}
X
X	oldmask = sigblock(sigmask(SIGALRM));
X	switch (gdp->code) {
X	case GDP_REPORT:
X	    if (report_time == 0)
X		process_report(&from, gdp);
X	    break;
X	case GDP_QUERY:
X	    if (report_time != 0)
X		process_query(&from, gdp);
X	    break;
X	default:
X	    break;
X	}
X	sigsetmask(oldmask);
X    }
X}
X
X/*
X * find_neighbor
X * Look for a given neighbor in the list and return ptr or NULL
X */
X
Xstruct neighbor *find_neighbor (nt, ip)
X    struct neighbor **nt;
X    struct in_addr ip;
X{
X    struct neighbor *p;
X
X    for (p = *nt; p != NULL; p = p->next)
X	if (p->ip.s_addr == ip.s_addr)
X	    break;
X    return(p);
X}
X
X/*
X * enter_neighbor
X * Enter a new neighbor into the table in priority order
X */
X
Xenter_neighbor (nt, ag)
X    struct neighbor **nt;
X    struct addrgrp *ag;
X{
X    struct neighbor *p, *pp, *newp;
X
X    newp = (struct neighbor *)malloc(sizeof(struct neighbor));
X    if (newp == NULL)
X	return;
X
X    newp->ip = ag->ip;
X    newp->priority = ntohs(ag->priority);
X    newp->holdtime = ntohs(ag->holdtime);
X    newp->next = NULL;
X    for (p = pp = *nt; p != NULL; pp = p, p = p->next)
X	if (newp->priority > p->priority)
X	    break;
X    if (p == NULL) {
X	if (*nt == NULL)
X	    *nt = newp;
X	else
X	    pp->next = newp;
X    } else if (p == pp) {
X	newp->next = *nt;
X	*nt = newp;
X    } else {
X	pp->next = newp;
X	newp->next = p;
X    }
X}
X
X/*
X * delete_neighbor
X * Remove neighbor from the list
X */
X
Xdelete_neighbor (nt, dp)
X    struct neighbor **nt;
X    struct neighbor *dp;
X{
X    struct neighbor *p, *pp;
X
X    for (p = pp = *nt; p != NULL; pp = p, p = p->next)
X	if (p == dp)
X	    break;
X    if (p == pp)
X	*nt = p->next;
X    else
X	pp->next = p->next;
X    free(p);
X
X}
X
X/*
X * robin_neighbor
X * Perform round robin on received neighbors of equal priority
X */
X
Xrobin_neighbor ()
X{
X    struct neighbor *p, *pp;
X
X    /*
X     * Find where next lower priorty starts
X     */
X    for (p = pp = rcvd_neighbors; p != NULL; p = p->next)
X	if (default_neighbor->priority > p->priority)
X	    break;
X    /*
X     * If there is only a single entry, then don't bother
X     */
X    if (default_neighbor == pp)
X	return;
X
X    /*
X     * Splice old one at end of equal priority list
X     */
X    rcvd_neighbors = default_neighbor->next;
X    pp->next = default_neighbor;
X    default_neighbor->next = p;
X    update_routes();
X}
X
X/*
X * process_report
X * handle processing of GDP report messages
X */
X
Xprocess_report (from, gdp)
X    struct sockaddr_in *from;
X    struct gdppkt *gdp;
X{
X    struct neighbor *p;
X    struct addrgrp *a;
X
X    a = gdp->addrs;
X    while (gdp->count-- > 0) {
X	if (valid_address(a->ip)) {
X	    p = find_neighbor(&sent_neighbors, a->ip);
X	    if (p != NULL)
X		p->holdtime = ntohs(a->holdtime);
X	    p = find_neighbor(&rcvd_neighbors, a->ip);
X	    if (p == NULL || p->priority != ntohs(a->priority)) {
X		if (p != NULL) {
X		    if (flush)
X			flush_routes(p->ip);
X		    delete_neighbor(&rcvd_neighbors, p);
X		}
X		enter_neighbor(&rcvd_neighbors, a);
X		update_routes();
X		round = round_robin;		/* restart timer */
X	    } else
X		p->holdtime = ntohs(a->holdtime);
X	} else if (debug)
X	    syslog(LOG_DEBUG, "invalid IP address: %s",
X		inet_ntoa(a->ip));
X	a++;
X    }
X}
X
X/*
X * process_query
X * Process a QUERY and return a REPORT
X */
X
Xprocess_query (from, gdp)
X    struct sockaddr_in *from;
X    struct gdppkt *gdp;
X{
X}
X
X/*
X * timer
X * Wake up once in a while and process running timers, etc.
X */
X
Xtimer ()
X{
X    struct neighbor *p, *dp;
X    struct in_addr bip;
X
X    bip.s_addr = 0L;
X    if (report_time != 0) {
X	if (report <= 0) {
X	    send_report(bip);
X	    report = report_time;
X	} else
X	    report -= ALARM_INTERVAL;
X    } else {
X	if (query_time != 0) {
X	    query -= ALARM_INTERVAL;
X	    if (query <= 0) {
X		for (p = sent_neighbors; p != NULL; p = p->next)
X		    send_query(p->ip);
X		query = query_time;
X	    }
X	}
X	for (p = rcvd_neighbors; p != NULL; ) {
X	    dp = p;
X	    p = p->next;
X	    dp->holdtime -= ALARM_INTERVAL;
X	    if (dp->holdtime <= 0) {
X		if (flush)
X		    flush_routes(dp->ip);
X		delete_neighbor(&rcvd_neighbors, dp);
X		update_routes();
X		round = round_robin;		/* restart timer */
X	    }
X	}
X    }
X    if (round_robin != 0) {
X	round -= ALARM_INTERVAL;
X	if (round <= 0) {
X	    if (default_neighbor != NULL)
X		robin_neighbor();
X	    round = round_robin;
X	}
X    }
X    alarm(ALARM_INTERVAL);
X}
X
X/*
X * send_query
X * Send a GDP query message
X */
X
Xsend_query (ip)
X    struct in_addr ip;
X{
X    struct gdppkt gdp;
X    struct sockaddr_in sin;
X    struct iface *ifp;
X    struct neighbor *p;
X
X    bzero(&gdp, sizeof(gdp));
X    gdp.version = GDP_VERSION;
X    gdp.code = GDP_QUERY;
X    bzero(&sin, sizeof(sin));
X    sin.sin_family = AF_INET;
X    sin.sin_addr = ip;
X    if (sp == NULL)
X	sin.sin_port = htons(GDP_PORT);
X    else
X	sin.sin_port = htons(sp->s_port);
X    if (ip.s_addr == 0L) {
X	for (ifp = iflist; ifp != NULL; ifp = ifp->next) {
X	    if ((ifp->flags & IFF_BROADCAST) == 0)
X		continue;
X	    sin.sin_addr = ifp->ipbroadcast;
X	    (void) sendto(s, &gdp, sizeof(gdp) - sizeof(struct addrgrp), 0,
X		&sin, sizeof(sin));
X	}
X	for (p = sent_neighbors; p != NULL; p = p->next)
X	    send_query(p->ip);
X    } else
X	(void) sendto(s, &gdp, sizeof(gdp) - sizeof(struct addrgrp), 0,
X	    &sin, sizeof(sin));
X}
X
X/*
X * send_report
X * Send a GDP REPORT message
X */
X
Xsend_report (ip)
X    struct in_addr ip;
X{
X}
X
X/*
X * build_iflist
X * Build a list of interfaces and accompaning information
X */
X
Xbuild_iflist ()
X{
X    int n;
X    char ifbuf[BUFSIZ];
X    struct ifconf ifc;
X    struct ifreq *ifr, ifreq;
X    struct iface *ifp;
X    struct sockaddr_in *sa;
X    short flags;
X
X    ifc.ifc_len = sizeof(ifbuf);
X    ifc.ifc_buf = ifbuf;
X    if (ioctl(s, SIOCGIFCONF, &ifc) < 0) {
X	syslog(LOG_ERR, "ioctl(IFCONF): %m");
X	exit(1);
X    }
X    ifr = ifc.ifc_req;
X    for (n = ifc.ifc_len / sizeof(struct ifreq); n > 0; n--, ifr++) {
X	/*
X	 * Ignore the loopback interface
X	 */
X	if (strncmp(ifr->ifr_name, "lo", 2) == 0)
X	    continue;
X	/*
X	 * Ignore all interfaces which aren't running
X	 */
X	strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
X	if (ioctl(s, SIOCGIFFLAGS, &ifreq) < 0)
X	    continue;
X	else
X	    flags = ifreq.ifr_flags;
X	if ((flags & IFF_RUNNING) == 0)
X	    continue;
X	sa = (struct sockaddr_in *)&ifr->ifr_addr;
X	/*
X	 * Ignore non-internet family and 0.0.0.0
X	 */
X	if (sa->sin_family != AF_INET || sa->sin_addr.s_addr == 0L)
X	    continue;
X	ifp = (struct iface *)malloc(sizeof(struct iface));
X	if (ifp == NULL)
X	    break;
X	bzero(ifp, sizeof(struct iface));
X	strncpy(ifp->name, ifr->ifr_name, sizeof(ifp->name));
X	ifp->ipaddress = sa->sin_addr;
X	ifp->flags = flags;
X	strncpy(ifreq.ifr_name, ifp->name, sizeof(ifp->name));
X	if (ioctl(s, SIOCGIFNETMASK, &ifreq) >= 0) {
X	    sa = (struct sockaddr_in *)&ifreq.ifr_addr;
X	    ifp->ipmask = sa->sin_addr;
X	}
X	if (ifp->flags & IFF_BROADCAST) {
X	    strncpy(ifreq.ifr_name, ifp->name, sizeof(ifp->name));
X	    if (ioctl(s, SIOCGIFBRDADDR, &ifreq) >= 0) {
X		sa = (struct sockaddr_in *)&ifreq.ifr_addr;
X		ifp->ipbroadcast = sa->sin_addr;
X	    }
X	}
X	if (iflist == NULL)
X	    iflist = ifp;
X	else {
X	    ifp->next = iflist;
X	    iflist = ifp;
X	}
X    }
X}
X
X/*
X * valid_address
X * Determine if give IP address is something we grok.
X */
X
Xvalid_address (ip)
X    struct in_addr ip;
X{
X    struct iface *ifp;
X
X    for (ifp = iflist; ifp != NULL; ifp = ifp->next) {
X	if ((ip.s_addr & ifp->ipmask.s_addr) ==
X	    (ifp->ipaddress.s_addr & ifp->ipmask.s_addr))
X	    return(1);
X    }
X    return(0);
X}
X
X/*
X * update_routes
X * Update default route if necessary when something changes
X */
X
Xupdate_routes ()
X{
X    struct rtentry rt;
X    struct sockaddr_in *sa;
X    struct in_addr inet_makeaddr();
X
X    if (default_neighbor == rcvd_neighbors)
X	return;
X
X    bzero(&rt, sizeof(rt));
X    rt.rt_flags = RTF_UP;
X    if (metric > 0)
X	rt.rt_flags |= RTF_GATEWAY;
X    sa = (struct sockaddr_in *)&rt.rt_dst;
X    sa->sin_family = AF_INET;
X    sa->sin_addr = inet_makeaddr(0, INADDR_ANY);
X    sa = (struct sockaddr_in *)&rt.rt_gateway;
X    sa->sin_family = AF_INET;
X    if (default_neighbor != NULL) {
X	sa->sin_addr = default_neighbor->ip;
X	if (metric == 0)
X	    flush_arp();
X	if (logging)
X	    syslog(LOG_NOTICE, "deleting old default: %s",
X		inet_ntoa(sa->sin_addr));
X	if (!debug)
X	    (void) ioctl(s, SIOCDELRT, &rt);
X    }
X    default_neighbor = rcvd_neighbors;
X    if (default_neighbor == NULL)
X	return;
X    sa->sin_addr = default_neighbor->ip;
X    if (logging)
X	syslog(LOG_NOTICE, "adding new default: %s",
X	    inet_ntoa(sa->sin_addr));
X    if (!debug)
X	(void) ioctl(s, SIOCADDRT, &rt);
X}
X
X/*
X * flush_arp
X * Flush the ARP tables. Used when we delete a default route and metric
X * is zero.
X */
X
Xflush_arp ()
X{
X    int size, fd;
X    int arptab_size;
X    struct arptab *atp;
X    struct arptab *at;
X    struct arpreq ar;
X    struct sockaddr_in *sa;
X
X    if (logging)
X	syslog(LOG_NOTICE, "flushing ARP tables");
X    if (debug)
X	return;
X    fd = open(MEM, O_RDONLY);
X    if (fd < 0) {
X	syslog(LOG_ERR,"%s: cannot open", MEM);
X	exit(1);
X    }
X
X    if (lseek(fd, (long)nl[X_ARPTAB_SIZE].n_value, 0) == -1 ||
X	read(fd, &arptab_size, sizeof(arptab_size)) != sizeof(arptab_size) ||
X	arptab_size < 0 || arptab_size > 10000) {
X	syslog(LOG_ERR, "bad ARP namelist");
X	exit(1);
X    }
X    size = arptab_size * sizeof(struct arptab);
X    atp = (struct arptab *)malloc(size);
X    at = atp;
X    if (at == NULL) {
X	close(fd);
X	return;
X    }
X
X    if (lseek(fd, (long)nl[X_ARPTAB].n_value, 0) == -1 ||
X	read(fd, (char *)at, size) != size) {
X	syslog(LOG_ERR, "error reading ARP table %m");
X	exit(1);
X    }
X    bzero(&ar, sizeof(ar));
X    sa = (struct sockaddr_in *)&ar.arp_pa;
X    sa->sin_family = AF_INET;
X    for ( ; arptab_size-- > 0; at++) {
X#ifndef pyr
X	if (at->at_iaddr.s_addr == 0 || at->at_flags == 0)
X#else
X	struct sockaddr_in sin;
X
X	bcopy(&at->at_addr, &sin, sizeof(struct sockaddr_in));
X	if (sin.sin_addr.s_addr == 0 || at->at_flags == 0)
X#endif
X	    continue;
X	if (at->at_flags & ATF_PERM)
X	    continue;
X#ifndef pyr
X	sa->sin_addr = at->at_iaddr;
X#else
X	sa->sin_addr = sin.sin_addr;
X#endif
X	(void) ioctl(s, SIOCDARP, &ar);
X    }
X    close(fd);
X    free(atp);
X}
X
X/*
X * flush_routes
X * Flush the routing table. We do this when asked.
X */
X
Xflush_routes (ip)
X    struct in_addr ip;
X{
X    struct in_addr gwin, dstin;
X    struct mbuf mb;
X    register struct rtentry *rt;
X    register struct mbuf *mbp;
X    struct mbuf **routehash;
X    int rthashsize, i, doinghost = 1, fd;
X
X    fd = open(MEM, O_RDONLY);
X    if (fd < 0) {
X	syslog(LOG_ERR,"%s: cannot open", MEM);
X	exit(1);
X    }
X
X    if (lseek(fd, nl[N_RTHASHSIZE].n_value, 0) == -1 ||
X	read(fd, &rthashsize, sizeof (rthashsize)) != sizeof(rthashsize)) {
X	syslog(LOG_ERR, "bad ROUTE namelist");
X	exit(1);
X    }
X    if (logging)
X	syslog(LOG_NOTICE, "flushing routes via %s", inet_ntoa(ip));
X    routehash = (struct mbuf **)malloc(rthashsize*sizeof (struct mbuf *));
X    if (routehash == NULL) {
X	close(fd);
X	return;
X    }
X    if (lseek(fd, nl[N_RTHOST].n_value, 0) == -1 ||
X	read(fd, routehash, rthashsize*sizeof (struct mbuf *)) !=
X	rthashsize*sizeof(struct mbuf *)) {
X	syslog(LOG_ERR, "error reading ROUTE table %m");
X	exit(1);
X    }
Xagain:
X    for (i = 0; i < rthashsize; i++) {
X	if (routehash[i] == 0)
X	    continue;
X	mbp = routehash[i];
X	    while (mbp) {
X		if (lseek(fd, mbp, 0) == -1 ||
X		    read(fd, &mb, sizeof (mb)) != sizeof(mb))
X		    goto done;
X		rt = mtod(&mb, struct rtentry *);
X		if ((rt->rt_flags & RTF_GATEWAY) &&
X		    rt->rt_gateway.sa_family == AF_INET) {
X		    gwin = ((struct sockaddr_in *)&rt->rt_gateway)->sin_addr;
X		    dstin = ((struct sockaddr_in *)&rt->rt_dst)->sin_addr;
X		    /*
X		     * Flush all routes through this device except
X		     * default which is done later.
X		     */
X		    if (gwin.s_addr == ip.s_addr && dstin.s_addr != 0L) {
X			if (logging) {
X			    syslog(LOG_NOTICE, "flushing route %s",
X				inet_ntoa(dstin));
X			}
X			if (!debug)
X			    (void) ioctl(s, SIOCDELRT, (caddr_t)rt);
X		    }
X		}
X		mbp = mb.m_next;
X	    }
X    }
X    if (doinghost) {
X	if (lseek(fd, nl[N_RTNET].n_value, 0) == -1 ||
X	    read(fd, routehash, rthashsize*sizeof (struct mbuf *)) !=
X	    rthashsize*sizeof(struct mbuf *))
X	    goto done;
X	doinghost = 0;
X	goto again;
X    }
Xdone:
X    free(routehash);
X    close(fd);
X}
END_OF_FILE
if test 19941 -ne `wc -c <'gdpd.c'`; then
    echo shar: \"'gdpd.c'\" unpacked with wrong size!
fi
# end of 'gdpd.c'
fi
if test -f 'irdpd.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'irdpd.c'\"
else
echo shar: Extracting \"'irdpd.c'\" \(22779 characters\)
sed "s/^X//" >'irdpd.c' <<'END_OF_FILE'
X/*
X * Router Discovery Protocol daemon suitable for using on Un*x systems.
X *
X * September 1989, Greg Satz
X *
X * Copyright (c) 1989 by cisco Systems, Inc.
X * All rights reserved.
X */
X
X#include <sys/types.h>
X#include <sys/socket.h>
X#include <sys/ioctl.h>
X#include <sys/file.h>
X#include <sys/mbuf.h>
X#ifdef	sun
X#include <sys/limits.h>
X#else
X#define	INT_MAX 0x7ffffff	/* assume 32 bit ints */
X#endif
X
X#include <net/if.h>
X#include <net/route.h>
X#include <netinet/in.h>
X#ifndef pyr
X#include <netinet/if_ether.h>
X#else
X#include <net/if_ether.h>
X#endif
X
X#include <stdio.h>
X#include <signal.h>
X#include <errno.h>
X#include <netdb.h>
X#include <syslog.h>
X#include <nlist.h>
X
X/*
X * ICMP RDP packet format
X * use this rather than the definition in ip_icmp.h
X */
Xstruct irdppkt {
X    unsigned char  icmp_type;	/* type of message */
X    unsigned char  icmp_code;	/* type of sub code */
X    unsigned short icmp_cksum;	/* ones complement cksum of struct */
X    unsigned char  icmp_entries;/* number of entries in report */
X    unsigned char  icmp_size;   /* size of each entry */
X    unsigned short icmp_lifetime;/* lifetime of entries in this packet */
X    struct addrgrp {
X	struct in_addr	ip;
X	unsigned long	priority;
X    } addrs[1];
X};
X#ifndef	ICMP_RDPADVERT
X#define	ICMP_RDPADVERT	9	/* type for RDP advertisements */
X#define	ICMP_RDPSOLICIT	10	/* type for RDP solicitations */
X#endif
X
X#define	DEFAULT_IRDP_PRIORITY	100
X#define	DEFAULT_IRDP_HOLDTIME	600
X#define	DEFAULT_IRDP_MAXADVERTINT 600
X#define	DEFAULT_IRDP_MINADVERTINT (DEFAULT_IRDP_MAXADVERTINT * 3 / 4)
X
Xint hold_time = DEFAULT_IRDP_HOLDTIME;	/* tell others how often to hold */
Xint priority = DEFAULT_IRDP_PRIORITY;	/* what priority do we advertise */
Xint min_report_time = DEFAULT_IRDP_MINADVERTINT;/* how often to send reports */
Xint max_report_time = DEFAULT_IRDP_MAXADVERTINT;
X
X#define	ALARM_INTERVAL		1
X
X#define	KERNEL		"/vmunix"
X#define	MEM		"/dev/kmem"
X
Xstruct nlist nl[] = {
X#define	X_ARPTAB	0
X	{ "_arptab" },
X#define	X_ARPTAB_SIZE	1
X	{ "_arptab_size" },
X#define	N_RTHOST	2
X	{ "_rthost" },
X#define	N_RTNET		3
X	{ "_rtnet" },
X#define	N_RTHASHSIZE	4
X	{ "_rthashsize" },
X	{ "" },
X};
X
Xstruct iface {
X    char name[IFNAMSIZ];
X    short flags;
X    struct in_addr ipaddress;
X    struct in_addr ipmask;
X    struct in_addr ipbroadcast;
X    struct iface *next;
X} *iflist;
X
Xstruct neighbor {
X    struct in_addr ip;
X    unsigned short priority;
X    unsigned short holdtime;
X    struct neighbor *next;
X};
X
Xstruct neighbor *rcvd_neighbors;
Xstruct neighbor *sent_neighbors;
X
Xstruct neighbor *default_neighbor;
X
X
Xint debug;				/* debugging flag */
Xint flush;				/* flush routing table flag */
Xint logging;				/* syslog logging flag */
Xint metric;				/* how do we run */
Xint query_time;				/* how often to send queries */
Xint query;
Xint report;
Xint round_robin;			/* how often to cycle parallel gws */
Xint round;
X
Xint s;
Xstruct sockaddr_in from;
Xint fromlen;
Xstruct hostent *hp;
Xunsigned char buf[BUFSIZ];
X
Xint timer();
X
X/*
X * main
X * Perform IRDP processing depending on what we were told
X */
X
Xmain (argc, argv)
X    int argc;
X    char *argv;
X{
X    int c, on = 1;
X    struct irdppkt *irdp;
X    struct addrgrp ag;
X    struct in_addr bip;
X    struct protoent *proto;
X    int oldmask;
X    extern char *optarg;
X    extern int optind;
X    extern int errno;
X
X    debug = 0;
X    flush = 0;
X    logging = 0;
X    metric = 1;				/* default to one hop */
X    priority = DEFAULT_IRDP_PRIORITY;
X    hold_time = DEFAULT_IRDP_HOLDTIME;
X    query_time = 0;
X    min_report_time = 0;
X    max_report_time = 0;
X    round_robin = 0;
X    iflist = NULL;
X    rcvd_neighbors = NULL;
X    sent_neighbors = NULL;
X    default_neighbor = NULL;
X    bip.s_addr = 0L;
X#ifdef LOG_DAEMON
X    openlog("irdpd", LOG_PID, LOG_DAEMON);
X#else
X    openlog("irdpd", LOG_PID);
X#endif
X    while ((c = getopt(argc, argv, "dfh:lm:p:q:r:t:")) != EOF)
X	switch (c) {
X	case 'd':			/* debug */
X	    debug = 1;
X	    break;
X	case 'f':			/* flush  */
X	    flush = 1;
X	    break;
X	case 'h':			/* hold time */
X	    hold_time = atoi(optarg);
X	    if (hold_time < 0) {
X		fprintf(stderr, "%s: illegal hold time value - %d",
X		    argv[0], hold_time);
X		exit(1);
X	    }
X	    break;
X	case 'l':			/* logging */
X	    logging = 1;
X	    break;
X	case 'm':			/* metric */
X	    metric = atoi(optarg);
X	    if (metric < 0) {
X		fprintf(stderr, "%s: illegal metric value - %d",
X		    argv[0], metric);
X		exit(1);
X	    }
X	    break;
X	case 'p':			/* priority */
X	    priority = atoi(optarg);
X	    if (priority < 0) {
X		fprintf(stderr, "%s: illegal priority value - %d",
X		    argv[0], priority);
X		exit(1);
X	    }
X	    break;
X	case 'q':			/* query */
X	    query_time = atoi(optarg);
X	    if (query_time < 0) {
X		fprintf(stderr, "%s: illegal querying value - %d",
X		    argv[0], query_time);
X		exit(1);
X	    }
X	    break;
X	case 'r':			/* min report */
X	    min_report_time = atoi(optarg);
X	    if (min_report_time < 0) {
X		fprintf(stderr, "%s: illegal reporting value - %d",
X		    argv[0], min_report_time);
X		exit(1);
X	    }
X	    break;
X	case 'R':			/* max report */
X	    max_report_time = atoi(optarg);
X	    if (max_report_time < 0) {
X		fprintf(stderr, "%s: illegal reporting value - %d",
X		    argv[0], max_report_time);
X		exit(1);
X	    }
X	    break;
X	case 't':			/* time */
X	    round_robin = atoi(optarg);
X	    if (round_robin < 0) {
X		fprintf(stderr, "%s: illegal round robin value - %d",
X		    argv[0], round_robin);
X		exit(1);
X	    }
X	    round_robin *= 60;		/* make seconds */
X	    break;
X	default:
X	    fprintf(stderr, "%s: illegal switch -%s", argv[0], optarg);
X	    exit(1);
X	}
X
X    if (query_time != 0 && max_report_time != 0) {
X	fprintf(stderr, "%s: cannot report and query simultaneously.\n",
X	    argv[0]);
X	exit(1);
X    }
X
X    bzero(&ag, sizeof(struct addrgrp));
X    while (argc != optind) {
X	ag.ip.s_addr = inet_addr(argv[optind]);
X	if (ag.ip.s_addr == -1) {
X	    hp = gethostbyname(argv[optind]);
X	    if (hp == NULL) {
X		fprintf(stderr, "%s: %s: unknown host\n", argv[0],
X		    argv[optind]);
X		exit(1);
X	    }
X	    bcopy(hp->h_addr, &ag.ip, sizeof(ag.ip));
X	}
X	enter_neighbor(&sent_neighbors, ag.ip, 0, 0);
X	optind++;
X    }
X
X    /* seed random number generator */
X    srandom((int) (time(0L) & INT_MAX));
X
X    if (query_time)
X      query = random() % query_time;
X
X    if (max_report_time)
X      report = min_report_time +
X	       (random() % (max_report_time - min_report_time));
X
X    round = round_robin;
X
X    if (metric == 0 || flush) {
X	nlist(KERNEL, nl);
X	if (nl[X_ARPTAB].n_value == 0) {
X	    fprintf(stderr, "%s: %s: bad namelist\n", argv[0], KERNEL);
X	    exit(1);
X	}
X	if (nl[X_ARPTAB_SIZE].n_value == 0) {
X	    fprintf(stderr, "%s: %s: bad namelist\n", argv[0], KERNEL);
X	    exit(1);
X	}
X	if (nl[N_RTHOST].n_value == 0) {
X	    fprintf(stderr, "%s: %s: bad namelist\n", argv[0], KERNEL);
X	    exit(1);
X	}
X	if (nl[N_RTNET].n_value == 0) {
X	    fprintf(stderr, "%s: %s: bad namelist\n", argv[0], KERNEL);
X	    exit(1);
X	}
X	if (nl[N_RTHASHSIZE].n_value == 0) {
X	    fprintf(stderr, "%s: %s: bad namelist\n", argv[0], KERNEL);
X	    exit(1);
X	}
X    }
X    if (debug)
X	syslog(LOG_DEBUG, "server starting");
X
X    if (!debug) {
X	if (fork())
X	    exit(0);
X	for (c = 0; c < getdtablesize(); c++)
X	    (void) close(c);
X	(void) open("/", O_RDONLY);
X	(void) dup2(0, 1);
X	(void) dup2(0, 2);
X	c = open("/dev/tty", O_RDWR);
X	if (c >= 0) {
X	    ioctl(c, TIOCNOTTY, (char *)0);
X	    (void) close(c);
X	}
X#ifdef LOG_DAEMON
X	openlog("irdpd", LOG_PID, LOG_DAEMON);
X#else
X	openlog("irdpd", LOG_PID);
X#endif
X    }
X
X    /*
X     * Get listener socket
X     */
X    if ((proto = getprotobyname("icmp")) == NULL) {
X	syslog(LOG_ERR, "getprotobyname: %m");
X	exit(1);
X    }
X    if ((s = socket(AF_INET, SOCK_RAW, proto->p_proto)) < 0) {
X	syslog(LOG_ERR, "socket: irdp %m");
X	exit(1);
X    }
X
X#ifdef SO_BROADCAST
X    if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0) {
X	syslog(LOG_ERR, "setsockopt: %m");
X	exit(1);
X    }
X#endif
X
X    build_iflist();
X    irdp_solicit(bip);
X    signal(SIGALRM, timer);
X    timer();
X
X    /*
X     * Now do the work
X     */
X
X    for (;;) {
X	fromlen = sizeof(from);
X	c = recvfrom(s, buf, sizeof(buf), 0, (caddr_t)&from, &fromlen);
X	if (c <= 0) {
X	    if (errno == EINTR)
X		continue;
X	    syslog(LOG_ERR, "recvfrom: %m");
X	    exit(1);
X	}
X	irdp = (struct irdppkt *)buf;
X
X	if (irdp->icmp_type != ICMP_RDPADVERT &&
X	    irdp->icmp_type != ICMP_RDPSOLICIT)
X
X	if (debug) {
X	    hp = gethostbyaddr(&from.sin_addr, sizeof(struct in_addr),
X		AF_INET);
X	    syslog(LOG_DEBUG, "%s received from %s",
X		   irdp->icmp_type == ICMP_RDPADVERT ? "ADVERT" : "SOLICIT",
X		   hp ? hp->h_name : (char *)inet_ntoa(from.sin_addr));
X	}
X
X	oldmask = sigblock(sigmask(SIGALRM));
X	if (irdp->icmp_type == ICMP_RDPADVERT) {
X	    if (max_report_time == 0)	/* if we're end node */
X	      irdp_procadvert(&from, buf);
X	} else {
X	    if (max_report_time != 0)	/* if we're router */
X	      irdp_procsolicit(&from, buf);
X	}
X    	sigsetmask(oldmask);
X    }
X}
X
X/*
X * find_neighbor
X * Look for a given neighbor in the list and return ptr or NULL
X */
X
Xstruct neighbor *find_neighbor (nt, ip)
X    struct neighbor **nt;
X    struct in_addr ip;
X{
X    struct neighbor *p;
X
X    for (p = *nt; p != NULL; p = p->next)
X	if (p->ip.s_addr == ip.s_addr)
X	    break;
X    return(p);
X}
X
X/*
X * enter_neighbor
X * Enter a new neighbor into the table in priority order
X */
X
Xenter_neighbor (nt, ip, priority, holdtime)
X    struct neighbor **nt;
X    struct in_addr ip;
X    int priority, holdtime;
X{
X    struct neighbor *p, *pp, *newp;
X
X    newp = (struct neighbor *)malloc(sizeof(struct neighbor));
X    if (newp == NULL)
X	return;
X
X    newp->ip = ip;
X    newp->priority = priority;
X    newp->holdtime = holdtime;
X    newp->next = NULL;
X    for (p = pp = *nt; p != NULL; pp = p, p = p->next)
X	if (newp->priority > p->priority)
X	    break;
X    if (p == NULL) {
X	if (*nt == NULL)
X	    *nt = newp;
X	else
X	    pp->next = newp;
X    } else if (p == pp) {
X	newp->next = *nt;
X	*nt = newp;
X    } else {
X	pp->next = newp;
X	newp->next = p;
X    }
X}
X
X/*
X * delete_neighbor
X * Remove neighbor from the list
X */
X
Xdelete_neighbor (nt, dp)
X    struct neighbor **nt;
X    struct neighbor *dp;
X{
X    struct neighbor *p, *pp;
X
X    for (p = pp = *nt; p != NULL; pp = p, p = p->next)
X	if (p == dp)
X	    break;
X    if (p == pp)
X	*nt = p->next;
X    else
X	pp->next = p->next;
X    free(p);
X
X}
X
X/*
X * robin_neighbor
X * Perform round robin on received neighbors of equal priority
X */
X
Xrobin_neighbor ()
X{
X    struct neighbor *p, *pp;
X
X    /*
X     * Find where next lower priorty starts
X     */
X    for (p = pp = rcvd_neighbors; p != NULL; p = p->next)
X	if (default_neighbor->priority > p->priority)
X	    break;
X    /*
X     * If there is only a single entry, then don't bother
X     */
X    if (default_neighbor == pp)
X	return;
X
X    /*
X     * Splice old one at end of equal priority list
X     */
X    rcvd_neighbors = default_neighbor->next;
X    pp->next = default_neighbor;
X    default_neighbor->next = p;
X    update_routes();
X}
X
X/*
X * irdp_procadvert
X * handle processing of IRDP advertisements
X */
X
Xirdp_procadvert (from, irdp)
X    struct sockaddr_in *from;
X    struct irdppkt *irdp;
X{
X    struct neighbor *p;
X    struct addrgrp *a;
X
X    a = irdp->addrs;
X    while (irdp->icmp_entries-- > 0) {
X	if (valid_address(a->ip)) {
X	    p = find_neighbor(&sent_neighbors, a->ip);
X	    if (p != NULL)
X		p->holdtime = ntohs(irdp->icmp_lifetime);
X	    p = find_neighbor(&rcvd_neighbors, a->ip);
X	    if (p == NULL || p->priority != ntohs(a->priority)) {
X		if (p != NULL) {
X		    if (flush)
X			flush_routes(p->ip);
X		    delete_neighbor(&rcvd_neighbors, p);
X		}
X		enter_neighbor(&rcvd_neighbors, a->ip,
X			       ntohs(a->priority), ntohs(irdp->icmp_lifetime));
X		update_routes();
X		round = round_robin;		/* restart timer */
X	    } else
X		p->holdtime = ntohs(irdp->icmp_lifetime);
X	} else if (debug)
X	    syslog(LOG_DEBUG, "invalid IP address: %s",
X		inet_ntoa(a->ip));
X	a++;
X    }
X}
X
X/*
X * irdp_procsolicit
X * Process a solicitation send out irdp packets on all ports
X */
X
Xirdp_procsolicit (from, irdp)
X    struct sockaddr_in *from;
X    struct irdppkt *irdp;
X{
X}
X
X/*
X * timer
X * Wake up once in a while and process running timers, etc.
X */
X
Xtimer ()
X{
X    struct neighbor *p, *dp;
X    struct in_addr bip;
X
X    bip.s_addr = 0L;
X    if (max_report_time != 0) {
X	if (report <= 0) {
X	    irdp_advert(bip);
X	    report = min_report_time +
X	      (random() % (max_report_time - min_report_time));
X	} else
X	    report -= ALARM_INTERVAL;
X    } else {
X	if (query_time != 0) {
X	    query -= ALARM_INTERVAL;
X	    if (query <= 0) {
X		for (p = sent_neighbors; p != NULL; p = p->next)
X		    irdp_solicit(p->ip);
X		query = query_time;
X	    }
X	}
X	for (p = rcvd_neighbors; p != NULL; ) {
X	    dp = p;
X	    p = p->next;
X	    dp->holdtime -= ALARM_INTERVAL;
X	    if (dp->holdtime <= 0) {
X		if (flush)
X		    flush_routes(dp->ip);
X		delete_neighbor(&rcvd_neighbors, dp);
X		update_routes();
X		round = round_robin;		/* restart timer */
X	    }
X	}
X    }
X    if (round_robin != 0) {
X	round -= ALARM_INTERVAL;
X	if (round <= 0) {
X	    if (default_neighbor != NULL)
X		robin_neighbor();
X	    round = round_robin;
X	}
X    }
X    alarm(ALARM_INTERVAL);
X}
X
X/*
X * irdp_solicit
X * Send a IRDP solictation - if IP = 0, send to all broadcast interfaces
X */
X
Xirdp_solicit (ip)
X    struct in_addr ip;
X{
X    struct irdppkt irdp;
X    struct sockaddr_in sin;
X    struct iface *ifp;
X    struct neighbor *p;
X
X    bzero(&irdp, sizeof(irdp));
X    irdp.icmp_type = ICMP_RDPSOLICIT;
X    irdp.icmp_cksum = in_cksum(irdp, sizeof(irdp)-sizeof(struct addrgrp));
X
X    bzero(&sin, sizeof(sin));
X    sin.sin_family = AF_INET;
X    sin.sin_addr = ip;
X    if (ip.s_addr == 0L) {
X	for (ifp = iflist; ifp != NULL; ifp = ifp->next) {
X	    if ((ifp->flags & IFF_BROADCAST) == 0)
X		continue;
X	    sin.sin_addr = ifp->ipbroadcast;
X	    (void) sendto(s, &irdp, sizeof(irdp) - sizeof(struct addrgrp), 0,
X		&sin, sizeof(sin));
X	}
X	for (p = sent_neighbors; p != NULL; p = p->next)
X	    irdp_solicit(p->ip);
X    } else
X	(void) sendto(s, &irdp, sizeof(irdp) - sizeof(struct addrgrp), 0,
X	    &sin, sizeof(sin));
X}
X
X/*
X * irdp_advert
X * Send a IRDP REPORT message
X */
X
Xirdp_advert (ip)
X    struct in_addr ip;
X{
X}
X
X/*
X * build_iflist
X * Build a list of interfaces and accompaning information
X */
X
Xbuild_iflist ()
X{
X    int n;
X    char ifbuf[BUFSIZ];
X    struct ifconf ifc;
X    struct ifreq *ifr, ifreq;
X    struct iface *ifp;
X    struct sockaddr_in *sa;
X    short flags;
X
X    ifc.ifc_len = sizeof(ifbuf);
X    ifc.ifc_buf = ifbuf;
X    if (ioctl(s, SIOCGIFCONF, &ifc) < 0) {
X	syslog(LOG_ERR, "ioctl(IFCONF): %m");
X	exit(1);
X    }
X    ifr = ifc.ifc_req;
X    for (n = ifc.ifc_len / sizeof(struct ifreq); n > 0; n--, ifr++) {
X	/*
X	 * Ignore the loopback interface
X	 */
X	if (strncmp(ifr->ifr_name, "lo", 2) == 0)
X	    continue;
X	/*
X	 * Ignore all interfaces which aren't running
X	 */
X	strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
X	if (ioctl(s, SIOCGIFFLAGS, &ifreq) < 0)
X	    continue;
X	else
X	    flags = ifreq.ifr_flags;
X	if ((flags & IFF_RUNNING) == 0)
X	    continue;
X	sa = (struct sockaddr_in *)&ifr->ifr_addr;
X	/*
X	 * Ignore non-internet family and 0.0.0.0
X	 */
X	if (sa->sin_family != AF_INET || sa->sin_addr.s_addr == 0L)
X	    continue;
X	ifp = (struct iface *)malloc(sizeof(struct iface));
X	if (ifp == NULL)
X	    break;
X	bzero(ifp, sizeof(struct iface));
X	strncpy(ifp->name, ifr->ifr_name, sizeof(ifp->name));
X	ifp->ipaddress = sa->sin_addr;
X	ifp->flags = flags;
X	strncpy(ifreq.ifr_name, ifp->name, sizeof(ifp->name));
X	if (ioctl(s, SIOCGIFNETMASK, &ifreq) >= 0) {
X	    sa = (struct sockaddr_in *)&ifreq.ifr_addr;
X	    ifp->ipmask = sa->sin_addr;
X	}
X	if (ifp->flags & IFF_BROADCAST) {
X	    strncpy(ifreq.ifr_name, ifp->name, sizeof(ifp->name));
X	    if (ioctl(s, SIOCGIFBRDADDR, &ifreq) >= 0) {
X		sa = (struct sockaddr_in *)&ifreq.ifr_addr;
X		ifp->ipbroadcast = sa->sin_addr;
X	    }
X	}
X	if (iflist == NULL)
X	    iflist = ifp;
X	else {
X	    ifp->next = iflist;
X	    iflist = ifp;
X	}
X    }
X}
X
X/*
X * valid_address
X * Determine if give IP address is something we grok.
X */
X
Xvalid_address (ip)
X    struct in_addr ip;
X{
X    struct iface *ifp;
X
X    for (ifp = iflist; ifp != NULL; ifp = ifp->next) {
X	if ((ip.s_addr & ifp->ipmask.s_addr) ==
X	    (ifp->ipaddress.s_addr & ifp->ipmask.s_addr))
X	    return(1);
X    }
X    return(0);
X}
X
X/*
X * update_routes
X * Update default route if necessary when something changes
X */
X
Xupdate_routes ()
X{
X    struct rtentry rt;
X    struct sockaddr_in *sa;
X    struct in_addr inet_makeaddr();
X
X    if (default_neighbor == rcvd_neighbors)
X	return;
X
X    bzero(&rt, sizeof(rt));
X    rt.rt_flags = RTF_UP;
X    if (metric > 0)
X	rt.rt_flags |= RTF_GATEWAY;
X    sa = (struct sockaddr_in *)&rt.rt_dst;
X    sa->sin_family = AF_INET;
X    sa->sin_addr = inet_makeaddr(0, INADDR_ANY);
X    sa = (struct sockaddr_in *)&rt.rt_gateway;
X    sa->sin_family = AF_INET;
X    if (default_neighbor != NULL) {
X	sa->sin_addr = default_neighbor->ip;
X	if (metric == 0)
X	    flush_arp();
X	if (logging)
X	    syslog(LOG_NOTICE, "deleting old default: %s",
X		inet_ntoa(sa->sin_addr));
X	if (!debug)
X	    (void) ioctl(s, SIOCDELRT, &rt);
X    }
X    default_neighbor = rcvd_neighbors;
X    if (default_neighbor == NULL)
X	return;
X    sa->sin_addr = default_neighbor->ip;
X    if (logging)
X	syslog(LOG_NOTICE, "adding new default: %s",
X	    inet_ntoa(sa->sin_addr));
X    if (!debug)
X	(void) ioctl(s, SIOCADDRT, &rt);
X}
X
X/*
X * flush_arp
X * Flush the ARP tables. Used when we delete a default route and metric
X * is zero.
X */
X
Xflush_arp ()
X{
X    int size, fd;
X    int arptab_size;
X    struct arptab *atp;
X    struct arptab *at;
X    struct arpreq ar;
X    struct sockaddr_in *sa;
X
X    if (logging)
X	syslog(LOG_NOTICE, "flushing ARP tables");
X    if (debug)
X	return;
X    fd = open(MEM, O_RDONLY);
X    if (fd < 0) {
X	syslog(LOG_ERR,"%s: cannot open", MEM);
X	exit(1);
X    }
X
X    if (lseek(fd, (long)nl[X_ARPTAB_SIZE].n_value, 0) == -1 ||
X	read(fd, &arptab_size, sizeof(arptab_size)) != sizeof(arptab_size) ||
X	arptab_size < 0 || arptab_size > 10000) {
X	syslog(LOG_ERR, "bad ARP namelist");
X	exit(1);
X    }
X    size = arptab_size * sizeof(struct arptab);
X    atp = (struct arptab *)malloc(size);
X    at = atp;
X    if (at == NULL) {
X	close(fd);
X	return;
X    }
X
X    if (lseek(fd, (long)nl[X_ARPTAB].n_value, 0) == -1 ||
X	read(fd, (char *)at, size) != size) {
X	syslog(LOG_ERR, "error reading ARP table %m");
X	exit(1);
X    }
X    bzero(&ar, sizeof(ar));
X    sa = (struct sockaddr_in *)&ar.arp_pa;
X    sa->sin_family = AF_INET;
X    for ( ; arptab_size-- > 0; at++) {
X#ifndef pyr
X	if (at->at_iaddr.s_addr == 0 || at->at_flags == 0)
X#else
X	struct sockaddr_in sin;
X
X	bcopy(&at->at_addr, &sin, sizeof(struct sockaddr_in));
X	if (sin.sin_addr.s_addr == 0 || at->at_flags == 0)
X#endif
X	    continue;
X	if (at->at_flags & ATF_PERM)
X	    continue;
X#ifndef pyr
X	sa->sin_addr = at->at_iaddr;
X#else
X	sa->sin_addr = sin.sin_addr;
X#endif
X	(void) ioctl(s, SIOCDARP, &ar);
X    }
X    close(fd);
X    free(atp);
X}
X
X/*
X * flush_routes
X * Flush the routing table. We do this when asked.
X */
X
Xflush_routes (ip)
X    struct in_addr ip;
X{
X    struct in_addr gwin, dstin;
X    struct mbuf mb;
X    register struct rtentry *rt;
X    register struct mbuf *mbp;
X    struct mbuf **routehash;
X    int rthashsize, i, doinghost = 1, fd;
X
X    fd = open(MEM, O_RDONLY);
X    if (fd < 0) {
X	syslog(LOG_ERR,"%s: cannot open", MEM);
X	exit(1);
X    }
X
X    if (lseek(fd, nl[N_RTHASHSIZE].n_value, 0) == -1 ||
X	read(fd, &rthashsize, sizeof (rthashsize)) != sizeof(rthashsize)) {
X	syslog(LOG_ERR, "bad ROUTE namelist");
X	exit(1);
X    }
X    if (logging)
X	syslog(LOG_NOTICE, "flushing routes via %s", inet_ntoa(ip));
X    routehash = (struct mbuf **)malloc(rthashsize*sizeof (struct mbuf *));
X    if (routehash == NULL) {
X	close(fd);
X	return;
X    }
X    if (lseek(fd, nl[N_RTHOST].n_value, 0) == -1 ||
X	read(fd, routehash, rthashsize*sizeof (struct mbuf *)) !=
X	rthashsize*sizeof(struct mbuf *)) {
X	syslog(LOG_ERR, "error reading ROUTE table %m");
X	exit(1);
X    }
Xagain:
X    for (i = 0; i < rthashsize; i++) {
X	if (routehash[i] == 0)
X	    continue;
X	mbp = routehash[i];
X	    while (mbp) {
X		if (lseek(fd, mbp, 0) == -1 ||
X		    read(fd, &mb, sizeof (mb)) != sizeof(mb))
X		    goto done;
X		rt = mtod(&mb, struct rtentry *);
X		if ((rt->rt_flags & RTF_GATEWAY) &&
X		    rt->rt_gateway.sa_family == AF_INET) {
X		    gwin = ((struct sockaddr_in *)&rt->rt_gateway)->sin_addr;
X		    dstin = ((struct sockaddr_in *)&rt->rt_dst)->sin_addr;
X		    /*
X		     * Flush all routes through this device except
X		     * default which is done later.
X		     */
X		    if (gwin.s_addr == ip.s_addr && dstin.s_addr != 0L) {
X			if (logging) {
X			    syslog(LOG_NOTICE, "flushing route %s",
X				inet_ntoa(dstin));
X			}
X			if (!debug)
X			    (void) ioctl(s, SIOCDELRT, (caddr_t)rt);
X		    }
X		}
X		mbp = mb.m_next;
X	    }
X    }
X    if (doinghost) {
X	if (lseek(fd, nl[N_RTNET].n_value, 0) == -1 ||
X	    read(fd, routehash, rthashsize*sizeof (struct mbuf *)) !=
X	    rthashsize*sizeof(struct mbuf *))
X	    goto done;
X	doinghost = 0;
X	goto again;
X    }
Xdone:
X    free(routehash);
X    close(fd);
X}
X
X/*
X * Copyright (c) 1987 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that the above copyright notice and this paragraph are
X * duplicated in all such forms and that any documentation,
X * advertising materials, and other materials related to such
X * distribution and use acknowledge that the software was developed
X * by the University of California, Berkeley.  The name of the
X * University may not be used to endorse or promote products derived
X * from this software without specific prior written permission.
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X */
X/*
X *			I N _ C K S U M
X *
X * Checksum routine for Internet Protocol family headers (C Version)
X *
X */
Xint
Xin_cksum(addr, len)
Xunsigned short *addr;
Xint len;
X{
X	register int nleft = len;
X	register u_short *w = addr;
X	register u_short answer;
X	register int sum = 0;
X	u_short odd_byte = 0;
X
X	/*
X	 *  Our algorithm is simple, using a 32 bit accumulator (sum),
X	 *  we add sequential 16 bit words to it, and at the end, fold
X	 *  back all the carry bits from the top 16 bits into the lower
X	 *  16 bits.
X	 */
X	while( nleft > 1 )  {
X		sum += *w++;
X		nleft -= 2;
X	}
X
X	/* mop up an odd byte, if necessary */
X	if( nleft == 1 ) {
X		*(u_char *)(&odd_byte) = *(u_char *)w;
X		sum += odd_byte;
X	}
X
X	/*
X	 * add back carry outs from top 16 bits to low 16 bits
X	 */
X	sum = (sum >> 16) + (sum & 0xffff);	/* add hi 16 to low 16 */
X	sum += (sum >> 16);			/* add carry */
X	answer = ~sum;				/* truncate to 16 bits */
X	return (answer);
X}
END_OF_FILE
if test 22779 -ne `wc -c <'irdpd.c'`; then
    echo shar: \"'irdpd.c'\" unpacked with wrong size!
fi
# end of 'irdpd.c'
fi
echo shar: End of shell archive.
exit 0
