+++ /dev/null
-/*
- * $OpenBSD: rdisc.c,v 1.1 1996/08/02 23:39:08 tholo Exp $
- *
- * Rdisc (this program) was developed by Sun Microsystems, Inc. and is
- * provided for unrestricted use provided that this legend is included on
- * all tape media and as a part of the software program in whole or part.
- * Users may copy or modify Rdisc without charge, and they may freely
- * distribute it.
- *
- * RDISC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
- * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
- *
- * Rdisc is provided with no support and without any obligation on the
- * part of Sun Microsystems, Inc. to assist in its use, correction,
- * modification or enhancement.
- *
- * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
- * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY RDISC
- * OR ANY PART THEREOF.
- *
- * In no event will Sun Microsystems, Inc. be liable for any lost revenue
- * or profits or other special, indirect and consequential damages, even if
- * Sun has been advised of the possibility of such damages.
- *
- * Sun Microsystems, Inc.
- * 2550 Garcia Avenue
- * Mountain View, California 94043
- */
-#include <stdio.h>
-#include <errno.h>
-#include <signal.h>
-#include <sys/types.h>
-#include <sys/time.h>
-
-#include <sys/param.h>
-#include <sys/socket.h>
-#include <sys/file.h>
-
-#include <sys/ioctl.h>
-#include <net/if.h>
-
-#include <netinet/in_systm.h>
-#include <netinet/in.h>
-#include <netinet/ip.h>
-#include <netinet/ip_icmp.h>
-
-#include <netdb.h>
-#include <arpa/inet.h>
-
-#include <string.h>
-#include <syslog.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <err.h>
-#include <sys/cdefs.h>
-
-#if __STDC__
-#include <stdarg.h>
-#else
-#include <varargs.h>
-#endif
-
-/*
- * TBD
- * Use 255.255.255.255 for broadcasts - not the interface broadcast
- * address.
- */
-
-#ifdef lint
-#define ALLIGN(ptr) (ptr ? 0 : 0)
-#else
-#define ALLIGN(ptr) (ptr)
-#endif
-
-
-#define ICMP_ROUTER_ADVERTISEMENT 9
-#define ICMP_ROUTER_SOLICITATION 10
-
-#define ALL_HOSTS_ADDRESS "224.0.0.1"
-#define ALL_ROUTERS_ADDRESS "224.0.0.2"
-
-#define MAXIFS 32
-
-/* Router constants */
-#define MAX_INITIAL_ADVERT_INTERVAL 16
-#define MAX_INITIAL_ADVERTISEMENTS 3
-#define MAX_RESPONSE_DELAY 2 /* Not used */
-
-/* Host constants */
-#define MAX_SOLICITATIONS 3
-#define SOLICITATION_INTERVAL 3
-#define MAX_SOLICITATION_DELAY 1 /* Not used */
-
-#define IGNORE_PREFERENCE 0x80000000 /* Maximum negative */
-
-#define MAX_ADV_INT 600
-
-/* Statics */
-int num_interfaces;
-struct interface {
- struct in_addr address; /* Used to identify the interface */
- struct in_addr localaddr; /* Actual address if the interface */
- int preference;
- int flags;
- struct in_addr bcastaddr;
- struct in_addr remoteaddr;
- struct in_addr netmask;
-};
-struct interface *interfaces;
-int interfaces_size; /* Number of elements in interfaces */
-
-
-#define MAXPACKET 4096 /* max packet size */
-u_char packet[MAXPACKET];
-
-char usage[] =
-"Usage: rdisc [-s] [-v] [-f] [-a] [send_address] [receive_address]\n\
- rdisc -r [-v] [-p <preference>] [-T <secs>] \n\
- [send_address] [receive_address]\n";
-
-
-int s; /* Socket file descriptor */
-struct sockaddr_in whereto;/* Address to send to */
-
-/* Common variables */
-int verbose = 0;
-int debug = 0;
-int trace = 0;
-int solicit = 0;
-int responder;
-int ntransmitted = 0;
-int nreceived = 0;
-int forever = 0; /* Never give up on host. If 0 defer fork until
- * first response.
- */
-
-/* Router variables */
-int max_adv_int = MAX_ADV_INT;
-int min_adv_int;
-int lifetime;
-int initial_advert_interval = MAX_INITIAL_ADVERT_INTERVAL;
-int initial_advertisements = MAX_INITIAL_ADVERTISEMENTS;
-int preference = 0; /* Setable with -p option */
-
-/* Host variables */
-int max_solicitations = MAX_SOLICITATIONS;
-unsigned int solicitation_interval = SOLICITATION_INTERVAL;
-int best_preference = 1; /* Set to record only the router(s) with the
- best preference in the kernel. Not set
- puts all routes in the kernel. */
-
-/* Prototypes */
-void do_fork __P((void));
-int main __P((int, char **));
-void timer __P((int));
-void solicitor __P((struct sockaddr_in *));
-void advertise __P((struct sockaddr_in *));
-char * pr_type __P((int));
-char * pr_name __P((struct in_addr));
-void pr_pack __P((char *, int, struct sockaddr_in *));
-int in_cksum __P((u_short *, int));
-void finish __P((int));
-int isbroadcast __P((struct sockaddr_in *));
-int ismulticast __P((struct sockaddr_in *));
-int sendbcast __P((int, char *, int));
-int sendbcastif __P((int, char *, int, struct interface *));
-int sendmcast __P((int, char *, int, struct sockaddr_in *));
-int sendmcastif __P((int, char *, int, struct sockaddr_in *, struct interface *));
-void init __P((void));
-void initifs __P((int));
-int support_multicast __P((void));
-int is_directly_connected __P((struct in_addr));
-struct table * find_router __P((struct in_addr));
-int max_preference __P((void));
-void age_table __P((int));
-void record_router __P((struct in_addr, long, int));
-void add_route __P((struct in_addr));
-void del_route __P((struct in_addr));
-void rtioctl __P((struct in_addr, int));
-void initlog __P((void));
-void logerr __P((char *fmt, ...));
-void logtrace __P((char *fmt, ...));
-void logdebug __P((char *fmt, ...));
-void logperror __P((char *str));
-void prusage __P((void));
-int join __P((int sock, struct sockaddr_in *sin));
-
-
-void
-prusage()
-{
- (void) fprintf(stderr, usage);
- exit(1);
-}
-
-void
-do_fork()
-{
- int t;
- long pid;
-
- if (trace)
- return;
-
- if ((pid = fork()))
- exit(0);
-
- for (t = 0; t < 20; t++)
- if (t != s)
- (void) close(t);
-
- (void) setsid ();
-
- initlog();
-}
-
-/*
- * M A I N
- */
-char *sendaddress, *recvaddress;
-
-int
-main(argc, argv)
- int argc;
- char *argv[];
-{
- struct sigaction sa;
- struct sockaddr_in from;
- struct sockaddr_in *to = &whereto;
- struct sockaddr_in joinaddr;
- int val;
- int c;
-
- min_adv_int =( max_adv_int * 3 / 4);
- lifetime = (3*max_adv_int);
-
- while ((c = getopt(argc, argv, "dtvsrabfT:p:")) != EOF) {
- switch(c) {
- case 'd':
- debug = 1;
- break;
- case 't':
- trace = 1;
- break;
- case 'v':
- verbose++;
- break;
- case 's':
- solicit = 1;
- break;
- case 'r':
- responder = 1;
- break;
- case 'a':
- best_preference = 0;
- break;
- case 'b':
- best_preference = 1;
- break;
- case 'f':
- forever = 1;
- break;
- case 'T':
- val = strtol(optarg, (char **)NULL, 0);
- if (val < 4 || val > 1800) {
- (void) fprintf(stderr,
- "Bad Max Advertizement Interval\n");
- exit(1);
- }
- max_adv_int = val;
- min_adv_int =( max_adv_int * 3 / 4);
- lifetime = (3*max_adv_int);
- break;
- case 'p':
- val = strtol(optarg, (char **)NULL, 0);
- preference = val;
- break;
- default:
- prusage();
- /* NOTREACHED*/
- }
- }
- argc -= optind;
- argv += optind;
-
- if( argc < 1) {
- if (support_multicast()) {
- if (responder)
- sendaddress = ALL_HOSTS_ADDRESS;
- else
- sendaddress = ALL_ROUTERS_ADDRESS;
- } else
- sendaddress = "255.255.255.255";
- } else {
- sendaddress = argv[0];
- argc--; argv++;
- }
-
- if (argc < 1) {
- if (support_multicast()) {
- if (responder)
- recvaddress = ALL_ROUTERS_ADDRESS;
- else
- recvaddress = ALL_HOSTS_ADDRESS;
- } else
- recvaddress = "255.255.255.255";
- } else {
- recvaddress = argv[0];
- argc--; argv++;
- }
- if (argc != 0) {
- (void) fprintf(stderr, "Extra paramaters\n");
- prusage();
- /* NOTREACHED */
- }
-
- if (solicit && responder) {
- prusage();
- /* NOTREACHED */
- }
-
- if (!(solicit && !forever)) {
- do_fork();
-/*
- * Added the next line to stop forking a second time
- * Fraser Gardiner - Sun Microsystems Australia
- */
- forever = 1;
- }
-
- bzero( (char *)&whereto, sizeof(struct sockaddr_in) );
- to->sin_family = AF_INET;
- to->sin_addr.s_addr = inet_addr(sendaddress);
-
- bzero( (char *)&joinaddr, sizeof(struct sockaddr_in) );
- joinaddr.sin_family = AF_INET;
- joinaddr.sin_addr.s_addr = inet_addr(recvaddress);
-
- if (responder) {
- /* TBD fix this to be more random */
- srandom((int)gethostid()+(int)time((time_t *)NULL));
- }
-
- if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0) {
- logperror("socket");
- exit(5);
- }
-
- setvbuf( stdout, NULL, _IOLBF, 0 );
-
- (void) signal( SIGINT, finish );
- (void) signal( SIGTERM, finish );
- (void) signal( SIGHUP, initifs );
-
- init();
- if (join(s, &joinaddr) < 0) {
- logerr("Failed joining addresses\n");
- exit (2);
- }
-
-
- /*
- * Make sure that this signal actually interrupts (rather than
- * restarts) the recvfrom call below.
- */
- memset(&sa, 0, sizeof(sa));
- sa.sa_handler = timer;
- sigemptyset(&sa.sa_mask);
- sa.sa_flags = 0; /* note: no SA_RESTART */
- (void) sigaction(SIGALRM, &sa, (struct sigaction *)NULL);
- timer(0); /* start things going */
-
- for (;;) {
- int len = sizeof (packet);
- int fromlen = sizeof (from);
- int cc;
-
- if ( (cc=recvfrom(s, (char *)packet, len, 0,
- (struct sockaddr *)&from, &fromlen)) < 0) {
- if( errno == EINTR )
- continue;
- logperror("recvfrom");
- continue;
- }
- pr_pack( (char *)packet, cc, &from );
- }
- /*NOTREACHED*/
-}
-
-#define TIMER_INTERVAL 3
-#define GETIFCONF_TIMER 30
-
-int left_until_advertise;
-
-/* Called every TIMER_INTERVAL */
-void timer(sig)
- int sig;
-{
- static int left_until_getifconf;
- static int left_until_solicit;
-
- left_until_getifconf -= TIMER_INTERVAL;
- left_until_advertise -= TIMER_INTERVAL;
- left_until_solicit -= TIMER_INTERVAL;
-
- if (left_until_getifconf < 0) {
- initifs(0);
- left_until_getifconf = GETIFCONF_TIMER;
- }
- if (responder && left_until_advertise <= 0) {
- ntransmitted++;
- advertise(&whereto);
- if (ntransmitted < initial_advertisements)
- left_until_advertise = initial_advert_interval;
- else
- left_until_advertise = min_adv_int +
- ((max_adv_int - min_adv_int) *
- (random() % 1000)/1000);
- } else if (solicit && left_until_solicit <= 0) {
- ntransmitted++;
- solicitor(&whereto);
- if (ntransmitted < max_solicitations)
- left_until_solicit = solicitation_interval;
- else {
- solicit = 0;
- if (!forever && nreceived == 0)
- exit(5);
- }
- }
- age_table(TIMER_INTERVAL);
- (void) alarm(TIMER_INTERVAL);
-}
-
-/*
- * S O L I C I T O R
- *
- * Compose and transmit an ICMP ROUTER SOLICITATION REQUEST packet.
- * The IP packet will be added on by the kernel.
- */
-void
-solicitor(sin)
- struct sockaddr_in *sin;
-{
- static u_char outpack[MAXPACKET];
- register struct icmp *icp = (struct icmp *) ALLIGN(outpack);
- int packetlen, i;
-
- if (verbose) {
- logtrace("Sending solicitation to %s\n",
- pr_name(sin->sin_addr));
- }
- icp->icmp_type = ICMP_ROUTER_SOLICITATION;
- icp->icmp_code = 0;
- icp->icmp_cksum = 0;
- icp->icmp_void = 0; /* Reserved */
- packetlen = 8;
-
- /* Compute ICMP checksum here */
- icp->icmp_cksum = in_cksum( (u_short *)icp, packetlen );
-
- if (isbroadcast(sin))
- i = sendbcast(s, (char *)outpack, packetlen);
- else if (ismulticast(sin))
- i = sendmcast( s, (char *)outpack, packetlen, sin);
- else
- i = sendto( s, (char *)outpack, packetlen, 0,
- (struct sockaddr *)sin, sizeof(struct sockaddr));
-
- if( i < 0 || i != packetlen ) {
- if( i<0 ) {
- logperror("sendto");
- }
- logerr("wrote %s %d chars, ret=%d\n",
- sendaddress, packetlen, i );
- }
-}
-
-/*
- * A V E R T I S E
- *
- * Compose and transmit an ICMP ROUTER ADVERTISEMENT packet.
- * The IP packet will be added on by the kernel.
- */
-void
-advertise(sin)
- struct sockaddr_in *sin;
-{
- static u_char outpack[MAXPACKET];
- register struct icmp *rap = (struct icmp *) ALLIGN(outpack);
- struct icmp_ra_addr *ap;
- int packetlen, i, cc;
-
- if (verbose) {
- logtrace("Sending advertisement to %s\n",
- pr_name(sin->sin_addr));
- }
-
- for (i = 0; i < num_interfaces; i++) {
- rap->icmp_type = ICMP_ROUTER_ADVERTISEMENT;
- rap->icmp_code = 0;
- rap->icmp_cksum = 0;
- rap->icmp_num_addrs = 0;
- rap->icmp_wpa = 2;
- rap->icmp_lifetime = lifetime;
- packetlen = 8;
-
- /*
- * TODO handle multiple logical interfaces per
- * physical interface. (increment with rap->icmp_wpa * 4 for
- * each address.)
- */
- ap = (struct icmp_ra_addr *)ALLIGN(outpack + ICMP_MINLEN);
- ap->ira_addr = interfaces[i].localaddr.s_addr;
- ap->ira_preference = interfaces[i].preference;
- packetlen += rap->icmp_wpa * 4;
- rap->icmp_num_addrs++;
-
-
- /* Compute ICMP checksum here */
- rap->icmp_cksum = in_cksum( (u_short *)rap, packetlen );
-
- if (isbroadcast(sin))
- cc = sendbcastif(s, (char *)outpack, packetlen,
- &interfaces[i]);
- else if (ismulticast(sin))
- cc = sendmcastif( s, (char *)outpack, packetlen, sin,
- &interfaces[i]);
- else {
- struct interface *ifp = &interfaces[i];
- /*
- * Verify that the interface matches the destination
- * address.
- */
- if ((sin->sin_addr.s_addr & ifp->netmask.s_addr) ==
- (ifp->address.s_addr & ifp->netmask.s_addr)) {
- if (debug) {
- logdebug("Unicast to %s ",
- pr_name(sin->sin_addr));
- logdebug("on interface %s\n",
- pr_name(ifp->address));
- }
- cc = sendto( s, (char *)outpack, packetlen, 0,
- (struct sockaddr *)sin,
- sizeof(struct sockaddr));
- } else
- cc = packetlen;
- }
- if( cc < 0 || cc != packetlen ) {
- if (cc < 0) {
- logperror("sendto");
- } else {
- logerr("wrote %s %d chars, ret=%d\n",
- sendaddress, packetlen, cc );
- }
- }
- }
-}
-
-/*
- * P R _ T Y P E
- *
- * Convert an ICMP "type" field to a printable string.
- */
-char *
-pr_type( t )
-register int t;
-{
- static char *ttab[] = {
- "Echo Reply",
- "ICMP 1",
- "ICMP 2",
- "Dest Unreachable",
- "Source Quench",
- "Redirect",
- "ICMP 6",
- "ICMP 7",
- "Echo",
- "Router Advertise",
- "Router Solicitation",
- "Time Exceeded",
- "Parameter Problem",
- "Timestamp",
- "Timestamp Reply",
- "Info Request",
- "Info Reply",
- "Netmask Request",
- "Netmask Reply"
- };
-
- if ( t < 0 || t > 16 )
- return("OUT-OF-RANGE");
-
- return(ttab[t]);
-}
-
-/*
- * P R _ N A M E
- *
- * Return a string name for the given IP address.
- */
-char *pr_name(addr)
- struct in_addr addr;
-{
- char *inet_ntoa();
- struct hostent *phe;
- static char buf[256];
-
- phe = gethostbyaddr((char *)&addr.s_addr, 4, AF_INET);
- if (phe == NULL)
- return( inet_ntoa(addr));
- (void) sprintf(buf, "%s (%s)", phe->h_name, inet_ntoa(addr));
- return(buf);
-}
-
-/*
- * P R _ P A C K
- *
- * Print out the packet, if it came from us. This logic is necessary
- * because ALL readers of the ICMP socket get a copy of ALL ICMP packets
- * which arrive ('tis only fair). This permits multiple copies of this
- * program to be run without having intermingled output (or statistics!).
- */
-void
-pr_pack( buf, cc, from )
-char *buf;
-int cc;
-struct sockaddr_in *from;
-{
- struct ip *ip;
- register struct icmp *icp;
- register int i;
- int hlen;
-
- ip = (struct ip *) ALLIGN(buf);
- hlen = ip->ip_hl << 2;
- if (cc < hlen + ICMP_MINLEN) {
- if (verbose)
- logtrace("packet too short (%d bytes) from %s\n", cc,
- pr_name(from->sin_addr));
- return;
- }
- cc -= hlen;
- icp = (struct icmp *)ALLIGN(buf + hlen);
- if (ip->ip_p == 0) {
- /*
- * Assume that we are running on a pre-4.3BSD system
- * such as SunOS before 4.0
- */
- icp = (struct icmp *)ALLIGN(buf);
- }
- switch (icp->icmp_type) {
- case ICMP_ROUTER_ADVERTISEMENT: {
- struct icmp *rap = (struct icmp *)ALLIGN(icp);
- struct icmp_ra_addr *ap;
-
- if (responder)
- break;
-
- /* TBD verify that the link is multicast or broadcast */
- /* XXX Find out the link it came in over? */
-#ifdef notdef
- if (debug) {
- logdebug("ROUTER_ADVERTISEMENT: \n");
- pr_hex(buf+hlen, cc);
- }
-#endif notdef
- if (in_cksum((u_short *)ALLIGN(buf+hlen), cc)) {
- if (verbose)
- logtrace("ICMP %s from %s: Bad checksum\n",
- pr_type((int)rap->icmp_type),
- pr_name(from->sin_addr));
- return;
- }
- if (rap->icmp_code != 0) {
- if (verbose)
- logtrace("ICMP %s from %s: Code = %d\n",
- pr_type((int)rap->icmp_type),
- pr_name(from->sin_addr),
- rap->icmp_code);
- return;
- }
- if (rap->icmp_num_addrs < 1) {
- if (verbose)
- logtrace("ICMP %s from %s: No addresses\n",
- pr_type((int)rap->icmp_type),
- pr_name(from->sin_addr));
- return;
- }
- if (rap->icmp_wpa < 2) {
- if (verbose)
- logtrace("ICMP %s from %s: Words/addr = %d\n",
- pr_type((int)rap->icmp_type),
- pr_name(from->sin_addr),
- rap->icmp_wpa);
- return;
- }
- if ((unsigned)cc <
- ICMP_MINLEN + rap->icmp_num_addrs * rap->icmp_wpa * 4) {
- if (verbose)
- logtrace("ICMP %s from %s: Too short %d, %d\n",
- pr_type((int)rap->icmp_type),
- pr_name(from->sin_addr),
- cc,
- ICMP_MINLEN +
- rap->icmp_num_addrs * rap->icmp_wpa * 4);
- return;
- }
- rap->icmp_lifetime = ntohs(rap->icmp_lifetime);
- if (rap->icmp_lifetime < 4) {
- if (verbose)
- logtrace("ICMP %s from %s: Lifetime = %d\n",
- pr_type((int)rap->icmp_type),
- pr_name(from->sin_addr),
- rap->icmp_lifetime);
- return;
- }
- if (verbose)
- logtrace("ICMP %s from %s, lifetime %d\n",
- pr_type((int)rap->icmp_type),
- pr_name(from->sin_addr),
- rap->icmp_lifetime);
-
- /* Check that at least one router address is a neighboor
- * on the arriving link.
- */
- for (i = 0; (unsigned)i < rap->icmp_num_addrs; i++) {
- struct in_addr ina;
- ap = (struct icmp_ra_addr *)
- ALLIGN(buf + hlen + ICMP_MINLEN +
- i * rap->icmp_wpa * 4);
- ina.s_addr = ap->ira_addr;
- if (verbose)
- logtrace("\taddress %s, preference 0x%x\n",
- pr_name(ina),
- ntohl(ap->ira_preference));
- if (!responder) {
- if (is_directly_connected(ina))
- record_router(ina,
- (long)ntohl(ap->ira_preference),
- rap->icmp_lifetime);
- }
- }
- nreceived++;
- if (!forever) {
- do_fork();
- forever = 1;
-/*
- * The next line was added so that the alarm is set for the new procces
- * Fraser Gardiner Sun Microsystems Australia
- */
- (void) alarm(TIMER_INTERVAL);
- }
- break;
- }
-
- case ICMP_ROUTER_SOLICITATION: {
- struct sockaddr_in sin;
-
- if (!responder)
- break;
-
- /* TBD verify that the link is multicast or broadcast */
- /* XXX Find out the link it came in over? */
-#ifdef notdef
- if (debug) {
- logdebug("ROUTER_SOLICITATION: \n");
- pr_hex(buf+hlen, cc);
- }
-#endif notdef
- if (in_cksum((u_short *)ALLIGN(buf+hlen), cc)) {
- if (verbose)
- logtrace("ICMP %s from %s: Bad checksum\n",
- pr_type((int)icp->icmp_type),
- pr_name(from->sin_addr));
- return;
- }
- if (icp->icmp_code != 0) {
- if (verbose)
- logtrace("ICMP %s from %s: Code = %d\n",
- pr_type((int)icp->icmp_type),
- pr_name(from->sin_addr),
- icp->icmp_code);
- return;
- }
-
- if (cc < ICMP_MINLEN) {
- if (verbose)
- logtrace("ICMP %s from %s: Too short %d, %d\n",
- pr_type((int)icp->icmp_type),
- pr_name(from->sin_addr),
- cc,
- ICMP_MINLEN);
- return;
- }
-
- if (verbose)
- logtrace("ICMP %s from %s\n",
- pr_type((int)icp->icmp_type),
- pr_name(from->sin_addr));
-
- if (!responder)
- break;
-
- /* Check that ip_src is either a neighboor
- * on the arriving link or 0.
- */
- sin.sin_family = AF_INET;
- if (ip->ip_src.s_addr == 0) {
- /* If it was sent to the broadcast address we respond
- * to the broadcast address.
- */
- if (IN_CLASSD(ip->ip_dst.s_addr))
- sin.sin_addr.s_addr = INADDR_ALLHOSTS_GROUP;
- else
- sin.sin_addr.s_addr = INADDR_BROADCAST;
- /* Restart the timer when we broadcast */
- left_until_advertise = min_adv_int +
- ((max_adv_int - min_adv_int)
- * (random() % 1000)/1000);
- }
- else {
- if (!is_directly_connected(ip->ip_src)) {
- if (verbose)
- logtrace("ICMP %s from %s: source not directly connected\n",
- pr_type((int)icp->icmp_type),
- pr_name(from->sin_addr));
- break;
- }
- sin.sin_addr.s_addr = ip->ip_src.s_addr;
- }
- nreceived++;
- ntransmitted++;
- advertise(&sin);
- break;
- }
- } /* end switch */
-}
-
-
-/*
- * I N _ C K S U M
- *
- * Checksum routine for Internet Protocol family headers (C Version)
- *
- */
-int
-in_cksum(addr, len)
-u_short *addr;
-int len;
-{
- register int nleft = len;
- register u_short *w = addr;
- register u_short answer;
- u_short odd_byte = 0;
- register int sum = 0;
-
- /*
- * Our algorithm is simple, using a 32 bit accumulator (sum),
- * we add sequential 16 bit words to it, and at the end, fold
- * back all the carry bits from the top 16 bits into the lower
- * 16 bits.
- */
- while( nleft > 1 ) {
- sum += *w++;
- nleft -= 2;
- }
-
- /* mop up an odd byte, if necessary */
- if( nleft == 1 ) {
- *(u_char *)(&odd_byte) = *(u_char *)w;
- sum += odd_byte;
- }
-
- /*
- * add back carry outs from top 16 bits to low 16 bits
- */
- sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
- sum += (sum >> 16); /* add carry */
- answer = ~sum; /* truncate to 16 bits */
- return (answer);
-}
-
-/*
- * F I N I S H
- *
- * Print out statistics, and give up.
- * Heavily buffered STDIO is used here, so that all the statistics
- * will be written with 1 sys-write call. This is nice when more
- * than one copy of the program is running on a terminal; it prevents
- * the statistics output from becomming intermingled.
- */
-void
-finish(sig)
- int sig;
-{
- if (responder) {
- int i;
-
- /* Send out a packet with a preference so that all
- * hosts will know that we are dead.
- */
- logerr("terminated\n");
- for (i = 0; i < num_interfaces; i++)
- interfaces[i].preference = IGNORE_PREFERENCE;
- ntransmitted++;
- advertise(&whereto);
- }
- if (verbose) {
- logtrace("\n----%s rdisc Statistics----\n", sendaddress );
- logtrace("%d packets transmitted, ", ntransmitted );
- logtrace("%d packets received, ", nreceived );
- (void) fflush(stdout);
- }
- exit(0);
-}
-
-#include <ctype.h>
-
-#ifdef notdef
-pr_hex(data, len)
-int len;
-unsigned char *data;
-{
- FILE *out;
-
- out = stdout;
-
- while (len) {
- register int i;
- char charstring[17];
-
- (void)strcpy(charstring," "); /* 16 spaces */
- for (i = 0; i < 16; i++) {
- /* output the bytes one at a time,
- * not going pas "len" bytes
- */
- if (len) {
- char ch = *data & 0x7f; /* strip parity */
- if (!isprint((u_char)ch))
- ch = ' '; /* ensure printable */
- charstring[i] = ch;
- (void) fprintf(out,"%02x ",*data++);
- len--;
- } else
- (void) fprintf(out," ");
- if (i==7)
- (void) fprintf(out," ");
- }
-
- (void) fprintf(out," *%s*\n",charstring);
- }
-}
-#endif notdef
-
-int
-isbroadcast(sin)
- struct sockaddr_in *sin;
-{
- return (sin->sin_addr.s_addr == INADDR_BROADCAST);
-}
-
-int
-ismulticast(sin)
- struct sockaddr_in *sin;
-{
- return (IN_CLASSD(ntohl(sin->sin_addr.s_addr)));
-}
-
-/* From libc/rpc/pmap_rmt.c */
-
-int
-sendbcast(s, packet, packetlen)
- int s;
- char *packet;
- int packetlen;
-{
- int i, cc;
-
- for (i = 0; i < num_interfaces; i++) {
- if ((interfaces[i].flags & IFF_BROADCAST) == 0)
- continue;
- cc = sendbcastif(s, packet, packetlen, &interfaces[i]);
- if (cc!= packetlen) {
- return (cc);
- }
- }
- return (packetlen);
-}
-
-int
-sendbcastif(s, packet, packetlen, ifp)
- int s;
- char *packet;
- int packetlen;
- struct interface *ifp;
-{
- int cc;
- struct sockaddr_in baddr;
-
- baddr.sin_family = AF_INET;
-
- if ((ifp->flags & IFF_BROADCAST) == 0)
- return (packetlen);
-
- baddr.sin_addr = ifp->bcastaddr;
- if (debug)
- logdebug("Broadcast to %s\n",
- pr_name(baddr.sin_addr));
- cc = sendto(s, packet, packetlen, 0,
- (struct sockaddr *)&baddr, sizeof (struct sockaddr));
- if (cc!= packetlen) {
- logperror("sendbcast: sendto");
- logerr("Cannot send broadcast packet to %s\n",
- pr_name(baddr.sin_addr));
- }
- return (cc);
-}
-
-int
-sendmcast(s, packet, packetlen, sin)
- int s;
- char *packet;
- int packetlen;
- struct sockaddr_in *sin;
-{
- int i, cc;
-
- for (i = 0; i < num_interfaces; i++) {
- if ((interfaces[i].flags & IFF_MULTICAST) == 0)
- continue;
- cc = sendmcastif(s, packet, packetlen, sin, &interfaces[i]);
- if (cc!= packetlen) {
- return (cc);
- }
- }
- return (packetlen);
-}
-
-int
-sendmcastif(s, packet, packetlen, sin, ifp)
- int s;
- char *packet;
- int packetlen;
- struct sockaddr_in *sin;
- struct interface *ifp;
-{
- int cc;
- struct sockaddr_in ifaddr;
-
- ifaddr.sin_family = AF_INET;
-
- if ((ifp->flags & IFF_MULTICAST) == 0)
- return (packetlen);
-
- ifaddr.sin_addr = ifp->address;
- if (debug)
- logdebug("Multicast to interface %s\n",
- pr_name(ifaddr.sin_addr));
- if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF,
- (char *)&ifaddr.sin_addr,
- sizeof(ifaddr.sin_addr)) < 0) {
- logperror("setsockopt (IP_MULTICAST_IF)");
- logerr("Cannot send multicast packet over interface %s\n",
- pr_name(ifaddr.sin_addr));
- return (-1);
- }
- cc = sendto(s, packet, packetlen, 0,
- (struct sockaddr *)sin, sizeof (struct sockaddr));
- if (cc!= packetlen) {
- logperror("sendmcast: sendto");
- logerr("Cannot send multicast packet over interface %s\n",
- pr_name(ifaddr.sin_addr));
- }
- return (cc);
-}
-
-void
-init()
-{
- int i;
-
- initifs(0);
- for (i = 0; i < interfaces_size; i++)
- interfaces[i].preference = preference;
-}
-
-void
-initifs(sig)
- int sig;
-{
- int sock;
- struct ifconf ifc;
- struct ifreq ifreq, *ifrp, *ifend;
- struct sockaddr_in *sin;
- int n, i;
- char *buf;
- int numifs;
- unsigned bufsize;
-
- sock = socket(AF_INET, SOCK_DGRAM, 0);
- if (sock < 0) {
- logperror("initifs: socket");
- return;
- }
-#ifdef SIOCGIFNUM
- if (ioctl(sock, SIOCGIFNUM, (char *)&numifs) < 0) {
- numifs = MAXIFS;
- }
-#else
- numifs = MAXIFS;
-#endif
- bufsize = numifs * sizeof(struct ifreq);
- buf = (char *)malloc(bufsize);
- if (buf == NULL) {
- logerr("out of memory\n");
- (void) close(sock);
- return;
- }
- bzero(buf, bufsize);
- if (interfaces)
- interfaces = (struct interface *)ALLIGN(realloc((char *)interfaces,
- numifs * sizeof(struct interface)));
- else
- interfaces = (struct interface *)ALLIGN(malloc(numifs *
- sizeof(struct interface)));
- if (interfaces == NULL) {
- logerr("out of memory\n");
- (void) close(sock);
- (void) free(buf);
- return;
- }
- interfaces_size = numifs;
-
- ifc.ifc_len = bufsize;
- ifc.ifc_buf = buf;
- if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) {
- logperror("initifs: ioctl (get interface configuration)");
- (void) close(sock);
- (void) free(buf);
- return;
- }
- ifrp = (struct ifreq *)buf;
- ifend = (struct ifreq *)(buf + ifc.ifc_len);
- for (i = 0; ifrp < ifend; ifrp = (struct ifreq *)((char *)ifrp + n)) {
- ifreq = *ifrp;
- if (ioctl(sock, SIOCGIFFLAGS, (char *)&ifreq) < 0) {
- logperror("initifs: ioctl (get interface flags)");
- n = 0;
- continue;
- }
- n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name);
- if (n < sizeof(*ifrp))
- n = sizeof(*ifrp);
- if (ifrp->ifr_addr.sa_family != AF_INET)
- continue;
- if ((ifreq.ifr_flags & IFF_UP) == 0)
- continue;
- if (ifreq.ifr_flags & IFF_LOOPBACK)
- continue;
- if ((ifreq.ifr_flags & (IFF_MULTICAST | IFF_BROADCAST)) == 0)
- continue;
- sin = (struct sockaddr_in *)ALLIGN(&ifrp->ifr_addr);
- interfaces[i].localaddr = sin->sin_addr;
- interfaces[i].flags = ifreq.ifr_flags;
- interfaces[i].netmask.s_addr = (unsigned long)0xffffffff;
- if (ifreq.ifr_flags & IFF_POINTOPOINT) {
- if (ioctl(sock, SIOCGIFDSTADDR, (char *)&ifreq) < 0) {
- logperror("initifs: ioctl (get destination addr)");
- continue;
- }
- sin = (struct sockaddr_in *)ALLIGN(&ifreq.ifr_addr);
- /* A pt-pt link is identified by the remote address */
- interfaces[i].address = sin->sin_addr;
- interfaces[i].remoteaddr = sin->sin_addr;
- /* Simulate broadcast for pt-pt */
- interfaces[i].bcastaddr = sin->sin_addr;
- interfaces[i].flags |= IFF_BROADCAST;
- } else {
- /* Non pt-pt links are identified by the local address */
- interfaces[i].address = interfaces[i].localaddr;
- interfaces[i].remoteaddr = interfaces[i].address;
- if (ioctl(sock, SIOCGIFNETMASK, (char *)&ifreq) < 0) {
- logperror("initifs: ioctl (get netmask)");
- continue;
- }
- sin = (struct sockaddr_in *)ALLIGN(&ifreq.ifr_addr);
- interfaces[i].netmask = sin->sin_addr;
- if (ifreq.ifr_flags & IFF_BROADCAST) {
- if (ioctl(sock, SIOCGIFBRDADDR, (char *)&ifreq) < 0) {
- logperror("initifs: ioctl (get broadcast address)");
- continue;
- }
- sin = (struct sockaddr_in *)ALLIGN(&ifreq.ifr_addr);
- interfaces[i].bcastaddr = sin->sin_addr;
- }
- }
-#ifdef notdef
- if (debug)
- logdebug("Found interface %s, flags 0x%x\n",
- pr_name(interfaces[i].localaddr),
- interfaces[i].flags);
-#endif
- i++;
- }
- num_interfaces = i;
-#ifdef notdef
- if (debug)
- logdebug("Found %d interfaces\n", num_interfaces);
-#endif
- (void) close(sock);
- (void) free(buf);
-}
-
-int
-join(sock, sin)
- int sock;
- struct sockaddr_in *sin;
-{
- int i;
- struct ip_mreq mreq;
-
- if (isbroadcast(sin))
- return (0);
-
- mreq.imr_multiaddr = sin->sin_addr;
- for (i = 0; i < num_interfaces; i++) {
- mreq.imr_interface = interfaces[i].address;
-
- if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
- (char *)&mreq, sizeof(mreq)) < 0) {
- logperror("setsockopt (IP_ADD_MEMBERSHIP)");
- return (-1);
- }
- }
- return (0);
-}
-
-int support_multicast()
-{
- int sock;
- u_char ttl = 1;
-
- sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
- if (sock < 0) {
- logperror("support_multicast: socket");
- return (0);
- }
-
- if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL,
- (char *)&ttl, sizeof(ttl)) < 0) {
- (void) close(sock);
- return (0);
- }
- (void) close(sock);
- return (1);
-}
-
-int
-is_directly_connected(in)
- struct in_addr in;
-{
- int i;
-
- for (i = 0; i < num_interfaces; i++) {
- /* Check that the subnetwork numbers match */
-
- if ((in.s_addr & interfaces[i].netmask.s_addr ) ==
- (interfaces[i].remoteaddr.s_addr & interfaces[i].netmask.s_addr))
- return (1);
- }
- return (0);
-}
-
-
-/*
- * TABLES
- */
-struct table {
- struct in_addr router;
- int preference;
- int remaining_time;
- int in_kernel;
- struct table *next;
-};
-
-struct table *table;
-
-struct table *
-find_router(addr)
- struct in_addr addr;
-{
- struct table *tp;
-
- tp = table;
- while (tp) {
- if (tp->router.s_addr == addr.s_addr)
- return (tp);
- tp = tp->next;
- }
- return (NULL);
-}
-
-int max_preference()
-{
- struct table *tp;
- int max = (int)IGNORE_PREFERENCE;
-
- tp = table;
- while (tp) {
- if (tp->preference > max)
- max = tp->preference;
- tp = tp->next;
- }
- return (max);
-}
-
-
-/* Note: this might leave the kernel with no default route for a short time. */
-void
-age_table(time)
- int time;
-{
- struct table **tpp, *tp;
- int recalculate_max = 0;
- int max = max_preference();
-
- tpp = &table;
- while (*tpp != NULL) {
- tp = *tpp;
- tp->remaining_time -= time;
- if (tp->remaining_time <= 0) {
- *tpp = tp->next;
- if (tp->in_kernel)
- del_route(tp->router);
- if (best_preference &&
- tp->preference == max)
- recalculate_max++;
- free((char *)tp);
- } else {
- tpp = &tp->next;
- }
- }
- if (recalculate_max) {
- int max = max_preference();
-
- if (max != IGNORE_PREFERENCE) {
- tp = table;
- while (tp) {
- if (tp->preference == max && !tp->in_kernel) {
- add_route(tp->router);
- tp->in_kernel++;
- }
- tp = tp->next;
- }
- }
- }
-}
-
-void
-record_router(router, preference, ttl)
- struct in_addr router;
- long preference;
- int ttl;
-{
- struct table *tp;
- int old_max = max_preference();
- int changed_up = 0; /* max preference could have increased */
- int changed_down = 0; /* max preference could have decreased */
-
- if (debug)
- logdebug("Recording %s, preference 0x%x\n",
- pr_name(router),
- preference);
- tp = find_router(router);
- if (tp) {
- if (tp->preference > preference &&
- tp->preference == old_max)
- changed_down++;
- else if (preference > tp->preference)
- changed_up++;
- tp->preference = preference;
- tp->remaining_time = ttl;
- } else {
- if (preference > old_max)
- changed_up++;
- tp = (struct table *)ALLIGN(malloc(sizeof(struct table)));
- if (tp == NULL) {
- logerr("Out of memory\n");
- return;
- }
- tp->router = router;
- tp->preference = preference;
- tp->remaining_time = ttl;
- tp->in_kernel = 0;
- tp->next = table;
- table = tp;
- }
- if (!tp->in_kernel &&
- (!best_preference || tp->preference == max_preference()) &&
- tp->preference != IGNORE_PREFERENCE) {
- add_route(tp->router);
- tp->in_kernel++;
- }
- if (tp->preference == IGNORE_PREFERENCE && tp->in_kernel) {
- del_route(tp->router);
- tp->in_kernel = 0;
- }
- if (best_preference && changed_down) {
- /* Check if we should add routes */
- int new_max = max_preference();
- if (new_max != IGNORE_PREFERENCE) {
- tp = table;
- while (tp) {
- if (tp->preference == new_max &&
- !tp->in_kernel) {
- add_route(tp->router);
- tp->in_kernel++;
- }
- tp = tp->next;
- }
- }
- }
- if (best_preference && (changed_up || changed_down)) {
- /* Check if we should remove routes already in the kernel */
- int new_max = max_preference();
- tp = table;
- while (tp) {
- if (tp->preference < new_max && tp->in_kernel) {
- del_route(tp->router);
- tp->in_kernel = 0;
- }
- tp = tp->next;
- }
- }
-}
-
-
-#include <net/route.h>
-
-void
-add_route(addr)
- struct in_addr addr;
-{
- if (debug)
- logdebug("Add default route to %s\n", pr_name(addr));
- rtioctl(addr, RTM_ADD);
-}
-
-void
-del_route(addr)
- struct in_addr addr;
-{
- if (debug)
- logdebug("Delete default route to %s\n", pr_name(addr));
- rtioctl(addr, RTM_DELETE);
-}
-
-void
-rtioctl(addr, op)
- struct in_addr addr;
- int op;
-{
- int sock;
- struct {
- struct rt_msghdr m_rtm;
- struct sockaddr_in m_dst;
- struct sockaddr_in m_gateway;
- struct sockaddr_in m_netmask;
- } m_rtmsg;
- static int seq = 0;
-
- bzero(&m_rtmsg, sizeof(m_rtmsg));
-
- m_rtmsg.m_rtm.rtm_type = op;
- m_rtmsg.m_rtm.rtm_flags = RTF_GATEWAY | RTF_UP; /* XXX more? */
- m_rtmsg.m_rtm.rtm_version = RTM_VERSION;
- m_rtmsg.m_rtm.rtm_seq = ++seq;
- m_rtmsg.m_rtm.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
-
- /* initialise route metrics to zero.. tcp may fill these in */
- bzero(&m_rtmsg.m_rtm.rtm_rmx, sizeof(m_rtmsg.m_rtm.rtm_rmx));
-
- m_rtmsg.m_rtm.rtm_inits = 0;
- m_rtmsg.m_rtm.rtm_msglen = sizeof(m_rtmsg);
-
- m_rtmsg.m_dst.sin_len = sizeof(struct sockaddr_in);
- m_rtmsg.m_dst.sin_family = AF_INET;
- m_rtmsg.m_dst.sin_addr.s_addr = 0; /* default */
-
- /* XXX: is setting a zero length right? */
- m_rtmsg.m_netmask.sin_len = 0;
- m_rtmsg.m_netmask.sin_family = AF_INET;
- m_rtmsg.m_netmask.sin_addr.s_addr = 0; /* default */
-
- m_rtmsg.m_gateway.sin_len = sizeof(struct sockaddr_in);
- m_rtmsg.m_gateway.sin_family = AF_INET;
- m_rtmsg.m_gateway.sin_addr = addr; /* gateway */
-
- sock = socket(PF_ROUTE, SOCK_RAW, 0);
- if (sock < 0) {
- logperror("rtioctl: socket");
- return;
- }
- if (write(sock, &m_rtmsg, sizeof(m_rtmsg)) != sizeof(m_rtmsg)) {
- if (!(op == RTM_ADD && errno == EEXIST))
- logperror("rtioctl: write");
- }
- close(sock);
-}
-
-
-
-/*
- * LOGGER
- */
-
-
-static int logging = 0;
-
-void
-initlog()
-{
- logging++;
- openlog("rdisc", LOG_PID | LOG_CONS, LOG_DAEMON);
-}
-
-/* VARARGS1 */
-void
-#if __STDC__
-logerr(char *fmt, ...)
-#else
-logerr(fmt, va_alist)
- char *fmt;
- va_dcl
-#endif
-{
- va_list ap;
-
-#if __STDC__
- va_start(ap, fmt);
-#else
- va_start(ap);
-#endif
-
- if (logging)
- vsyslog(LOG_ERR, fmt, ap);
- else
- (void) vfprintf(stderr, fmt, ap);
-
- va_end(ap);
-}
-
-/* VARARGS1 */
-void
-#if __STDC__
-logtrace(char *fmt, ...)
-#else
-logtrace(fmt, va_alist)
- char *fmt;
- va_dcl
-#endif
-{
- va_list ap;
-
-#if __STDC__
- va_start(ap, fmt);
-#else
- va_start(ap);
-#endif
-
- if (logging)
- vsyslog(LOG_INFO, fmt, ap);
- else
- (void) vfprintf(stdout, fmt, ap);
-
- va_end(ap);
-}
-
-/* VARARGS1 */
-void
-#if __STDC__
-logdebug(char *fmt, ...)
-#else
-logdebug(fmt, va_alist)
- char *fmt;
- va_dcl
-#endif
-{
- va_list ap;
-
-#if __STDC__
- va_start(ap, fmt);
-#else
- va_start(ap);
-#endif
-
- if (logging)
- vsyslog(LOG_DEBUG, fmt, ap);
- else
- (void) vfprintf(stdout, fmt, ap);
-
- va_end(ap);
-}
-
-void
-logperror(str)
- char *str;
-{
- if (logging)
- syslog(LOG_ERR, "%s: %m", str);
- else
- (void) warn("%s", str);
-}