OSDN Git Service

Fix no pic
[uclinux-h8/uClinux-dist.git] / user / iputils / rdisc.c
1 /*
2  * Rdisc (this program) was developed by Sun Microsystems, Inc. and is 
3  * provided for unrestricted use provided that this legend is included on 
4  * all tape media and as a part of the software program in whole or part.  
5  * Users may copy or modify Rdisc without charge, and they may freely 
6  * distribute it.
7  *
8  * RDISC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
9  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
10  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
11  *
12  * Rdisc is provided with no support and without any obligation on the
13  * part of Sun Microsystems, Inc. to assist in its use, correction,
14  * modification or enhancement.
15  *
16  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
17  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY RDISC
18  * OR ANY PART THEREOF.
19  *
20  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
21  * or profits or other special, indirect and consequential damages, even if
22  * Sun has been advised of the possibility of such damages.
23  *
24  * Sun Microsystems, Inc.
25  * 2550 Garcia Avenue
26  * Mountain View, California  94043
27  */
28 #include <stdio.h>
29 #include <errno.h>
30 #include <signal.h>
31 #include <unistd.h>
32 #include <stdlib.h>
33 #include <sys/types.h>
34 #include <sys/time.h>
35 /* Do not use "improved" glibc version! */
36 #include <linux/limits.h>
37
38 #include <sys/param.h>
39 #include <sys/socket.h>
40 #include <sys/file.h>
41 #include <malloc.h>
42
43 #include <sys/ioctl.h>
44 #include <linux/if.h>
45 #include <linux/route.h>
46
47 #include <netinet/in.h>
48 #include <netinet/ip.h>
49 #include <netinet/ip_icmp.h>
50
51 /*
52  * The next include contains all defs and structures for multicast
53  * that are not in SunOS 4.1.x. On a SunOS 4.1.x system none of this code
54  * is ever used because it does not support multicast
55  * Fraser Gardiner - Sun Microsystems Australia
56  */
57
58 #include <netdb.h>
59 #include <arpa/inet.h>
60
61 #include <string.h>
62 #include <syslog.h>
63
64 #include "SNAPSHOT.h"
65
66 struct interface
67 {
68         struct in_addr  address;        /* Used to identify the interface */
69         struct in_addr  localaddr;      /* Actual address if the interface */
70         int             preference;
71         int             flags;
72         struct in_addr  bcastaddr;
73         struct in_addr  remoteaddr;
74         struct in_addr  netmask;
75         int             ifindex;
76         char            name[IFNAMSIZ];
77 };
78
79
80 /* 
81  * TBD
82  *      Use 255.255.255.255 for broadcasts - not the interface broadcast
83  *      address.
84  */
85
86 #define ALLIGN(ptr)     (ptr)
87
88 static int join(int sock, struct sockaddr_in *sin);
89 static void solicitor(struct sockaddr_in *);
90 #ifdef RDISC_SERVER
91 static void advertise(struct sockaddr_in *, int lft);
92 #endif
93 static char *pr_name(struct in_addr addr);
94 static void pr_pack(char *buf, int cc, struct sockaddr_in *from);
95 static void age_table(int time);
96 static void record_router(struct in_addr router, int preference, int ttl);
97 static void add_route(struct in_addr addr);
98 static void del_route(struct in_addr addr);
99 static void rtioctl(struct in_addr addr, int op);
100 static int support_multicast(void);
101 static int sendbcast(int s, char *packet, int packetlen);
102 static int sendmcast(int s, char *packet, int packetlen, struct sockaddr_in *);
103 static int sendbcastif(int s, char *packet, int packetlen, struct interface *ifp);
104 static int sendmcastif(int s, char *packet, int packetlen, struct sockaddr_in *sin, struct interface *ifp);
105 static int is_directly_connected(struct in_addr in);
106 static void initlog(void);
107 static void discard_table(void);
108 static void init(void);
109
110 #define ICMP_ROUTER_ADVERTISEMENT       9
111 #define ICMP_ROUTER_SOLICITATION        10
112
113 #define ALL_HOSTS_ADDRESS               "224.0.0.1"
114 #define ALL_ROUTERS_ADDRESS             "224.0.0.2"
115
116 #define MAXIFS 32
117
118 #if !defined(__GLIBC__) || __GLIBC__ < 2
119 /* For router advertisement */
120 struct icmp_ra
121 {
122         u_char  icmp_type;              /* type of message, see below */
123         u_char  icmp_code;              /* type sub code */
124         u_short icmp_cksum;             /* ones complement cksum of struct */
125         u_char  icmp_num_addrs;
126         u_char  icmp_wpa;               /* Words per address */
127         short   icmp_lifetime;
128 };
129
130 struct icmp_ra_addr
131 {
132         __u32   ira_addr;
133         __u32   ira_preference;
134 };
135 #else
136 #define icmp_ra icmp
137 #endif
138
139 /* Router constants */
140 #define MAX_INITIAL_ADVERT_INTERVAL     16
141 #define MAX_INITIAL_ADVERTISEMENTS      3
142 #define MAX_RESPONSE_DELAY              2       /* Not used */
143
144 /* Host constants */
145 #define MAX_SOLICITATIONS               3
146 #define SOLICITATION_INTERVAL           3
147 #define MAX_SOLICITATION_DELAY          1       /* Not used */
148
149 #define INELIGIBLE_PREF                 0x80000000      /* Maximum negative */
150
151 #define MAX_ADV_INT 600
152
153 /* Statics */
154 static int num_interfaces;
155
156 static struct interface *interfaces;
157 static int interfaces_size;                     /* Number of elements in interfaces */
158
159
160 #define MAXPACKET       4096    /* max packet size */
161
162 /* fraser */
163 int debugfile;
164
165 char usage[] =
166 "Usage: rdisc [-b] [-d] [-s] [-v] [-f] [-a] [-V] [send_address] [receive_address]\n"
167 #ifdef RDISC_SERVER
168 "       rdisc -r [-b] [-d] [-s] [-v] [-f] [-a] [-V] [-p <preference>] [-T <secs>] \n"
169 "                [send_address] [receive_address]\n"
170 #endif
171 ;
172
173
174 int s;                  /* Socket file descriptor */
175 struct sockaddr_in whereto;/* Address to send to */
176
177 /* Common variables */
178 int verbose = 0;
179 int debug = 0;
180 int trace = 0;
181 int solicit = 0;
182 int ntransmitted = 0;
183 int nreceived = 0;
184 int forever = 0;        /* Never give up on host. If 0 defer fork until 
185                          * first response.
186                          */
187
188 #ifdef RDISC_SERVER
189 /* Router variables */
190 int responder;
191 int max_adv_int = MAX_ADV_INT;
192 int min_adv_int;
193 int lifetime;
194 int initial_advert_interval = MAX_INITIAL_ADVERT_INTERVAL;
195 int initial_advertisements = MAX_INITIAL_ADVERTISEMENTS;
196 int preference = 0;             /* Setable with -p option */
197 #endif
198
199 /* Host variables */
200 int max_solicitations = MAX_SOLICITATIONS;
201 unsigned int solicitation_interval = SOLICITATION_INTERVAL;
202 int best_preference = 1;        /* Set to record only the router(s) with the 
203                                    best preference in the kernel. Not set
204                                    puts all routes in the kernel. */
205
206
207 static void graceful_finish(void);
208 static void finish(void);
209 static void timer(void);
210 static void initifs(void);
211 static u_short in_cksum(u_short *addr, int len);
212
213 static int logging = 0;
214
215 #define logerr(fmt...) ({ if (logging) syslog(LOG_ERR, fmt); \
216                           else fprintf(stderr, fmt); })
217 #define logtrace(fmt...) ({ if (logging) syslog(LOG_INFO, fmt); \
218                           else fprintf(stderr, fmt); })
219 #define logdebug(fmt...) ({ if (logging) syslog(LOG_DEBUG, fmt); \
220                           else fprintf(stderr, fmt); })
221 static void logperror(char *str);
222
223 static __inline__ int isbroadcast(struct sockaddr_in *sin)
224 {
225         return (sin->sin_addr.s_addr == INADDR_BROADCAST);
226 }
227
228 static __inline__ int ismulticast(struct sockaddr_in *sin)
229 {
230         return IN_CLASSD(ntohl(sin->sin_addr.s_addr));
231 }
232
233 static void prusage(void)
234 {
235         (void) fprintf(stderr, usage);
236         exit(1);
237 }
238
239 void do_fork(void)
240 {
241         int t;
242         pid_t pid;
243         
244         if (trace)
245                 return;
246
247         if ((pid=fork()) != 0)
248                 exit(0);
249
250         for (t = 0; t < OPEN_MAX; t++)
251                 if (t != s)
252                         close(t);
253
254         setsid();
255         initlog();
256 }
257
258 void signal_setup(int signo, void (*handler)(void))
259 {
260         struct sigaction sa;
261
262         memset(&sa, 0, sizeof(sa));
263
264         sa.sa_handler = (void (*)(int))handler;
265 #ifdef SA_INTERRUPT
266         sa.sa_flags = SA_INTERRUPT;
267 #endif
268         sigaction(signo, &sa, NULL);
269 }
270
271 /*
272  *                      M A I N
273  */
274 char    *sendaddress, *recvaddress;
275
276 int main(int argc, char **argv)
277 {
278         struct sockaddr_in from;
279         char **av = argv;
280         struct sockaddr_in *to = &whereto;
281         struct sockaddr_in joinaddr;
282         sigset_t sset, sset_empty;
283 #ifdef RDISC_SERVER
284         int val;
285
286         min_adv_int =( max_adv_int * 3 / 4);
287         lifetime = (3*max_adv_int);
288 #endif
289
290         argc--, av++;
291         while (argc > 0 && *av[0] == '-') {
292                 while (*++av[0]) {
293                         switch (*av[0]) {
294                         case 'd':
295                                 debug = 1;
296                                 break;
297                         case 't':
298                                 trace = 1;
299                                 break;
300                         case 'v':
301                                 verbose++;
302                                 break;
303                         case 's':
304                                 solicit = 1;
305                                 break;
306 #ifdef RDISC_SERVER
307                         case 'r':
308                                 responder = 1;
309                                 break;
310 #endif
311                         case 'a':
312                                 best_preference = 0;
313                                 break;
314                         case 'b':
315                                 best_preference = 1;
316                                 break;
317                         case 'f':
318                                 forever = 1;
319                                 break;
320                         case 'V':
321                                 printf("rdisc utility, iputils-ss%s\n", SNAPSHOT);
322                                 exit(0);
323 #ifdef RDISC_SERVER
324                         case 'T':
325                                 argc--, av++;
326                                 if (argc != 0) {
327                                         val = strtol(av[0], (char **)NULL, 0);
328                                         if (val < 4 || val > 1800) {
329                                                 (void) fprintf(stderr, 
330                                                                "Bad Max Advertizement Interval\n");
331                                                 exit(1);
332                                         }
333                                         max_adv_int = val;
334                                         min_adv_int =( max_adv_int * 3 / 4);
335                                         lifetime = (3*max_adv_int);
336                                 } else {
337                                         prusage();
338                                         /* NOTREACHED*/
339                                 } 
340                                 goto next;
341                         case 'p':
342                                 argc--, av++;
343                                 if (argc != 0) {
344                                         val = strtol(av[0], (char **)NULL, 0);
345                                         preference = val;
346                                 } else {
347                                         prusage();
348                                         /* NOTREACHED*/
349                                 }
350                                 goto next;
351 #endif
352                         default:
353                                 prusage();
354                                 /* NOTREACHED*/
355                         }
356                 }
357 #ifdef RDISC_SERVER
358 next:
359 #endif
360                 argc--, av++;
361         }
362         if( argc < 1)  {
363                 if (support_multicast()) {
364                         sendaddress = ALL_ROUTERS_ADDRESS;
365 #ifdef RDISC_SERVER
366                         if (responder)
367                                 sendaddress = ALL_HOSTS_ADDRESS;
368 #endif
369                 } else
370                         sendaddress = "255.255.255.255";
371         } else {
372                 sendaddress = av[0];
373                 argc--;
374         }
375
376         if (argc < 1) {
377                 if (support_multicast()) {
378                         recvaddress = ALL_HOSTS_ADDRESS;
379 #ifdef RDISC_SERVER
380                         if (responder)
381                                 recvaddress = ALL_ROUTERS_ADDRESS;
382 #endif
383                 } else
384                         recvaddress = "255.255.255.255";
385         } else {
386                 recvaddress = av[0];
387                 argc--;
388         }
389         if (argc != 0) {
390                 (void) fprintf(stderr, "Extra paramaters\n");
391                 prusage();
392                 /* NOTREACHED */
393         }
394
395 #ifdef RDISC_SERVER
396         if (solicit && responder) {
397                 prusage();
398                 /* NOTREACHED */
399         }
400 #endif
401
402         if (!(solicit && !forever)) {
403                 do_fork();
404 /*
405  * Added the next line to stop forking a second time
406  * Fraser Gardiner - Sun Microsystems Australia
407  */
408                 forever = 1;
409         }
410
411         bzero( (char *)&whereto, sizeof(struct sockaddr_in) );
412         to->sin_family = AF_INET;
413         to->sin_addr.s_addr = inet_addr(sendaddress);
414
415         bzero( (char *)&joinaddr, sizeof(struct sockaddr_in) );
416         joinaddr.sin_family = AF_INET;
417         joinaddr.sin_addr.s_addr = inet_addr(recvaddress);
418
419 #ifdef RDISC_SERVER
420         if (responder)
421                 srandom((int)gethostid());
422 #endif
423
424         if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0) {
425                 logperror("socket");
426                 exit(5);
427         }
428
429         setlinebuf( stdout );
430
431         signal_setup(SIGINT, finish );
432         signal_setup(SIGTERM, graceful_finish );
433         signal_setup(SIGHUP, initifs );
434         signal_setup(SIGALRM, timer );
435
436         sigemptyset(&sset);
437         sigemptyset(&sset_empty);
438         sigaddset(&sset, SIGALRM);
439         sigaddset(&sset, SIGHUP);
440         sigaddset(&sset, SIGTERM);
441         sigaddset(&sset, SIGINT);
442
443         init();
444         if (join(s, &joinaddr) < 0) {
445                 logerr("Failed joining addresses\n");
446                 exit (2);
447         }
448
449         timer();        /* start things going */
450
451         for (;;) {
452                 u_char  packet[MAXPACKET];
453                 int len = sizeof (packet);
454                 socklen_t fromlen = sizeof (from);
455                 int cc;
456
457                 cc=recvfrom(s, (char *)packet, len, 0, 
458                             (struct sockaddr *)&from, &fromlen);
459                 if (cc<0) {
460                         if (errno == EINTR)
461                                 continue;
462                         logperror("recvfrom");
463                         continue;
464                 }
465
466                 sigprocmask(SIG_SETMASK, &sset, NULL);
467                 pr_pack( (char *)packet, cc, &from );
468                 sigprocmask(SIG_SETMASK, &sset_empty, NULL);
469         }
470         /*NOTREACHED*/
471 }
472
473 #define TIMER_INTERVAL  3
474 #define GETIFCONF_TIMER 30
475
476 static int left_until_advertise;
477
478 /* Called every TIMER_INTERVAL */
479 void timer()
480 {
481         static int time;
482         static int left_until_getifconf;
483         static int left_until_solicit;
484
485
486         time += TIMER_INTERVAL;
487
488         left_until_getifconf -= TIMER_INTERVAL;
489         left_until_advertise -= TIMER_INTERVAL;
490         left_until_solicit -= TIMER_INTERVAL;
491
492         if (left_until_getifconf < 0) {
493                 initifs();
494                 left_until_getifconf = GETIFCONF_TIMER;
495         }
496 #ifdef RDISC_SERVER
497         if (responder && left_until_advertise <= 0) {
498                 ntransmitted++;
499                 advertise(&whereto, lifetime);
500                 if (ntransmitted < initial_advertisements)
501                         left_until_advertise = initial_advert_interval;
502                 else
503                         left_until_advertise = min_adv_int + 
504                                 ((max_adv_int - min_adv_int) * 
505                                  (random() % 1000)/1000);
506         } else
507 #endif
508         if (solicit && left_until_solicit <= 0) {
509                 ntransmitted++;
510                 solicitor(&whereto);
511                 if (ntransmitted < max_solicitations)
512                         left_until_solicit = solicitation_interval;
513                 else {
514                         solicit = 0;
515                         if (!forever && nreceived == 0)
516                                 exit(5);
517                 }
518         }
519         age_table(TIMER_INTERVAL);
520         alarm(TIMER_INTERVAL);
521 }
522
523 /*
524  *                      S O L I C I T O R
525  * 
526  * Compose and transmit an ICMP ROUTER SOLICITATION REQUEST packet.  
527  * The IP packet will be added on by the kernel.  
528  */
529 void
530 solicitor(struct sockaddr_in *sin)
531 {
532         static u_char outpack[MAXPACKET];
533         struct icmphdr *icp = (struct icmphdr *) ALLIGN(outpack);
534         int packetlen, i;
535
536         if (verbose) {
537                 logtrace("Sending solicitation to %s\n",
538                          pr_name(sin->sin_addr));
539         }
540         icp->type = ICMP_ROUTER_SOLICITATION;
541         icp->code = 0;
542         icp->checksum = 0;
543         icp->un.gateway = 0; /* Reserved */
544         packetlen = 8;
545
546         /* Compute ICMP checksum here */
547         icp->checksum = in_cksum( (u_short *)icp, packetlen );
548
549         if (isbroadcast(sin)) 
550                 i = sendbcast(s, (char *)outpack, packetlen);
551         else if (ismulticast(sin))
552                 i = sendmcast(s, (char *)outpack, packetlen, sin);
553         else
554                 i = sendto( s, (char *)outpack, packetlen, 0,
555                            (struct sockaddr *)sin, sizeof(struct sockaddr));
556
557         if( i < 0 || i != packetlen )  {
558                 if( i<0 ) {
559                     logperror("solicitor:sendto");
560                 }
561                 logerr("wrote %s %d chars, ret=%d\n",
562                         sendaddress, packetlen, i );
563         }
564 }
565
566 #ifdef RDISC_SERVER
567 /*
568  *                      A V E R T I S E
569  * 
570  * Compose and transmit an ICMP ROUTER ADVERTISEMENT packet.  
571  * The IP packet will be added on by the kernel.  
572  */
573 void
574 advertise(struct sockaddr_in *sin, int lft)
575 {
576         static u_char outpack[MAXPACKET];
577         struct icmp_ra *rap = (struct icmp_ra *) ALLIGN(outpack);
578         struct icmp_ra_addr *ap;
579         int packetlen, i, cc;
580
581         if (verbose) {
582                 logtrace("Sending advertisement to %s\n",
583                          pr_name(sin->sin_addr));
584         }
585         
586         for (i = 0; i < num_interfaces; i++) {
587                 rap->icmp_type = ICMP_ROUTER_ADVERTISEMENT;
588                 rap->icmp_code = 0;
589                 rap->icmp_cksum = 0;
590                 rap->icmp_num_addrs = 0; 
591                 rap->icmp_wpa = 2;
592                 rap->icmp_lifetime = htons(lft);
593                 packetlen = 8;
594
595                 /* 
596                  * TODO handle multiple logical interfaces per 
597                  * physical interface. (increment with rap->icmp_wpa * 4 for
598                  * each address.)
599                  */
600                 ap = (struct icmp_ra_addr *)ALLIGN(outpack + ICMP_MINLEN);
601                 ap->ira_addr = interfaces[i].localaddr.s_addr;
602                 ap->ira_preference = htonl(interfaces[i].preference);
603                 packetlen += rap->icmp_wpa * 4;
604                 rap->icmp_num_addrs++;
605
606                 /* Compute ICMP checksum here */
607                 rap->icmp_cksum = in_cksum( (u_short *)rap, packetlen );
608
609                 if (isbroadcast(sin)) 
610                         cc = sendbcastif(s, (char *)outpack, packetlen, 
611                                         &interfaces[i]);
612                 else if (ismulticast(sin))
613                         cc = sendmcastif( s, (char *)outpack, packetlen, sin,
614                                         &interfaces[i]);
615                 else {
616                         struct interface *ifp = &interfaces[i];
617                         /* 
618                          * Verify that the interface matches the destination
619                          * address.
620                          */
621                         if ((sin->sin_addr.s_addr & ifp->netmask.s_addr) ==
622                             (ifp->address.s_addr & ifp->netmask.s_addr)) {
623                                 if (debug) {
624                                         logdebug("Unicast to %s ",
625                                                  pr_name(sin->sin_addr));
626                                         logdebug("on interface %s, %s\n",
627                                                  ifp->name,
628                                                  pr_name(ifp->address));
629                                 }
630                                 cc = sendto( s, (char *)outpack, packetlen, 0,
631                                             (struct sockaddr *)sin, 
632                                             sizeof(struct sockaddr));
633                         } else
634                                 cc = packetlen;
635                 }
636                 if( cc < 0 || cc != packetlen )  {
637                         if (cc < 0) {
638                                 logperror("sendto");
639                         } else {
640                                 logerr("wrote %s %d chars, ret=%d\n",
641                                        sendaddress, packetlen, cc );
642                         }
643                 }
644         }
645 }
646 #endif
647
648 /*
649  *                      P R _ T Y P E
650  *
651  * Convert an ICMP "type" field to a printable string.
652  */
653 char *
654 pr_type(int t)
655 {
656         static char *ttab[] = {
657                 "Echo Reply",
658                 "ICMP 1",
659                 "ICMP 2",
660                 "Dest Unreachable",
661                 "Source Quench",
662                 "Redirect",
663                 "ICMP 6",
664                 "ICMP 7",
665                 "Echo",
666                 "Router Advertise",
667                 "Router Solicitation",
668                 "Time Exceeded",
669                 "Parameter Problem",
670                 "Timestamp",
671                 "Timestamp Reply",
672                 "Info Request",
673                 "Info Reply",
674                 "Netmask Request",
675                 "Netmask Reply"
676         };
677
678         if ( t < 0 || t > 16 )
679                 return("OUT-OF-RANGE");
680
681         return(ttab[t]);
682 }
683
684 /*
685  *                      P R _ N A M E
686  *
687  * Return a string name for the given IP address.
688  */
689 char *pr_name(struct in_addr addr)
690 {
691         struct hostent *phe;
692         static char buf[80];
693
694         phe = gethostbyaddr((char *)&addr.s_addr, 4, AF_INET);
695         if (phe == NULL) 
696                 return( inet_ntoa(addr));
697         snprintf(buf, sizeof(buf), "%s (%s)", phe->h_name, inet_ntoa(addr));
698         return(buf);
699 }
700
701 /*
702  *                      P R _ P A C K
703  *
704  * Print out the packet, if it came from us.  This logic is necessary
705  * because ALL readers of the ICMP socket get a copy of ALL ICMP packets
706  * which arrive ('tis only fair).  This permits multiple copies of this
707  * program to be run without having intermingled output (or statistics!).
708  */
709 void
710 pr_pack(char *buf, int cc, struct sockaddr_in *from)
711 {
712         struct iphdr *ip;
713         struct icmphdr *icp;
714         int i;
715         int hlen;
716
717         ip = (struct iphdr *) ALLIGN(buf);
718         hlen = ip->ihl << 2;
719         if (cc < hlen + 8) {
720                 if (verbose)
721                         logtrace("packet too short (%d bytes) from %s\n", cc,
722                                  pr_name(from->sin_addr));
723                 return;
724         }
725         cc -= hlen;
726         icp = (struct icmphdr *)ALLIGN(buf + hlen);
727
728         switch (icp->type) {
729         case ICMP_ROUTER_ADVERTISEMENT:
730         {
731                 struct icmp_ra *rap = (struct icmp_ra *)ALLIGN(icp);
732                 struct icmp_ra_addr *ap;
733
734 #ifdef RDISC_SERVER
735                 if (responder)
736                         break;
737 #endif
738
739                 /* TBD verify that the link is multicast or broadcast */
740                 /* XXX Find out the link it came in over? */
741                 if (in_cksum((u_short *)ALLIGN(buf+hlen), cc)) {
742                         if (verbose)
743                                 logtrace("ICMP %s from %s: Bad checksum\n",
744                                          pr_type((int)rap->icmp_type),
745                                          pr_name(from->sin_addr));
746                         return;
747                 }
748                 if (rap->icmp_code != 0) {
749                         if (verbose)
750                                 logtrace("ICMP %s from %s: Code = %d\n",
751                                          pr_type((int)rap->icmp_type),
752                                          pr_name(from->sin_addr),
753                                          rap->icmp_code);
754                         return;
755                 }
756                 if (rap->icmp_num_addrs < 1) {
757                         if (verbose) 
758                                 logtrace("ICMP %s from %s: No addresses\n",
759                                          pr_type((int)rap->icmp_type),
760                                          pr_name(from->sin_addr));
761                         return;
762                 }
763                 if (rap->icmp_wpa < 2) {
764                         if (verbose)
765                                 logtrace("ICMP %s from %s: Words/addr = %d\n",
766                                          pr_type((int)rap->icmp_type),
767                                          pr_name(from->sin_addr),
768                                          rap->icmp_wpa);
769                         return;
770                 }
771                 if ((unsigned)cc < 
772                     8 + rap->icmp_num_addrs * rap->icmp_wpa * 4) {
773                         if (verbose)
774                                 logtrace("ICMP %s from %s: Too short %d, %d\n",
775                                               pr_type((int)rap->icmp_type),
776                                               pr_name(from->sin_addr),
777                                               cc, 
778                                               8 + rap->icmp_num_addrs * rap->icmp_wpa * 4);
779                         return;
780                 }
781
782                 if (verbose)
783                         logtrace("ICMP %s from %s, lifetime %d\n",
784                                       pr_type((int)rap->icmp_type),
785                                       pr_name(from->sin_addr),
786                                       ntohs(rap->icmp_lifetime));
787
788                 /* Check that at least one router address is a neighboor
789                  * on the arriving link.
790                  */
791                 for (i = 0; (unsigned)i < rap->icmp_num_addrs; i++) {
792                         struct in_addr ina;
793                         ap = (struct icmp_ra_addr *)
794                                 ALLIGN(buf + hlen + 8 + 
795                                        i * rap->icmp_wpa * 4);
796                         ina.s_addr = ap->ira_addr;
797                         if (verbose)
798                                 logtrace("\taddress %s, preference 0x%x\n", 
799                                               pr_name(ina),
800                                               (unsigned int)ntohl(ap->ira_preference));
801                         if (is_directly_connected(ina))
802                                 record_router(ina, 
803                                               ntohl(ap->ira_preference),
804                                               ntohs(rap->icmp_lifetime));
805                 }
806                 nreceived++;
807                 if (!forever) {
808                         do_fork();
809                         forever = 1;
810 /*
811  * The next line was added so that the alarm is set for the new procces
812  * Fraser Gardiner Sun Microsystems Australia
813  */
814                         (void) alarm(TIMER_INTERVAL);
815                 }
816                 break;
817         }
818
819 #ifdef RDISC_SERVER     
820         case ICMP_ROUTER_SOLICITATION:
821         {
822                 struct sockaddr_in sin;
823
824                 if (!responder)
825                         break;
826
827                 /* TBD verify that the link is multicast or broadcast */
828                 /* XXX Find out the link it came in over? */
829
830                 if (in_cksum((u_short *)ALLIGN(buf+hlen), cc)) {
831                         if (verbose)
832                                 logtrace("ICMP %s from %s: Bad checksum\n",
833                                               pr_type((int)icp->type),
834                                               pr_name(from->sin_addr));
835                         return;
836                 }
837                 if (icp->code != 0) {
838                         if (verbose)
839                                 logtrace("ICMP %s from %s: Code = %d\n",
840                                               pr_type((int)icp->type),
841                                               pr_name(from->sin_addr),
842                                               icp->code);
843                         return;
844                 }
845
846                 if (cc < ICMP_MINLEN) {
847                         if (verbose)
848                                 logtrace("ICMP %s from %s: Too short %d, %d\n",
849                                               pr_type((int)icp->type),
850                                               pr_name(from->sin_addr),
851                                               cc, 
852                                               ICMP_MINLEN);
853                         return;
854                 }
855
856                 if (verbose)
857                         logtrace("ICMP %s from %s\n",
858                                       pr_type((int)icp->type),
859                                       pr_name(from->sin_addr));
860                 
861                 /* Check that ip_src is either a neighboor
862                  * on the arriving link or 0.
863                  */
864                 sin.sin_family = AF_INET;
865                 if (ip->saddr == 0) {
866                         /* If it was sent to the broadcast address we respond
867                          * to the broadcast address.
868                          */
869                         if (IN_CLASSD(ntohl(ip->daddr)))
870                                 sin.sin_addr.s_addr = htonl(0xe0000001);
871                         else
872                                 sin.sin_addr.s_addr = INADDR_BROADCAST;
873                         /* Restart the timer when we broadcast */
874                         left_until_advertise = min_adv_int + 
875                                 ((max_adv_int - min_adv_int) 
876                                  * (random() % 1000)/1000);
877                 } else {
878                         sin.sin_addr = ip->saddr;
879                         if (!is_directly_connected(sin.sin_addr)) {
880                                 if (verbose)
881                                         logtrace("ICMP %s from %s: source not directly connected\n",
882                                                       pr_type((int)icp->type),
883                                                       pr_name(from->sin_addr));
884                                 break;
885                         }
886                 }
887                 nreceived++;
888                 ntransmitted++;
889                 advertise(&sin, lifetime);
890                 break;
891         }
892 #endif
893         }
894 }
895
896
897 /*
898  *                      I N _ C K S U M
899  *
900  * Checksum routine for Internet Protocol family headers (C Version)
901  *
902  */
903 u_short in_cksum(u_short *addr, int len)
904 {
905         register int nleft = len;
906         register u_short *w = addr;
907         register u_short answer;
908         register int sum = 0;
909
910         /*
911          *  Our algorithm is simple, using a 32 bit accumulator (sum),
912          *  we add sequential 16 bit words to it, and at the end, fold
913          *  back all the carry bits from the top 16 bits into the lower
914          *  16 bits.
915          */
916         while( nleft > 1 )  {
917                 sum += *w++;
918                 nleft -= 2;
919         }
920
921         /* mop up an odd byte, if necessary */
922         if( nleft == 1 )
923                 sum += htons(*(u_char *)w<<8);
924
925         /*
926          * add back carry outs from top 16 bits to low 16 bits
927          */
928         sum = (sum >> 16) + (sum & 0xffff);     /* add hi 16 to low 16 */
929         sum += (sum >> 16);                     /* add carry */
930         answer = ~sum;                          /* truncate to 16 bits */
931         return (answer);
932 }
933
934 /*
935  *                      F I N I S H
936  *
937  * Print out statistics, and give up.
938  * Heavily buffered STDIO is used here, so that all the statistics
939  * will be written with 1 sys-write call.  This is nice when more
940  * than one copy of the program is running on a terminal;  it prevents
941  * the statistics output from becomming intermingled.
942  */
943 void
944 finish()
945 {
946 #ifdef RDISC_SERVER
947         if (responder) {
948                 int i;
949
950                 /* Send out a packet with a preference so that all
951                  * hosts will know that we are dead.
952                  *
953                  * Wrong comment, wrong code. 
954                  *      ttl must be set to 0 instead. --ANK 
955                  */
956                 logerr("terminated\n");
957                 ntransmitted++;
958                 advertise(&whereto, 0);
959         }
960 #endif
961         logtrace("\n----%s rdisc Statistics----\n", sendaddress );
962         logtrace("%d packets transmitted, ", ntransmitted );
963         logtrace("%d packets received, ", nreceived );
964         logtrace("\n");
965         (void) fflush(stdout);
966         exit(0);
967 }
968
969 void
970 graceful_finish()
971 {
972         discard_table();
973         finish();
974         exit(0);
975 }
976
977
978 /* From libc/rpc/pmap_rmt.c */
979
980 int
981 sendbcast(int s, char *packet, int packetlen)
982 {
983         int i, cc;
984         
985         for (i = 0; i < num_interfaces; i++) {
986                 if ((interfaces[i].flags & (IFF_BROADCAST|IFF_POINTOPOINT)) == 0)
987                         continue;
988                 cc = sendbcastif(s, packet, packetlen, &interfaces[i]);
989                 if (cc!= packetlen) {
990                         return (cc);
991                 }
992         }
993         return (packetlen);
994 }
995
996 int
997 sendbcastif(int s, char *packet, int packetlen, struct interface *ifp)
998 {
999         int on;
1000         int cc;
1001         struct sockaddr_in baddr;
1002
1003         baddr.sin_family = AF_INET;
1004         baddr.sin_addr = ifp->bcastaddr;
1005         if (debug)
1006                 logdebug("Broadcast to %s\n",
1007                          pr_name(baddr.sin_addr));
1008         on = 1;
1009         setsockopt(s, SOL_SOCKET, SO_BROADCAST, (char*)&on, sizeof(on));
1010         cc = sendto(s, packet, packetlen, 0,
1011                     (struct sockaddr *)&baddr, sizeof (struct sockaddr));
1012         if (cc!= packetlen) {
1013                 logperror("sendbcast: sendto");
1014                 logerr("Cannot send broadcast packet to %s\n",
1015                        pr_name(baddr.sin_addr));
1016         }
1017         on = 0;
1018         setsockopt(s, SOL_SOCKET, SO_BROADCAST, (char*)&on, sizeof(on));
1019         return (cc);
1020 }
1021
1022 int
1023 sendmcast(int s, char *packet, int packetlen, struct sockaddr_in *sin)
1024 {
1025         int i, cc;
1026         
1027         for (i = 0; i < num_interfaces; i++) {
1028                 if ((interfaces[i].flags & (IFF_BROADCAST|IFF_POINTOPOINT|IFF_MULTICAST)) == 0)
1029                         continue;
1030                 cc = sendmcastif(s, packet, packetlen, sin, &interfaces[i]);
1031                 if (cc!= packetlen) {
1032                         return (cc);
1033                 }
1034         }
1035         return (packetlen);
1036 }       
1037
1038 int
1039 sendmcastif(int s, char *packet, int packetlen, struct sockaddr_in *sin,
1040             struct interface *ifp)
1041 {
1042         int cc;
1043         struct ip_mreqn mreq;
1044
1045         memset(&mreq, 0, sizeof(mreq));
1046         mreq.imr_ifindex = ifp->ifindex;
1047         mreq.imr_address = ifp->localaddr;
1048         if (debug)
1049                 logdebug("Multicast to interface %s, %s\n",
1050                          ifp->name,
1051                          pr_name(mreq.imr_address));
1052         if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, 
1053                        (char *)&mreq,
1054                        sizeof(mreq)) < 0) {
1055                 logperror("setsockopt (IP_MULTICAST_IF)");
1056                 logerr("Cannot send multicast packet over interface %s, %s\n",
1057                        ifp->name,
1058                        pr_name(mreq.imr_address));
1059                 return (-1);
1060         }
1061         cc = sendto(s, packet, packetlen, 0,
1062                     (struct sockaddr *)sin, sizeof (struct sockaddr));
1063         if (cc!= packetlen) {
1064                 logperror("sendmcast: sendto");
1065                 logerr("Cannot send multicast packet over interface %s, %s\n",
1066                        ifp->name, pr_name(mreq.imr_address));
1067         }
1068         return (cc);
1069 }
1070
1071 void
1072 init()
1073 {
1074         initifs();
1075 #ifdef RDISC_SERVER
1076         {
1077                 int i;
1078                 for (i = 0; i < interfaces_size; i++)
1079                         interfaces[i].preference = preference;
1080         }
1081 #endif
1082 }
1083
1084 void
1085 initifs()
1086 {
1087         int     sock;
1088         struct ifconf ifc;
1089         struct ifreq ifreq, *ifr;
1090         struct sockaddr_in *sin;
1091         int n, i;
1092         char *buf;
1093         int numifs;
1094         unsigned bufsize;
1095
1096         sock = socket(AF_INET, SOCK_DGRAM, 0);
1097         if (sock < 0) {
1098                 logperror("initifs: socket");
1099                 return;
1100         }
1101 #ifdef SIOCGIFNUM
1102         if (ioctl(sock, SIOCGIFNUM, (char *)&numifs) < 0) {
1103                 numifs = MAXIFS;
1104         }
1105 #else
1106         numifs = MAXIFS;
1107 #endif
1108         bufsize = numifs * sizeof(struct ifreq);
1109         buf = (char *)malloc(bufsize);
1110         if (buf == NULL) {
1111                 logerr("out of memory\n");
1112                 (void) close(sock);
1113                 return;
1114         }
1115         if (interfaces) 
1116                 interfaces = (struct interface *)ALLIGN(realloc((char *)interfaces,
1117                                          numifs * sizeof(struct interface)));
1118         else
1119                 interfaces = (struct interface *)ALLIGN(malloc(numifs *
1120                                                 sizeof(struct interface)));
1121         if (interfaces == NULL) {
1122                 logerr("out of memory\n");
1123                 (void) close(sock);
1124                 (void) free(buf);
1125                 return;
1126         }
1127         interfaces_size = numifs;
1128                                                 
1129         ifc.ifc_len = bufsize;
1130         ifc.ifc_buf = buf;
1131         if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) {
1132                 logperror("initifs: ioctl (get interface configuration)");
1133                 (void) close(sock);
1134                 (void) free(buf);
1135                 return;
1136         }
1137         ifr = ifc.ifc_req;
1138         for (i = 0, n = ifc.ifc_len/sizeof (struct ifreq); n > 0; n--, ifr++) {
1139                 ifreq = *ifr;
1140                 if (strlen(ifreq.ifr_name) >= IFNAMSIZ)
1141                         continue;
1142                 if (ioctl(sock, SIOCGIFFLAGS, (char *)&ifreq) < 0) {
1143                         logperror("initifs: ioctl (get interface flags)");
1144                         continue;
1145                 }
1146                 if (ifr->ifr_addr.sa_family != AF_INET) 
1147                         continue;
1148                 if ((ifreq.ifr_flags & IFF_UP) == 0)
1149                         continue;
1150                 if (ifreq.ifr_flags & IFF_LOOPBACK)
1151                         continue;
1152                 if ((ifreq.ifr_flags & (IFF_MULTICAST|IFF_BROADCAST|IFF_POINTOPOINT)) == 0)
1153                         continue;
1154                 strncpy(interfaces[i].name, ifr->ifr_name, IFNAMSIZ-1);
1155
1156                 sin = (struct sockaddr_in *)ALLIGN(&ifr->ifr_addr);
1157                 interfaces[i].localaddr = sin->sin_addr;
1158                 interfaces[i].flags = ifreq.ifr_flags;
1159                 interfaces[i].netmask.s_addr = (__u32)0xffffffff;
1160                 if (ioctl(sock, SIOCGIFINDEX, (char *)&ifreq) < 0) {
1161                         logperror("initifs: ioctl (get ifindex)");
1162                         continue;
1163                 }
1164                 interfaces[i].ifindex = ifreq.ifr_ifindex;
1165                 if (ifreq.ifr_flags & IFF_POINTOPOINT) {
1166                         if (ioctl(sock, SIOCGIFDSTADDR, (char *)&ifreq) < 0) {
1167                                 logperror("initifs: ioctl (get destination addr)");
1168                                 continue;
1169                         }
1170                         sin = (struct sockaddr_in *)ALLIGN(&ifreq.ifr_addr);
1171                         /* A pt-pt link is identified by the remote address */
1172                         interfaces[i].address = sin->sin_addr;
1173                         interfaces[i].remoteaddr = sin->sin_addr;
1174                         /* Simulate broadcast for pt-pt */
1175                         interfaces[i].bcastaddr = sin->sin_addr;
1176                         interfaces[i].flags |= IFF_BROADCAST;
1177                 } else {
1178                         /* Non pt-pt links are identified by the local address */
1179                         interfaces[i].address = interfaces[i].localaddr;
1180                         interfaces[i].remoteaddr = interfaces[i].address;
1181                         if (ioctl(sock, SIOCGIFNETMASK, (char *)&ifreq) < 0) {
1182                                 logperror("initifs: ioctl (get netmask)");
1183                                 continue;
1184                         }
1185                         sin = (struct sockaddr_in *)ALLIGN(&ifreq.ifr_addr);
1186                         interfaces[i].netmask = sin->sin_addr;
1187                         if (ifreq.ifr_flags & IFF_BROADCAST) {
1188                                 if (ioctl(sock, SIOCGIFBRDADDR, (char *)&ifreq) < 0) {
1189                                         logperror("initifs: ioctl (get broadcast address)");
1190                                         continue;
1191                                 }
1192                                 sin = (struct sockaddr_in *)ALLIGN(&ifreq.ifr_addr);
1193                                 interfaces[i].bcastaddr = sin->sin_addr;
1194                         }
1195                 }
1196 #ifdef notdef
1197                 if (debug)
1198                         logdebug("Found interface %s, flags 0x%x\n",
1199                                  pr_name(interfaces[i].localaddr),
1200                                  interfaces[i].flags);
1201 #endif
1202                 i++;
1203         }
1204         num_interfaces = i;
1205 #ifdef notdef
1206         if (debug)
1207                 logdebug("Found %d interfaces\n", num_interfaces);
1208 #endif
1209         (void) close(sock);
1210         (void) free(buf);
1211 }
1212
1213 int
1214 join(int sock, struct sockaddr_in *sin)
1215 {
1216         int i;
1217         struct ip_mreqn mreq;
1218
1219         if (isbroadcast(sin))
1220                 return (0);
1221
1222         mreq.imr_multiaddr = sin->sin_addr;
1223         for (i = 0; i < num_interfaces; i++) {
1224                 mreq.imr_ifindex = interfaces[i].ifindex;
1225                 mreq.imr_address.s_addr = 0;
1226
1227                 if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
1228                                (char *)&mreq, sizeof(mreq)) < 0) {
1229                         logperror("setsockopt (IP_ADD_MEMBERSHIP)");
1230                         return (-1);
1231                 }
1232         }
1233         return (0);
1234 }
1235
1236 int support_multicast()
1237 {
1238         int sock;
1239         u_char ttl = 1;
1240
1241         sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
1242         if (sock < 0) {
1243                 logperror("support_multicast: socket");
1244                 return (0);
1245         }
1246
1247         if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL, 
1248                        (char *)&ttl, sizeof(ttl)) < 0) {
1249                 (void) close(sock);
1250                 return (0);
1251         }
1252         (void) close(sock);
1253         return (1);
1254 }
1255
1256 int
1257 is_directly_connected(struct in_addr in)
1258 {
1259         int i;
1260
1261         for (i = 0; i < num_interfaces; i++) {
1262                 /* Check that the subnetwork numbers match */
1263
1264                 if ((in.s_addr & interfaces[i].netmask.s_addr ) == 
1265                     (interfaces[i].remoteaddr.s_addr & interfaces[i].netmask.s_addr))
1266                         return (1);
1267         }
1268         return (0);
1269 }
1270
1271 /*
1272  * TABLES
1273  */
1274 struct table {
1275         struct in_addr  router;
1276         int             preference;
1277         int             remaining_time;
1278         int             in_kernel;
1279         struct table    *next;
1280 };
1281
1282 struct table *table;
1283
1284 struct table *
1285 find_router(struct in_addr addr)
1286 {
1287         struct table *tp;
1288
1289         tp = table;
1290         while (tp) {
1291                 if (tp->router.s_addr == addr.s_addr)
1292                         return (tp);
1293                 tp = tp->next;
1294         }
1295         return (NULL);
1296 }
1297
1298 int max_preference(void)
1299 {
1300         struct table *tp;
1301         int max = (int)INELIGIBLE_PREF;
1302
1303         tp = table;
1304         while (tp) {
1305                 if (tp->preference > max)
1306                         max = tp->preference;
1307                 tp = tp->next;
1308         }
1309         return (max);
1310 }
1311
1312
1313 /* Note: this might leave the kernel with no default route for a short time. */
1314 void
1315 age_table(int time)
1316 {
1317         struct table **tpp, *tp;
1318         int recalculate_max = 0;
1319         int max = max_preference();
1320
1321         tpp = &table; 
1322         while (*tpp != NULL) {
1323                 tp = *tpp;
1324                 tp->remaining_time -= time;
1325                 if (tp->remaining_time <= 0) {
1326                         *tpp = tp->next;
1327                         if (tp->in_kernel) 
1328                                 del_route(tp->router);
1329                         if (best_preference && 
1330                             tp->preference == max)
1331                                 recalculate_max++;
1332                         free((char *)tp);
1333                 } else {
1334                         tpp = &tp->next;
1335                 }
1336         }
1337         if (recalculate_max) {
1338                 int max = max_preference();
1339
1340                 if (max != INELIGIBLE_PREF) {
1341                         tp = table;
1342                         while (tp) {
1343                                 if (tp->preference == max && !tp->in_kernel) {
1344                                         add_route(tp->router);
1345                                         tp->in_kernel++;
1346                                 }
1347                                 tp = tp->next;
1348                         }
1349                 }
1350         }
1351 }
1352
1353 void discard_table(void)
1354 {
1355         struct table **tpp, *tp;
1356
1357         tpp = &table; 
1358         while (*tpp != NULL) {
1359                 tp = *tpp;
1360                 *tpp = tp->next;
1361                 if (tp->in_kernel) 
1362                         del_route(tp->router);
1363                 free((char *)tp);
1364         }
1365 }
1366
1367
1368 void
1369 record_router(struct in_addr router, int preference, int ttl)
1370 {
1371         struct table *tp;
1372         int old_max = max_preference();
1373         int changed_up = 0;     /* max preference could have increased */
1374         int changed_down = 0;   /* max preference could have decreased */
1375         
1376         if (ttl < 4)
1377                 preference = INELIGIBLE_PREF;
1378
1379         if (debug)
1380                 logdebug("Recording %s, ttl %d, preference 0x%x\n", 
1381                          pr_name(router),
1382                          ttl,
1383                          preference);
1384         tp = find_router(router);
1385         if (tp) {
1386                 if (tp->preference > preference &&
1387                     tp->preference == old_max)
1388                         changed_down++;
1389                 else if (preference > tp->preference)
1390                         changed_up++;
1391                 tp->preference = preference;
1392                 tp->remaining_time = ttl;
1393         } else {
1394                 if (preference > old_max)
1395                         changed_up++;
1396                 tp = (struct table *)ALLIGN(malloc(sizeof(struct table)));
1397                 if (tp == NULL) {
1398                         logerr("Out of memory\n");
1399                         return;
1400                 }
1401                 tp->router = router;
1402                 tp->preference = preference;
1403                 tp->remaining_time = ttl;
1404                 tp->in_kernel = 0;
1405                 tp->next = table;
1406                 table = tp;
1407         }
1408         if (!tp->in_kernel && 
1409             (!best_preference || tp->preference == max_preference()) &&
1410             tp->preference != INELIGIBLE_PREF) {
1411                 add_route(tp->router);
1412                 tp->in_kernel++;
1413         }
1414         if (tp->preference == INELIGIBLE_PREF && tp->in_kernel) {
1415                 del_route(tp->router);
1416                 tp->in_kernel = 0;
1417         }
1418         if (best_preference && changed_down) {
1419                 /* Check if we should add routes */
1420                 int new_max = max_preference();
1421                 if (new_max != INELIGIBLE_PREF) {
1422                         tp = table;
1423                         while (tp) {
1424                                 if (tp->preference == new_max && 
1425                                     !tp->in_kernel) {
1426                                         add_route(tp->router);
1427                                         tp->in_kernel++;
1428                                 }
1429                                 tp = tp->next;
1430                         }
1431                 }
1432         }
1433         if (best_preference && (changed_up || changed_down)) {
1434                 /* Check if we should remove routes already in the kernel */
1435                 int new_max = max_preference();
1436                 tp = table;
1437                 while (tp) {
1438                         if (tp->preference < new_max && tp->in_kernel) {
1439                                 del_route(tp->router);
1440                                 tp->in_kernel = 0;
1441                         }
1442                         tp = tp->next;
1443                 }
1444         }
1445 }
1446
1447 void
1448 add_route(struct in_addr addr)
1449 {
1450         if (debug)
1451                 logdebug("Add default route to %s\n", pr_name(addr));
1452         rtioctl(addr, SIOCADDRT);
1453 }
1454
1455 void
1456 del_route(struct in_addr addr)
1457 {
1458         if (debug)
1459                 logdebug("Delete default route to %s\n", pr_name(addr));
1460         rtioctl(addr, SIOCDELRT);
1461 }
1462
1463 void
1464 rtioctl(struct in_addr addr, int op)
1465 {
1466         int sock;
1467         struct rtentry rt;
1468         struct sockaddr_in *sin;
1469
1470         bzero((char *)&rt, sizeof(struct rtentry));
1471         rt.rt_dst.sa_family = AF_INET;
1472         rt.rt_gateway.sa_family = AF_INET;
1473         rt.rt_genmask.sa_family = AF_INET;
1474         sin = (struct sockaddr_in *)ALLIGN(&rt.rt_gateway);
1475         sin->sin_addr = addr;
1476         rt.rt_flags = RTF_UP | RTF_GATEWAY;
1477         
1478         sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
1479         if (sock < 0) {
1480                 logperror("rtioctl: socket");
1481                 return;
1482         }
1483         if (ioctl(sock, op, (char *)&rt) < 0) {
1484                 if (!(op == SIOCADDRT && errno == EEXIST))
1485                         logperror("ioctl (add/delete route)");
1486         }
1487         (void) close(sock);
1488 }
1489         
1490 /*
1491  * LOGGER
1492  */
1493
1494 void initlog(void)
1495 {
1496         logging++;
1497         openlog("in.rdiscd", LOG_PID | LOG_CONS, LOG_DAEMON);
1498 }
1499
1500
1501 void
1502 logperror(char *str)
1503 {
1504         if (logging)
1505                 syslog(LOG_ERR, "%s: %m", str);
1506         else
1507                 (void) fprintf(stderr, "%s: %s\n", str, strerror(errno));
1508 }