1 /*
2 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
5
6 /*
7 * Copyright (c) 1987 Regents of the University of California.
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms are permitted
11 * provided that the above copyright notice and this paragraph are
12 * duplicated in all such forms and that any documentation,
13 * advertising materials, and other materials related to such
14 * distribution and use acknowledge that the software was developed
15 * by the University of California, Berkeley. The name of the
16 * University may not be used to endorse or promote products derived
17 * from this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
20 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
21 */
22
23 #include <stdio.h>
24 #include <errno.h>
25 #include <signal.h>
26 #include <sys/types.h>
27 #include <sys/time.h>
28 #include <sys/stat.h>
29
30 #include <sys/param.h>
31 #include <sys/socket.h>
32 #include <sys/file.h>
33
34 #include <sys/ioctl.h>
35 #include <net/if.h>
36
37 #include <netinet/in_systm.h>
38 #include <netinet/in.h>
39 #include <netinet/ip.h>
40 #include <netinet/ip_icmp.h>
41 #include <netdb.h>
42 #include <arpa/inet.h>
43
44 #include <fcntl.h>
45 #include <strings.h>
46 #include <stdarg.h>
47 #include <stdlib.h>
48 #include <unistd.h>
49 #include <assert.h>
50
51 #define ALIGN(ptr) (ptr)
52
53 #ifdef SYSV
54 #define signal(s, f) sigset(s, (void (*)(int))f)
55 #define random() rand()
56 #endif
57
58 #define ALL_HOSTS_ADDRESS "224.0.0.1"
59 #define ALL_ROUTERS_ADDRESS "224.0.0.2"
60
61 #define MAXIFS 256
62
63 /* For router advertisement */
64 struct icmp_ra {
65 uchar_t icmp_type; /* type of message, see below */
66 uchar_t icmp_code; /* type sub code */
67 ushort_t icmp_cksum; /* ones complement cksum of struct */
68 uchar_t icmp_num_addrs;
69 uchar_t icmp_wpa; /* Words per address */
70 short icmp_lifetime;
71 };
72
73 struct icmp_ra_addr {
74 ulong_t addr;
75 ulong_t preference;
76 };
77
78 /* Router constants */
79 #define MAX_INITIAL_ADVERT_INTERVAL 16
80 #define MAX_INITIAL_ADVERTISEMENTS 3
81 #define MAX_RESPONSE_DELAY 2 /* Not used */
82
83 /* Host constants */
84 #define MAX_SOLICITATIONS 3
85 #define SOLICITATION_INTERVAL 3
86 #define MAX_SOLICITATION_DELAY 1 /* Not used */
87
88 #define IGNORE_PREFERENCE 0x80000000 /* Maximum negative */
89
90 #define MAX_ADV_INT 600
91
92
93 /*
94 * A doubly linked list of all physical interfaces that each contain a
95 * doubly linked list of logical interfaces aka IP addresses.
96 */
97 struct phyint {
98 char pi_name[IFNAMSIZ]; /* Used to identify it */
99 int pi_state; /* See below */
100 struct logint *pi_logical_first;
101 struct logint *pi_logical_last;
102 struct phyint *pi_next;
103 struct phyint *pi_prev;
104 };
105
106 struct logint {
107 char li_name[IFNAMSIZ]; /* Used to identify it */
108 int li_state; /* See below */
109 struct in_addr li_address; /* Used to identify the interface */
110 struct in_addr li_localaddr; /* Actual address of the interface */
111 int li_preference;
112 int li_index; /* interface index (SIOCGLIFINDEX) */
113 uint64_t li_flags;
114 struct in_addr li_bcastaddr;
115 struct in_addr li_remoteaddr;
116 struct in_addr li_netmask;
117 struct logint *li_next; /* Next logical for this physical */
118 struct logint *li_prev; /* Prev logical for this physical */
119 struct phyint *li_physical; /* Back pointer */
120 };
121
122 struct phyint *phyint;
123 int num_usable_interfaces; /* Num used for sending/receiving */
124
125 /*
126 * State bits
127 */
128 #define ST_MARKED 0x01 /* To determine removed interfaces */
129 #define ST_JOINED 0x02 /* Joined multicast group */
130 #define ST_DELETED 0x04 /* Interface should be ignored */
131
132 /* Function prototypes */
133 static void solicitor(struct sockaddr_in *sin);
134 static void advertise(struct sockaddr_in *sin);
135
136 static void age_table(int time);
137 static void flush_unreachable_routers(void);
138 static void record_router(struct in_addr router, long preference, int ttl);
139
140 static void add_route(struct in_addr addr);
141 static void del_route(struct in_addr addr);
142 static void rtioctl(struct in_addr addr, int op);
143
144 static int support_multicast(void);
145 static int sendbcast(int s, char *packet, int packetlen);
146 static int sendbcastif(int s, char *packet, int packetlen,
147 struct logint *li);
148 static int sendmcast(int s, char *packet, int packetlen,
149 struct sockaddr_in *sin);
150 static int sendmcastif(int s, char *packet, int packetlen,
151 struct sockaddr_in *sin, struct logint *li);
152
153 static int ismulticast(struct sockaddr_in *sin);
154 static int isbroadcast(struct sockaddr_in *sin);
155 int in_cksum(ushort_t *addr, int len);
156 static struct logint *find_directly_connected_logint(struct in_addr in,
157 struct phyint *pi);
158 static void force_preference(int preference);
159
160 static void timer(void);
161 static void finish(void);
162 static void report(void);
163 static void report_interfaces(void);
164 static void report_routes(void);
165 static void reinitifs(void);
166
167 static struct phyint *find_phyint(char *name);
168 static struct phyint *add_phyint(char *name);
169 static void free_phyint(struct phyint *pi);
170 static struct logint *find_logint(struct phyint *pi, char *name);
171 static struct logint *add_logint(struct phyint *pi, char *name);
172 static void free_logint(struct logint *li);
173
174 static void deleted_phyint(struct phyint *pi, int s,
175 struct sockaddr_in *joinaddr);
176 static void added_logint(struct logint *li, int s,
177 struct sockaddr_in *joinaddr);
178 static void deleted_logint(struct logint *li, struct logint *newli, int s,
179 struct sockaddr_in *joinaddr);
180
181 static int initifs(int s, struct sockaddr_in *joinaddr, int preference);
182 static boolean_t getconfig(int sock, uint64_t if_flags, struct sockaddr *addr,
183 struct ifreq *ifr, struct logint *li);
184
185 static void pr_pack(char *buf, int cc, struct sockaddr_in *from);
186 char *pr_name(struct in_addr addr);
187 char *pr_type(int t);
188
189 static void initlog(void);
190 static void logerr(char *, ...);
191 static void logtrace(char *, ...);
192 static void logdebug(char *, ...);
193 static void logperror(char *);
194
195 /* Local variables */
196
197 #define MAXPACKET 4096 /* max packet size */
198 uchar_t packet[MAXPACKET];
199
200 char usage[] =
201 "Usage: rdisc [-s] [-v] [-f] [-a] [send_address] [receive_address]\n"
202 " rdisc -r [-v] [-p <preference>] [-T <secs>] \n"
203 " [send_address] [receive_address]\n";
204
205
206 int s; /* Socket file descriptor */
207 struct sockaddr_in whereto; /* Address to send to */
208 struct sockaddr_in g_joinaddr; /* Address to receive on */
209 char *sendaddress, *recvaddress; /* For logging purposes only */
210
211 /* Common variables */
212 int verbose = 0;
213 int debug = 0;
214 int trace = 0;
215 int start_solicit = 0; /* -s parameter set */
216 int solicit = 0; /* Are we currently sending solicitations? */
217 int responder;
218 int ntransmitted = 0;
219 int nreceived = 0;
220 int forever = 0; /* Never give up on host. If 0 defer fork until */
221 /* first response. */
222
223 /* Router variables */
224 int max_adv_int = MAX_ADV_INT;
225 int min_adv_int;
226 int lifetime;
227 int initial_advert_interval = MAX_INITIAL_ADVERT_INTERVAL;
228 int initial_advertisements = MAX_INITIAL_ADVERTISEMENTS;
229 ulong_t g_preference = 0; /* Setable with -p option */
230
231 /* Host variables */
232 int max_solicitations = MAX_SOLICITATIONS;
233 unsigned int solicitation_interval = SOLICITATION_INTERVAL;
234 int best_preference = 1; /* Set to record only the router(s) with the */
235 /* best preference in the kernel. Not set */
236 /* puts all routes in the kernel. */
237
238
239 static void
prusage()240 prusage()
241 {
242 (void) fprintf(stderr, usage);
243 exit(1);
244 }
245
246 static int sock = -1;
247
248 static void
do_fork()249 do_fork()
250 {
251 int t;
252
253 if (trace)
254 return;
255
256 if (fork())
257 exit(0);
258 for (t = 0; t < 20; t++)
259 if (t != s)
260 (void) close(t);
261 sock = -1;
262 (void) open("/", 0);
263 (void) dup2(0, 1);
264 (void) dup2(0, 2);
265 #ifndef SYSV
266 t = open("/dev/tty", 2);
267 if (t >= 0) {
268 (void) ioctl(t, TIOCNOTTY, (char *)0);
269 (void) close(t);
270 }
271 #else
272 (void) setpgrp();
273 #endif
274 initlog();
275 }
276
277 /*
278 * M A I N
279 */
280 int
main(int argc,char * argv[])281 main(int argc, char *argv[])
282 {
283 #ifndef SYSV
284 struct sigvec sv;
285 #endif
286 struct sockaddr_in from;
287 char **av = argv;
288 struct sockaddr_in *to = &whereto;
289 ulong_t val;
290
291 min_adv_int = (max_adv_int * 3 / 4);
292 lifetime = (3*max_adv_int);
293
294 argc--, av++;
295 while (argc > 0 && *av[0] == '-') {
296 while (*++av[0])
297 switch (*av[0]) {
298 case 'd':
299 debug = 1;
300 break;
301 case 't':
302 trace = 1;
303 break;
304 case 'v':
305 verbose++;
306 break;
307 case 's':
308 start_solicit = solicit = 1;
309 break;
310 case 'r':
311 responder = 1;
312 break;
313 case 'a':
314 best_preference = 0;
315 break;
316 case 'b':
317 best_preference = 1;
318 break;
319 case 'f':
320 forever = 1;
321 break;
322 case 'T':
323 argc--, av++;
324 if (argc != 0) {
325 val = strtol(av[0], (char **)NULL, 0);
326 if (val < 4 || val > 1800) {
327 (void) fprintf(stderr,
328 "Bad Max Advertisement Interval\n");
329 exit(1);
330 }
331 max_adv_int = val;
332 min_adv_int = (max_adv_int * 3 / 4);
333 lifetime = (3*max_adv_int);
334 } else {
335 prusage();
336 /* NOTREACHED */
337 }
338 goto next;
339 case 'p':
340 argc--, av++;
341 if (argc != 0) {
342 val = strtoul(av[0], (char **)NULL, 0);
343 g_preference = val;
344 } else {
345 prusage();
346 /* NOTREACHED */
347 }
348 goto next;
349 default:
350 prusage();
351 /* NOTREACHED */
352 }
353 next:
354 argc--, av++;
355 }
356 if (argc < 1) {
357 if (support_multicast()) {
358 if (responder)
359 sendaddress = ALL_HOSTS_ADDRESS;
360 else
361 sendaddress = ALL_ROUTERS_ADDRESS;
362 } else
363 sendaddress = "255.255.255.255";
364 } else {
365 sendaddress = av[0];
366 argc--;
367 }
368 if (argc < 1) {
369 if (support_multicast()) {
370 if (responder)
371 recvaddress = ALL_ROUTERS_ADDRESS;
372 else
373 recvaddress = ALL_HOSTS_ADDRESS;
374 } else
375 recvaddress = "255.255.255.255";
376 } else {
377 recvaddress = av[0];
378 argc--;
379 }
380 if (argc != 0) {
381 (void) fprintf(stderr, "Extra paramaters\n");
382 prusage();
383 /* NOTREACHED */
384 }
385
386 if (solicit && responder) {
387 prusage();
388 /* NOTREACHED */
389 }
390
391 if (!(solicit && !forever)) {
392 do_fork();
393 }
394
395 bzero((char *)&whereto, sizeof (struct sockaddr_in));
396 to->sin_family = AF_INET;
397 to->sin_addr.s_addr = inet_addr(sendaddress);
398 if (to->sin_addr.s_addr == (unsigned long)-1) {
399 logerr("in.rdisc: bad address %s\n", sendaddress);
400 exit(1);
401 }
402
403 bzero((char *)&g_joinaddr, sizeof (struct sockaddr_in));
404 g_joinaddr.sin_family = AF_INET;
405 g_joinaddr.sin_addr.s_addr = inet_addr(recvaddress);
406 if (g_joinaddr.sin_addr.s_addr == (unsigned long)-1) {
407 logerr("in.rdisc: bad address %s\n", recvaddress);
408 exit(1);
409 }
410
411 if (responder) {
412 #ifdef SYSV
413 srand((int)gethostid());
414 #else
415 srandom((int)gethostid());
416 #endif
417 }
418
419 if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0) {
420 logperror("socket");
421 exit(5);
422 }
423
424 #ifdef SYSV
425 setvbuf(stdout, NULL, _IOLBF, 0);
426 #else
427 setlinebuf(stdout);
428 #endif
429
430 (void) signal(SIGINT, finish);
431 (void) signal(SIGTERM, finish);
432 (void) signal(SIGHUP, reinitifs);
433 (void) signal(SIGUSR1, report);
434
435 if (initifs(s, &g_joinaddr, g_preference) < 0) {
436 logerr("Failed initializing interfaces\n");
437 exit(2);
438 }
439
440 /*
441 * If there are no usable interfaces and we are soliciting
442 * waiting for to return an exit code (i.e. forever isn't set)
443 * give up immediately.
444 */
445 if (num_usable_interfaces == 0 && solicit && !forever) {
446 logerr("in.rdisc: No interfaces up\n");
447 exit(5);
448 }
449
450 #ifdef SYSV
451 (void) signal(SIGALRM, timer);
452 #else
453 /*
454 * Make sure that this signal actually interrupts (rather than
455 * restarts) the recvfrom call below.
456 */
457 sv.sv_handler = timer;
458 sv.sv_mask = 0;
459 sv.sv_flags = SV_INTERRUPT;
460 (void) sigvec(SIGALRM, &sv, (struct sigvec *)NULL);
461 #endif
462 timer(); /* start things going */
463
464 for (;;) {
465 int len = sizeof (packet);
466 socklen_t fromlen = (socklen_t)sizeof (from);
467 int cc;
468 sigset_t newmask, oldmask;
469
470 if ((cc = recvfrom(s, (char *)packet, len, 0,
471 (struct sockaddr *)&from,
472 &fromlen)) < 0) {
473 if (errno == EINTR)
474 continue;
475 logperror("recvfrom");
476 continue;
477 }
478 /* Block all signals while processing */
479 (void) sigfillset(&newmask);
480 (void) sigprocmask(SIG_SETMASK, &newmask, &oldmask);
481 pr_pack((char *)packet, cc, &from);
482 (void) sigprocmask(SIG_SETMASK, &oldmask, NULL);
483 }
484 /* NOTREACHED */
485 }
486
487 static void
report(void)488 report(void)
489 {
490 report_interfaces();
491 report_routes();
492 }
493
494 #define TIMER_INTERVAL 6
495 #define GETIFCONF_TIMER 30
496
497 static int left_until_advertise;
498
499 /* Called every TIMER_INTERVAL */
500 static void
timer(void)501 timer(void)
502 {
503 static int time;
504 static int left_until_getifconf;
505 static int left_until_solicit;
506
507 time += TIMER_INTERVAL;
508
509 left_until_getifconf -= TIMER_INTERVAL;
510 left_until_advertise -= TIMER_INTERVAL;
511 left_until_solicit -= TIMER_INTERVAL;
512
513 if (left_until_getifconf < 0) {
514 (void) initifs(s, &g_joinaddr, g_preference);
515 left_until_getifconf = GETIFCONF_TIMER;
516 }
517 if (responder && left_until_advertise <= 0) {
518 ntransmitted++;
519 advertise(&whereto);
520 if (ntransmitted < initial_advertisements)
521 left_until_advertise = initial_advert_interval;
522 else
523 left_until_advertise = min_adv_int +
524 ((max_adv_int - min_adv_int) *
525 (random() % 1000)/1000);
526 } else if (solicit && left_until_solicit <= 0) {
527 if (ntransmitted < max_solicitations) {
528 ntransmitted++;
529 solicitor(&whereto);
530 left_until_solicit = solicitation_interval;
531 } else {
532 solicit = 0;
533 if (!forever && nreceived == 0)
534 exit(5);
535 }
536 }
537 age_table(TIMER_INTERVAL);
538 (void) alarm(TIMER_INTERVAL);
539 }
540
541 /*
542 * S O L I C I T O R
543 *
544 * Compose and transmit an ICMP ROUTER SOLICITATION REQUEST packet.
545 * The IP packet will be added on by the kernel.
546 */
547 static void
solicitor(struct sockaddr_in * sin)548 solicitor(struct sockaddr_in *sin)
549 {
550 static uchar_t outpack[MAXPACKET];
551 register struct icmp *icp = (struct icmp *)ALIGN(outpack);
552 int packetlen, i;
553
554 if (verbose) {
555 logtrace("Sending solicitation to %s\n",
556 pr_name(sin->sin_addr));
557 }
558 icp->icmp_type = ICMP_ROUTERSOLICIT;
559 icp->icmp_code = 0;
560 icp->icmp_cksum = 0;
561 icp->icmp_void = 0; /* Reserved */
562 packetlen = 8;
563
564 /* Compute ICMP checksum here */
565 icp->icmp_cksum = in_cksum((ushort_t *)icp, packetlen);
566
567 if (isbroadcast(sin))
568 i = sendbcast(s, (char *)outpack, packetlen);
569 else if (ismulticast(sin))
570 i = sendmcast(s, (char *)outpack, packetlen, sin);
571 else {
572 struct logint *li;
573
574 li = find_directly_connected_logint(sin->sin_addr, NULL);
575 if (li != NULL && (li->li_flags & IFF_NORTEXCH)) {
576 if (verbose) {
577 logtrace("Suppressing sending %s on %s "
578 "(no route exchange on interface)\n",
579 pr_type((int)icp->icmp_type), li->li_name);
580 }
581 return;
582 } else {
583 i = sendto(s, (char *)outpack, packetlen, 0,
584 (struct sockaddr *)sin, sizeof (struct sockaddr));
585 }
586 }
587
588 if (i < 0 || i != packetlen) {
589 if (i < 0) {
590 logperror("sendto");
591 }
592 logerr("wrote %s %d chars, ret=%d\n",
593 sendaddress, packetlen, i);
594 }
595 }
596
597 /*
598 * A D V E R T I S E
599 *
600 * Compose and transmit an ICMP ROUTER ADVERTISEMENT packet.
601 * The IP packet will be added on by the kernel.
602 */
603 static void
advertise(struct sockaddr_in * sin)604 advertise(struct sockaddr_in *sin)
605 {
606 struct phyint *pi;
607 struct logint *li, *li_tmp;
608 static uchar_t outpack[MAXPACKET];
609 register struct icmp_ra *rap = (struct icmp_ra *)ALIGN(outpack);
610 struct icmp_ra_addr *ap;
611 int packetlen, cc;
612
613 if (verbose) {
614 logtrace("Sending advertisement to %s\n",
615 pr_name(sin->sin_addr));
616 }
617
618 for (pi = phyint; pi != NULL; pi = pi->pi_next) {
619 rap->icmp_type = ICMP_ROUTERADVERT;
620 rap->icmp_code = 0;
621 rap->icmp_cksum = 0;
622 rap->icmp_num_addrs = 0;
623 rap->icmp_wpa = 2;
624 rap->icmp_lifetime = htons(lifetime);
625 packetlen = ICMP_MINLEN;
626
627 for (li = pi->pi_logical_first; li != NULL; li = li->li_next) {
628 if (li->li_state & ST_DELETED)
629 continue;
630
631 /*
632 * XXX Just truncate the list of addresses.
633 * Should probably send multiple packets.
634 */
635 if (packetlen + rap->icmp_wpa * 4 > sizeof (outpack)) {
636 if (debug)
637 logdebug("full packet: %d addresses\n",
638 rap->icmp_num_addrs);
639 break;
640 }
641 ap = (struct icmp_ra_addr *)ALIGN(outpack + packetlen);
642 ap->addr = li->li_localaddr.s_addr;
643 ap->preference = htonl(li->li_preference);
644 packetlen += rap->icmp_wpa * 4;
645 rap->icmp_num_addrs++;
646 }
647
648 if (rap->icmp_num_addrs == 0)
649 continue;
650
651 /* Compute ICMP checksum here */
652 rap->icmp_cksum = in_cksum((ushort_t *)rap, packetlen);
653
654 if (isbroadcast(sin))
655 cc = sendbcastif(s, (char *)outpack, packetlen,
656 pi->pi_logical_first);
657 else if (ismulticast(sin))
658 cc = sendmcastif(s, (char *)outpack, packetlen, sin,
659 pi->pi_logical_first);
660 else {
661 /*
662 * Verify that the physical interface matches the
663 * destination address.
664 */
665 li_tmp = find_directly_connected_logint(sin->sin_addr,
666 pi);
667 if (li_tmp == NULL)
668 continue;
669 if (li_tmp->li_flags & IFF_NORTEXCH) {
670 if (verbose) {
671 logtrace("Suppressing sending %s on %s "
672 "(no route exchange on "
673 "interface)\n",
674 pr_type((int)rap->icmp_type),
675 li_tmp->li_name);
676 }
677 continue;
678 }
679 if (debug) {
680 logdebug("Unicast to %s ",
681 pr_name(sin->sin_addr));
682 logdebug("on interface %s\n", pi->pi_name);
683 }
684 cc = sendto(s, (char *)outpack, packetlen, 0,
685 (struct sockaddr *)sin, sizeof (struct sockaddr));
686 }
687 if (cc < 0 || cc != packetlen) {
688 if (cc < 0) {
689 logperror("sendto");
690 } else {
691 logerr("wrote %s %d chars, ret=%d\n",
692 sendaddress, packetlen, cc);
693 }
694 }
695 }
696 }
697
698 /*
699 * P R _ T Y P E
700 *
701 * Convert an ICMP "type" field to a printable string.
702 */
703 char *
pr_type(int t)704 pr_type(int t)
705 {
706 static char *ttab[] = {
707 "Echo Reply",
708 "ICMP 1",
709 "ICMP 2",
710 "Dest Unreachable",
711 "Source Quench",
712 "Redirect",
713 "ICMP 6",
714 "ICMP 7",
715 "Echo",
716 "Router Advertise",
717 "Router Solicitation",
718 "Time Exceeded",
719 "Parameter Problem",
720 "Timestamp",
721 "Timestamp Reply",
722 "Info Request",
723 "Info Reply",
724 "Netmask Request",
725 "Netmask Reply"
726 };
727
728 if (t < 0 || t > 16)
729 return ("OUT-OF-RANGE");
730
731 return (ttab[t]);
732 }
733
734 /*
735 * P R _ N A M E
736 *
737 * Return a string name for the given IP address.
738 */
739 char *
pr_name(struct in_addr addr)740 pr_name(struct in_addr addr)
741 {
742 struct hostent *phe;
743 static char buf[256];
744
745 phe = gethostbyaddr((char *)&addr.s_addr, 4, AF_INET);
746 if (phe == NULL)
747 return (inet_ntoa(addr));
748 (void) sprintf(buf, "%s (%s)", phe->h_name, inet_ntoa(addr));
749 return (buf);
750 }
751
752 /*
753 * P R _ P A C K
754 *
755 * Print out the packet, if it came from us. This logic is necessary
756 * because ALL readers of the ICMP socket get a copy of ALL ICMP packets
757 * which arrive ('tis only fair). This permits multiple copies of this
758 * program to be run without having intermingled output (or statistics!).
759 */
760 static void
pr_pack(char * buf,int cc,struct sockaddr_in * from)761 pr_pack(char *buf, int cc, struct sockaddr_in *from)
762 {
763 struct ip *ip;
764 register struct icmp *icp;
765 register int i;
766 int hlen;
767 struct logint *li;
768
769 ip = (struct ip *)ALIGN(buf);
770 hlen = ip->ip_hl << 2;
771 if (cc < hlen + ICMP_MINLEN) {
772 if (verbose)
773 logtrace("packet too short (%d bytes) from %s\n", cc,
774 pr_name(from->sin_addr));
775 return;
776 }
777
778 cc -= hlen;
779 icp = (struct icmp *)ALIGN(buf + hlen);
780
781 /*
782 * Let's check if IFF_NORTEXCH flag is set on the interface which
783 * recevied this packet.
784 * TODO: this code can be re-written using one socket per interface
785 * to determine which interface the packet is recevied.
786 */
787 li = find_directly_connected_logint(ip->ip_src, NULL);
788 if (li != NULL && (li->li_flags & IFF_NORTEXCH)) {
789 if (verbose) {
790 logtrace("Ignoring received %s on %s "
791 "(no route exchange on interface)",
792 pr_type((int)icp->icmp_type), li->li_name);
793 }
794 return;
795 }
796
797 if (ip->ip_p == 0) {
798 /*
799 * Assume that we are running on a pre-4.3BSD system
800 * such as SunOS before 4.0
801 */
802 icp = (struct icmp *)ALIGN(buf);
803 }
804 switch (icp->icmp_type) {
805 case ICMP_ROUTERADVERT: {
806 struct icmp_ra *rap = (struct icmp_ra *)ALIGN(icp);
807 struct icmp_ra_addr *ap;
808
809 if (responder)
810 break;
811
812 /* TBD verify that the link is multicast or broadcast */
813 /* XXX Find out the link it came in over? */
814 #ifdef notdef
815 if (debug) {
816 logdebug("ROUTER_ADVERTISEMENT: \n");
817 pr_hex(buf+hlen, cc);
818 }
819 #endif /* notdef */
820 if (in_cksum((ushort_t *)ALIGN(buf+hlen), cc)) {
821 if (verbose)
822 logtrace("ICMP %s from %s: Bad checksum\n",
823 pr_type((int)rap->icmp_type),
824 pr_name(from->sin_addr));
825 return;
826 }
827 if (rap->icmp_code != 0) {
828 if (verbose)
829 logtrace("ICMP %s from %s: Code = %d\n",
830 pr_type((int)rap->icmp_type),
831 pr_name(from->sin_addr),
832 rap->icmp_code);
833 return;
834 }
835 if (rap->icmp_num_addrs < 1) {
836 if (verbose)
837 logtrace("ICMP %s from %s: No addresses\n",
838 pr_type((int)rap->icmp_type),
839 pr_name(from->sin_addr));
840 return;
841 }
842 if (rap->icmp_wpa < 2) {
843 if (verbose)
844 logtrace("ICMP %s from %s: Words/addr = %d\n",
845 pr_type((int)rap->icmp_type),
846 pr_name(from->sin_addr),
847 rap->icmp_wpa);
848 return;
849 }
850 if ((unsigned)cc <
851 ICMP_MINLEN + rap->icmp_num_addrs * rap->icmp_wpa * 4) {
852 if (verbose)
853 logtrace("ICMP %s from %s: Too short %d, %d\n",
854 pr_type((int)rap->icmp_type),
855 pr_name(from->sin_addr),
856 cc,
857 ICMP_MINLEN +
858 rap->icmp_num_addrs *
859 rap->icmp_wpa * 4);
860 return;
861 }
862 rap->icmp_lifetime = ntohs(rap->icmp_lifetime);
863 if ((rap->icmp_lifetime < 4 && rap->icmp_lifetime != 0) ||
864 rap->icmp_lifetime > 9000) {
865 if (verbose)
866 logtrace("ICMP %s from %s: Invalid lifetime %d\n",
867 pr_type((int)rap->icmp_type),
868 pr_name(from->sin_addr),
869 rap->icmp_lifetime);
870 return;
871 }
872 if (verbose)
873 logtrace("ICMP %s from %s, lifetime %d\n",
874 pr_type((int)rap->icmp_type),
875 pr_name(from->sin_addr),
876 rap->icmp_lifetime);
877
878 /*
879 * Check that at least one router address is a neighbor
880 * on the arriving link.
881 */
882 for (i = 0; (unsigned)i < rap->icmp_num_addrs; i++) {
883 struct in_addr ina;
884 ap = (struct icmp_ra_addr *)
885 ALIGN(buf + hlen + ICMP_MINLEN +
886 i * rap->icmp_wpa * 4);
887 ap->preference = ntohl(ap->preference);
888 ina.s_addr = ap->addr;
889 if (verbose)
890 logtrace("\taddress %s, preference 0x%x\n",
891 pr_name(ina),
892 ap->preference);
893 if (!responder) {
894 if (find_directly_connected_logint(ina, NULL) !=
895 NULL) {
896 record_router(ina,
897 (long)ap->preference,
898 rap->icmp_lifetime);
899 }
900 }
901 }
902 nreceived++;
903 if (!forever) {
904 (void) alarm(0);
905 do_fork();
906 forever = 1;
907 (void) alarm(TIMER_INTERVAL);
908 }
909 break;
910 }
911
912 case ICMP_ROUTERSOLICIT: {
913 struct sockaddr_in sin;
914
915 if (!responder)
916 break;
917
918 /* TBD verify that the link is multicast or broadcast */
919 /* XXX Find out the link it came in over? */
920 #ifdef notdef
921 if (debug) {
922 logdebug("ROUTER_SOLICITATION: \n");
923 pr_hex(buf+hlen, cc);
924 }
925 #endif /* notdef */
926 if (in_cksum((ushort_t *)ALIGN(buf+hlen), cc)) {
927 if (verbose)
928 logtrace("ICMP %s from %s: Bad checksum\n",
929 pr_type((int)icp->icmp_type),
930 pr_name(from->sin_addr));
931 return;
932 }
933 if (icp->icmp_code != 0) {
934 if (verbose)
935 logtrace("ICMP %s from %s: Code = %d\n",
936 pr_type((int)icp->icmp_type),
937 pr_name(from->sin_addr),
938 icp->icmp_code);
939 return;
940 }
941
942 if (cc < ICMP_MINLEN) {
943 if (verbose)
944 logtrace("ICMP %s from %s: Too short %d, %d\n",
945 pr_type((int)icp->icmp_type),
946 pr_name(from->sin_addr),
947 cc,
948 ICMP_MINLEN);
949 return;
950 }
951
952 if (verbose)
953 logtrace("ICMP %s from %s\n",
954 pr_type((int)icp->icmp_type),
955 pr_name(from->sin_addr));
956
957 if (!responder)
958 break;
959
960 /*
961 * Check that ip_src is either a neighbor
962 * on the arriving link or 0.
963 */
964 sin.sin_family = AF_INET;
965 if (ip->ip_src.s_addr == 0) {
966 /*
967 * If it was sent to the broadcast address we respond
968 * to the broadcast address.
969 */
970 if (IN_CLASSD(ntohl(ip->ip_dst.s_addr))) {
971 sin.sin_addr.s_addr =
972 htonl(INADDR_ALLHOSTS_GROUP);
973 } else
974 sin.sin_addr.s_addr = htonl(INADDR_BROADCAST);
975 /* Restart the timer when we broadcast */
976 left_until_advertise = min_adv_int +
977 ((max_adv_int - min_adv_int)
978 * (random() % 1000)/1000);
979 } else {
980 if (li == NULL) {
981 if (verbose)
982 logtrace("ICMP %s from %s: %s\n",
983 pr_type((int)icp->icmp_type),
984 pr_name(from->sin_addr),
985 "source not directly connected");
986 break;
987 }
988 sin.sin_addr.s_addr = ip->ip_src.s_addr;
989 }
990 nreceived++;
991 ntransmitted++;
992 advertise(&sin);
993 break;
994 }
995 }
996 }
997
998
999 /*
1000 * I N _ C K S U M
1001 *
1002 * Checksum routine for Internet Protocol family headers (C Version)
1003 *
1004 */
1005 int
in_cksum(ushort_t * addr,int len)1006 in_cksum(ushort_t *addr, int len)
1007 {
1008 register int nleft = len;
1009 register ushort_t *w = addr;
1010 register ushort_t answer;
1011 ushort_t odd_byte = 0;
1012 register int sum = 0;
1013
1014 /*
1015 * Our algorithm is simple, using a 32 bit accumulator (sum),
1016 * we add sequential 16 bit words to it, and at the end, fold
1017 * back all the carry bits from the top 16 bits into the lower
1018 * 16 bits.
1019 */
1020 while (nleft > 1) {
1021 sum += *w++;
1022 nleft -= 2;
1023 }
1024
1025 /* mop up an odd byte, if necessary */
1026 if (nleft == 1) {
1027 *(uchar_t *)(&odd_byte) = *(uchar_t *)w;
1028 sum += odd_byte;
1029 }
1030
1031 /*
1032 * add back carry outs from top 16 bits to low 16 bits
1033 */
1034 sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
1035 sum += (sum >> 16); /* add carry */
1036 answer = ~sum; /* truncate to 16 bits */
1037 return (answer);
1038 }
1039
1040 /*
1041 * F I N I S H
1042 *
1043 * Print out statistics, and give up.
1044 * Heavily buffered stdio is used here, so that all the statistics
1045 * will be written with 1 sys-write call. This is nice when more
1046 * than one copy of the program is running on a terminal; it prevents
1047 * the statistics output from becoming intermingled.
1048 */
1049 static void
finish(void)1050 finish(void)
1051 {
1052 if (responder) {
1053 /*
1054 * Send out a packet with a preference so that all
1055 * hosts will know that we are dead.
1056 */
1057 logerr("terminated\n");
1058 force_preference(IGNORE_PREFERENCE);
1059 ntransmitted++;
1060 advertise(&whereto);
1061 }
1062 if (verbose) {
1063 logtrace("\n----%s rdisc Statistics----\n", sendaddress);
1064 logtrace("%d packets transmitted, ", ntransmitted);
1065 logtrace("%d packets received, ", nreceived);
1066 logtrace("\n");
1067 }
1068 (void) fflush(stdout);
1069 exit(0);
1070 }
1071
1072 #include <ctype.h>
1073
1074 #ifdef notdef
1075 int
pr_hex(unsigned char * data,int len)1076 pr_hex(unsigned char *data, int len)
1077 {
1078 FILE *out;
1079
1080 out = stdout;
1081
1082 while (len) {
1083 register int i;
1084 char charstring[17];
1085
1086 (void) strcpy(charstring, " "); /* 16 spaces */
1087 for (i = 0; i < 16; i++) {
1088 /*
1089 * output the bytes one at a time,
1090 * not going past "len" bytes
1091 */
1092 if (len) {
1093 char ch = *data & 0x7f; /* strip parity */
1094 if (!isprint((uchar_t)ch))
1095 ch = ' '; /* ensure printable */
1096 charstring[i] = ch;
1097 (void) fprintf(out, "%02x ", *data++);
1098 len--;
1099 } else
1100 (void) fprintf(out, " ");
1101 if (i == 7)
1102 (void) fprintf(out, " ");
1103 }
1104
1105 (void) fprintf(out, " *%s*\n", charstring);
1106 }
1107 }
1108 #endif /* notdef */
1109
1110 static int
isbroadcast(struct sockaddr_in * sin)1111 isbroadcast(struct sockaddr_in *sin)
1112 {
1113 return (sin->sin_addr.s_addr == htonl(INADDR_BROADCAST));
1114 }
1115
1116 static int
ismulticast(struct sockaddr_in * sin)1117 ismulticast(struct sockaddr_in *sin)
1118 {
1119 return (IN_CLASSD(ntohl(sin->sin_addr.s_addr)));
1120 }
1121
1122 /* From libc/rpc/pmap_rmt.c */
1123
1124
1125 /* Only send once per physical interface */
1126 static int
sendbcast(int s,char * packet,int packetlen)1127 sendbcast(int s, char *packet, int packetlen)
1128 {
1129 struct phyint *pi;
1130 struct logint *li;
1131 boolean_t bcast;
1132 int cc;
1133
1134 for (pi = phyint; pi != NULL; pi = pi->pi_next) {
1135 bcast = B_FALSE;
1136 for (li = pi->pi_logical_first; li != NULL; li = li->li_next) {
1137 if (li->li_state & ST_DELETED)
1138 continue;
1139
1140 if (li->li_flags & IFF_BROADCAST) {
1141 bcast = B_TRUE;
1142 break;
1143 }
1144 }
1145 if (!bcast)
1146 continue;
1147 cc = sendbcastif(s, packet, packetlen, li);
1148 if (cc != packetlen) {
1149 return (cc);
1150 }
1151 }
1152 return (packetlen);
1153 }
1154
1155 static int
sendbcastif(int s,char * packet,int packetlen,struct logint * li)1156 sendbcastif(int s, char *packet, int packetlen, struct logint *li)
1157 {
1158 int cc;
1159 struct sockaddr_in baddr;
1160 struct icmp *icp = (struct icmp *)ALIGN(packet);
1161
1162 baddr.sin_family = AF_INET;
1163
1164 if ((li->li_flags & IFF_BROADCAST) == 0) {
1165 if (verbose) {
1166 logtrace("Suppressing sending %s on %s "
1167 "(interface is not broadcast capable)\n",
1168 pr_type((int)icp->icmp_type), li->li_name);
1169 }
1170 return (packetlen);
1171 }
1172 if (li->li_flags & IFF_NORTEXCH) {
1173 if (verbose) {
1174 logtrace("Suppressing sending %s on %s "
1175 "(no route exchange on interface)\n",
1176 pr_type((int)icp->icmp_type), li->li_name);
1177 }
1178 return (packetlen);
1179 }
1180
1181 baddr.sin_addr = li->li_bcastaddr;
1182 if (debug)
1183 logdebug("Broadcast to %s\n",
1184 pr_name(baddr.sin_addr));
1185 cc = sendto(s, packet, packetlen, 0,
1186 (struct sockaddr *)&baddr, sizeof (struct sockaddr));
1187 if (cc != packetlen) {
1188 logperror("sendbcast: sendto");
1189 logerr("Cannot send broadcast packet to %s\n",
1190 pr_name(baddr.sin_addr));
1191 }
1192 return (cc);
1193 }
1194
1195 static int
sendmcast(int s,char * packet,int packetlen,struct sockaddr_in * sin)1196 sendmcast(int s, char *packet, int packetlen, struct sockaddr_in *sin)
1197 {
1198 struct phyint *pi;
1199 struct logint *li;
1200 boolean_t mcast;
1201 int cc;
1202
1203 for (pi = phyint; pi != NULL; pi = pi->pi_next) {
1204 mcast = B_FALSE;
1205 for (li = pi->pi_logical_first; li != NULL; li = li->li_next) {
1206 if (li->li_state & ST_DELETED)
1207 continue;
1208
1209 if (li->li_flags & IFF_MULTICAST) {
1210 mcast = B_TRUE;
1211 break;
1212 }
1213 }
1214 if (!mcast)
1215 continue;
1216 cc = sendmcastif(s, packet, packetlen, sin, li);
1217 if (cc != packetlen) {
1218 return (cc);
1219 }
1220 }
1221 return (packetlen);
1222 }
1223
1224 static int
sendmcastif(int s,char * packet,int packetlen,struct sockaddr_in * sin,struct logint * li)1225 sendmcastif(int s, char *packet, int packetlen, struct sockaddr_in *sin,
1226 struct logint *li)
1227 {
1228 int cc;
1229 struct sockaddr_in ifaddr;
1230 struct icmp *icp = (struct icmp *)ALIGN(packet);
1231
1232 ifaddr.sin_family = AF_INET;
1233
1234 if ((li->li_flags & IFF_MULTICAST) == 0) {
1235 if (verbose) {
1236 logtrace("Suppressing sending %s on %s "
1237 "(interface is not multicast capable)\n",
1238 pr_type((int)icp->icmp_type), li->li_name);
1239 }
1240 return (packetlen);
1241 }
1242 if (li->li_flags & IFF_NORTEXCH) {
1243 if (verbose) {
1244 logtrace("Suppressing sending %s on %s "
1245 "(no route exchange on interface)\n",
1246 pr_type((int)icp->icmp_type), li->li_name);
1247 }
1248 return (packetlen);
1249 }
1250
1251 ifaddr.sin_addr = li->li_address;
1252 if (debug)
1253 logdebug("Multicast to interface %s\n",
1254 pr_name(ifaddr.sin_addr));
1255 if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF,
1256 (char *)&ifaddr.sin_addr,
1257 sizeof (ifaddr.sin_addr)) < 0) {
1258 logperror("setsockopt (IP_MULTICAST_IF)");
1259 logerr("Cannot send multicast packet over interface %s\n",
1260 pr_name(ifaddr.sin_addr));
1261 return (-1);
1262 }
1263 cc = sendto(s, packet, packetlen, 0,
1264 (struct sockaddr *)sin, sizeof (struct sockaddr));
1265 if (cc != packetlen) {
1266 logperror("sendmcast: sendto");
1267 logerr("Cannot send multicast packet over interface %s\n",
1268 pr_name(ifaddr.sin_addr));
1269 }
1270 return (cc);
1271 }
1272
1273 static void
reinitifs(void)1274 reinitifs(void)
1275 {
1276 (void) initifs(s, &g_joinaddr, g_preference);
1277 }
1278
1279 static void
force_preference(int preference)1280 force_preference(int preference)
1281 {
1282 struct phyint *pi;
1283 struct logint *li;
1284
1285 for (pi = phyint; pi != NULL; pi = pi->pi_next) {
1286 for (li = pi->pi_logical_first; li != NULL; li = li->li_next) {
1287 if (li->li_state & ST_DELETED)
1288 continue;
1289
1290 li->li_preference = preference;
1291 }
1292 }
1293 }
1294
1295 /*
1296 * Returns -1 on failure.
1297 */
1298 static int
initifs(int s,struct sockaddr_in * joinaddr,int preference)1299 initifs(int s, struct sockaddr_in *joinaddr, int preference)
1300 {
1301 struct ifconf ifc;
1302 struct ifreq ifreq, *ifr;
1303 struct lifreq lifreq;
1304 int n;
1305 char *buf;
1306 int numifs;
1307 unsigned bufsize;
1308 struct phyint *pi;
1309 struct logint *li;
1310 int num_deletions;
1311 char phyintname[IFNAMSIZ];
1312 char *cp;
1313 int old_num_usable_interfaces = num_usable_interfaces;
1314
1315 /*
1316 * Mark all interfaces so that we can determine which ones
1317 * have gone away.
1318 */
1319 for (pi = phyint; pi != NULL; pi = pi->pi_next) {
1320 pi->pi_state |= ST_MARKED;
1321 for (li = pi->pi_logical_first; li != NULL; li = li->li_next) {
1322 li->li_state |= ST_MARKED;
1323 }
1324 }
1325
1326 if (sock < 0) {
1327 sock = socket(AF_INET, SOCK_DGRAM, 0);
1328 if (sock < 0) {
1329 logperror("initifs: socket");
1330 return (-1);
1331 }
1332 }
1333 #ifdef SIOCGIFNUM
1334 if (ioctl(sock, SIOCGIFNUM, (char *)&numifs) < 0) {
1335 logperror("initifs: SIOCGIFNUM");
1336 return (-1);
1337 }
1338 #else
1339 numifs = MAXIFS;
1340 #endif
1341 bufsize = numifs * sizeof (struct ifreq);
1342 buf = (char *)malloc(bufsize);
1343 if (buf == NULL) {
1344 logerr("out of memory\n");
1345 (void) close(sock);
1346 sock = -1;
1347 return (-1);
1348 }
1349 ifc.ifc_len = bufsize;
1350 ifc.ifc_buf = buf;
1351 if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) {
1352 logperror("initifs: ioctl (get interface configuration)");
1353 (void) close(sock);
1354 sock = -1;
1355 (void) free(buf);
1356 return (-1);
1357 }
1358 ifr = ifc.ifc_req;
1359 for (n = ifc.ifc_len/sizeof (struct ifreq); n > 0; n--, ifr++) {
1360 ifreq = *ifr;
1361 /*
1362 * We need to use new interface ioctls to get 64-bit flags.
1363 */
1364 (void) strncpy(lifreq.lifr_name, ifr->ifr_name,
1365 sizeof (ifr->ifr_name));
1366 if (ioctl(sock, SIOCGLIFFLAGS, (char *)&lifreq) < 0) {
1367 logperror("initifs: ioctl (get interface flags)");
1368 continue;
1369 }
1370 if (ifr->ifr_addr.sa_family != AF_INET)
1371 continue;
1372 if ((lifreq.lifr_flags & IFF_UP) == 0)
1373 continue;
1374 if (lifreq.lifr_flags & IFF_LOOPBACK)
1375 continue;
1376 if ((lifreq.lifr_flags & (IFF_MULTICAST | IFF_BROADCAST)) == 0)
1377 continue;
1378
1379 /* Create the physical name by truncating at the ':' */
1380 strncpy(phyintname, ifreq.ifr_name, sizeof (phyintname));
1381 if ((cp = strchr(phyintname, ':')) != NULL)
1382 *cp = '\0';
1383
1384 pi = find_phyint(phyintname);
1385 if (pi == NULL) {
1386 pi = add_phyint(phyintname);
1387 if (pi == NULL) {
1388 logerr("out of memory\n");
1389 (void) close(sock);
1390 sock = -1;
1391 (void) free(buf);
1392 return (-1);
1393 }
1394 }
1395 pi->pi_state &= ~ST_MARKED;
1396
1397 li = find_logint(pi, ifreq.ifr_name);
1398 if (li != NULL) {
1399 /*
1400 * Detect significant changes.
1401 * We treat netmask changes as insignificant but all
1402 * other changes cause a delete plus add of the
1403 * logical interface.
1404 * Note: if the flags and localaddr are unchanged
1405 * then nothing but the netmask and the broadcast
1406 * address could have changed since the other addresses
1407 * are derived from the flags and the localaddr.
1408 */
1409 struct logint newli;
1410
1411 if (!getconfig(sock, lifreq.lifr_flags, &ifr->ifr_addr,
1412 &ifreq, &newli)) {
1413 free_logint(li);
1414 continue;
1415 }
1416
1417 if (newli.li_flags != li->li_flags ||
1418 newli.li_localaddr.s_addr !=
1419 li->li_localaddr.s_addr || newli.li_index !=
1420 li->li_index) {
1421 /* Treat as an interface deletion + addition */
1422 li->li_state |= ST_DELETED;
1423 deleted_logint(li, &newli, s, joinaddr);
1424 free_logint(li);
1425 li = NULL; /* li recreated below */
1426 } else {
1427 /*
1428 * No significant changes.
1429 * Just update the netmask, and broadcast.
1430 */
1431 li->li_netmask = newli.li_netmask;
1432 li->li_bcastaddr = newli.li_bcastaddr;
1433 }
1434 }
1435 if (li == NULL) {
1436 li = add_logint(pi, ifreq.ifr_name);
1437 if (li == NULL) {
1438 logerr("out of memory\n");
1439 (void) close(sock);
1440 sock = -1;
1441 (void) free(buf);
1442 return (-1);
1443 }
1444
1445 /* init li */
1446 if (!getconfig(sock, lifreq.lifr_flags, &ifr->ifr_addr,
1447 &ifreq, li)) {
1448 free_logint(li);
1449 continue;
1450 }
1451 li->li_preference = preference;
1452 added_logint(li, s, joinaddr);
1453 }
1454 li->li_state &= ~ST_MARKED;
1455 }
1456 (void) free(buf);
1457
1458 /*
1459 * Determine which interfaces have gone away.
1460 * The deletion is done in three phases:
1461 * 1. Mark ST_DELETED
1462 * 2. Inform using the deleted_* function.
1463 * 3. Unlink and free the actual memory.
1464 * Note that for #3 the physical interface must be deleted after
1465 * the logical ones.
1466 * Also count the number of physical interfaces.
1467 */
1468 num_usable_interfaces = 0;
1469 num_deletions = 0;
1470 for (pi = phyint; pi != NULL; pi = pi->pi_next) {
1471 if (pi->pi_state & ST_MARKED) {
1472 num_deletions++;
1473 pi->pi_state |= ST_DELETED;
1474 }
1475 for (li = pi->pi_logical_first; li != NULL; li = li->li_next) {
1476 if (li->li_state & ST_MARKED) {
1477 num_deletions++;
1478 li->li_state |= ST_DELETED;
1479 }
1480 }
1481 if (!(pi->pi_state & ST_DELETED))
1482 num_usable_interfaces++;
1483 }
1484 if (num_deletions != 0) {
1485 struct phyint *nextpi;
1486 struct logint *nextli;
1487
1488 for (pi = phyint; pi != NULL; pi = pi->pi_next) {
1489 if (pi->pi_state & ST_DELETED) {
1490 /*
1491 * By deleting the physical interface pi, all of
1492 * the corresponding logical interfaces will
1493 * also be deleted so there is no need to delete
1494 * them individually.
1495 */
1496 deleted_phyint(pi, s, joinaddr);
1497 } else {
1498 for (li = pi->pi_logical_first; li != NULL;
1499 li = li->li_next) {
1500 if (li->li_state & ST_DELETED) {
1501 deleted_logint(li, NULL, s,
1502 joinaddr);
1503 }
1504 }
1505 }
1506 }
1507 /* Do the actual linked list update + free */
1508 for (pi = phyint; pi != NULL; pi = nextpi) {
1509 nextpi = pi->pi_next;
1510 for (li = pi->pi_logical_first; li != NULL;
1511 li = nextli) {
1512 nextli = li->li_next;
1513 if (li->li_state & ST_DELETED)
1514 free_logint(li);
1515 }
1516 if (pi->pi_state & ST_DELETED)
1517 free_phyint(pi);
1518 }
1519 }
1520 /*
1521 * When the set of available interfaces goes from zero to
1522 * non-zero we restart solicitations if '-s' was specified.
1523 */
1524 if (old_num_usable_interfaces == 0 && num_usable_interfaces > 0 &&
1525 start_solicit && !solicit) {
1526 if (debug)
1527 logdebug("switching to solicitations: num if %d\n",
1528 num_usable_interfaces);
1529 solicit = start_solicit;
1530 ntransmitted = 0;
1531 ntransmitted++;
1532 solicitor(&whereto);
1533 }
1534 return (0);
1535 }
1536
1537 static boolean_t
getconfig(int sock,uint64_t if_flags,struct sockaddr * addr,struct ifreq * ifr,struct logint * li)1538 getconfig(int sock, uint64_t if_flags, struct sockaddr *addr,
1539 struct ifreq *ifr, struct logint *li)
1540 {
1541 struct ifreq ifreq;
1542 struct sockaddr_in *sin;
1543 struct lifreq lifreq;
1544
1545 ifreq = *ifr; /* Copy name etc */
1546
1547 li->li_flags = if_flags;
1548 sin = (struct sockaddr_in *)ALIGN(addr);
1549 li->li_localaddr = sin->sin_addr;
1550
1551 (void) strlcpy(lifreq.lifr_name, ifr->ifr_name,
1552 sizeof (lifreq.lifr_name));
1553 if (ioctl(sock, SIOCGLIFINDEX, &lifreq) < 0) {
1554 logperror("initifs: ioctl (get if index)");
1555 /* Continue with 0; a safe value never used for interfaces */
1556 li->li_index = 0;
1557 } else {
1558 li->li_index = lifreq.lifr_index;
1559 }
1560
1561 if (if_flags & IFF_POINTOPOINT) {
1562 li->li_netmask.s_addr = (unsigned long)0xffffffff;
1563 if (ioctl(sock, SIOCGIFDSTADDR, (char *)&ifreq) < 0) {
1564 logperror("initifs: ioctl (get dest addr)");
1565 return (B_FALSE);
1566 }
1567 /* A pt-pt link is identified by the remote address */
1568 sin = (struct sockaddr_in *)ALIGN(&ifreq.ifr_addr);
1569 li->li_address = sin->sin_addr;
1570 li->li_remoteaddr = sin->sin_addr;
1571 /* Simulate broadcast for pt-pt */
1572 li->li_bcastaddr = sin->sin_addr;
1573 li->li_flags |= IFF_BROADCAST;
1574 } else {
1575 /*
1576 * Non pt-pt links are identified by the local
1577 * address
1578 */
1579 li->li_address = li->li_localaddr;
1580 li->li_remoteaddr = li->li_address;
1581 if (ioctl(sock, SIOCGIFNETMASK, (char *)&ifreq) < 0) {
1582 logperror("initifs: ioctl (get netmask)");
1583 return (B_FALSE);
1584 }
1585 sin = (struct sockaddr_in *)ALIGN(&ifreq.ifr_addr);
1586 li->li_netmask = sin->sin_addr;
1587 if (if_flags & IFF_BROADCAST) {
1588 if (ioctl(sock, SIOCGIFBRDADDR, (char *)&ifreq) < 0) {
1589 logperror(
1590 "initifs: ioctl (get broadcast address)");
1591 return (B_FALSE);
1592 }
1593 sin = (struct sockaddr_in *)ALIGN(&ifreq.ifr_addr);
1594 li->li_bcastaddr = sin->sin_addr;
1595 }
1596 }
1597 return (B_TRUE);
1598 }
1599
1600
1601 static int
support_multicast(void)1602 support_multicast(void)
1603 {
1604 int sock;
1605 uchar_t ttl = 1;
1606
1607 sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
1608 if (sock < 0) {
1609 logperror("support_multicast: socket");
1610 return (0);
1611 }
1612
1613 if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL,
1614 (char *)&ttl, sizeof (ttl)) < 0) {
1615 (void) close(sock);
1616 return (0);
1617 }
1618 (void) close(sock);
1619 return (1);
1620 }
1621
1622 /*
1623 * For a given destination address, find the logical interface to use.
1624 * If opi is NULL check all interfaces. Otherwise just match against
1625 * the specified physical interface.
1626 * Return logical interface if there's a match, NULL otherwise.
1627 */
1628 static struct logint *
find_directly_connected_logint(struct in_addr in,struct phyint * opi)1629 find_directly_connected_logint(struct in_addr in, struct phyint *opi)
1630 {
1631 struct phyint *pi;
1632 struct logint *li;
1633
1634 if (opi == NULL)
1635 pi = phyint;
1636 else
1637 pi = opi;
1638
1639 for (; pi != NULL; pi = pi->pi_next) {
1640 for (li = pi->pi_logical_first; li != NULL; li = li->li_next) {
1641 if (li->li_state & ST_DELETED)
1642 continue;
1643
1644 /* Check that the subnetwork numbers match */
1645 if ((in.s_addr & li->li_netmask.s_addr) ==
1646 (li->li_remoteaddr.s_addr &
1647 li->li_netmask.s_addr))
1648 return (li);
1649 }
1650 if (opi != NULL)
1651 break;
1652 }
1653 return (NULL);
1654 }
1655
1656 /*
1657 * INTERFACES - physical and logical identified by name
1658 */
1659
1660
1661 static void
report_interfaces(void)1662 report_interfaces(void)
1663 {
1664 struct phyint *pi;
1665 struct logint *li;
1666
1667 logdebug("\nInterfaces:\n\n");
1668 for (pi = phyint; pi != NULL; pi = pi->pi_next) {
1669 logdebug("Phyint %s state 0x%x\n",
1670 pi->pi_name, pi->pi_state);
1671 for (li = pi->pi_logical_first; li != NULL; li = li->li_next) {
1672 logdebug("IF %s state 0x%x, flags 0x%x, addr %s\n",
1673 li->li_name, li->li_state, li->li_flags,
1674 pr_name(li->li_address));
1675 logdebug("\tlocal %s pref 0x%x ",
1676 pr_name(li->li_localaddr), li->li_preference);
1677 logdebug("bcast %s\n",
1678 pr_name(li->li_bcastaddr));
1679 logdebug("\tremote %s ",
1680 pr_name(li->li_remoteaddr));
1681 logdebug("netmask %s\n",
1682 pr_name(li->li_netmask));
1683 }
1684 }
1685 }
1686
1687 static struct phyint *
find_phyint(char * name)1688 find_phyint(char *name)
1689 {
1690 struct phyint *pi;
1691
1692 for (pi = phyint; pi != NULL; pi = pi->pi_next) {
1693 if (strcmp(pi->pi_name, name) == 0)
1694 return (pi);
1695 }
1696 return (NULL);
1697 }
1698
1699 /* Assumes that the entry does not exist - caller must use find_* */
1700 static struct phyint *
add_phyint(char * name)1701 add_phyint(char *name)
1702 {
1703 struct phyint *pi;
1704
1705 pi = malloc(sizeof (*pi));
1706 if (pi == NULL)
1707 return (NULL);
1708 bzero((char *)pi, sizeof (*pi));
1709
1710 strncpy(pi->pi_name, name, sizeof (pi->pi_name));
1711 /* Link into list */
1712 pi->pi_next = phyint;
1713 pi->pi_prev = NULL;
1714 if (phyint != NULL)
1715 phyint->pi_prev = pi;
1716 phyint = pi;
1717 return (pi);
1718 }
1719
1720 static void
free_phyint(struct phyint * pi)1721 free_phyint(struct phyint *pi)
1722 {
1723 assert(pi->pi_logical_first == NULL);
1724 assert(pi->pi_logical_last == NULL);
1725
1726 if (pi->pi_prev == NULL) {
1727 /* Delete first */
1728 assert(phyint == pi);
1729 phyint = pi->pi_next;
1730 } else {
1731 assert(pi->pi_prev->pi_next == pi);
1732 pi->pi_prev->pi_next = pi->pi_next;
1733 }
1734 if (pi->pi_next != NULL) {
1735 assert(pi->pi_next->pi_prev == pi);
1736 pi->pi_next->pi_prev = pi->pi_prev;
1737 }
1738 free(pi);
1739 }
1740
1741 static struct logint *
find_logint(struct phyint * pi,char * name)1742 find_logint(struct phyint *pi, char *name)
1743 {
1744 struct logint *li;
1745
1746 for (li = pi->pi_logical_first; li != NULL; li = li->li_next) {
1747 if (strcmp(li->li_name, name) == 0)
1748 return (li);
1749 }
1750 return (NULL);
1751 }
1752
1753 /*
1754 * Assumes that the entry does not exist - caller must use find_*
1755 * Tail insertion.
1756 */
1757 static struct logint *
add_logint(struct phyint * pi,char * name)1758 add_logint(struct phyint *pi, char *name)
1759 {
1760 struct logint *li;
1761
1762 li = malloc(sizeof (*li));
1763 if (li == NULL)
1764 return (NULL);
1765 bzero((char *)li, sizeof (*li));
1766
1767 strncpy(li->li_name, name, sizeof (li->li_name));
1768 /* Link into list */
1769 li->li_prev = pi->pi_logical_last;
1770 if (pi->pi_logical_last == NULL) {
1771 /* First one */
1772 assert(pi->pi_logical_first == NULL);
1773 pi->pi_logical_first = li;
1774 } else {
1775 pi->pi_logical_last->li_next = li;
1776 }
1777 li->li_next = NULL;
1778 li->li_physical = pi;
1779 pi->pi_logical_last = li;
1780 return (li);
1781
1782 }
1783
1784 static void
free_logint(struct logint * li)1785 free_logint(struct logint *li)
1786 {
1787 struct phyint *pi;
1788
1789 pi = li->li_physical;
1790 if (li->li_prev == NULL) {
1791 /* Delete first */
1792 assert(pi->pi_logical_first == li);
1793 pi->pi_logical_first = li->li_next;
1794 } else {
1795 assert(li->li_prev->li_next == li);
1796 li->li_prev->li_next = li->li_next;
1797 }
1798 if (li->li_next == NULL) {
1799 /* Delete last */
1800 assert(pi->pi_logical_last == li);
1801 pi->pi_logical_last = li->li_prev;
1802 } else {
1803 assert(li->li_next->li_prev == li);
1804 li->li_next->li_prev = li->li_prev;
1805 }
1806 free(li);
1807 }
1808
1809
1810 /* Tell all the logical interfaces that they are going away */
1811 static void
deleted_phyint(struct phyint * pi,int s,struct sockaddr_in * joinaddr)1812 deleted_phyint(struct phyint *pi, int s,
1813 struct sockaddr_in *joinaddr)
1814 {
1815 struct logint *li;
1816
1817 if (debug)
1818 logdebug("Deleting physical interface %s\n", pi->pi_name);
1819
1820 for (li = pi->pi_logical_first; li != NULL; li = li->li_next) {
1821 li->li_state |= ST_DELETED;
1822 }
1823 for (li = pi->pi_logical_first; li != NULL; li = li->li_next) {
1824 deleted_logint(li, NULL, s, joinaddr);
1825 }
1826 }
1827
1828 /*
1829 * Join the multicast address if no other logical interface has done
1830 * so for this physical interface.
1831 */
1832 static void
added_logint(struct logint * li,int s,struct sockaddr_in * joinaddr)1833 added_logint(struct logint *li, int s,
1834 struct sockaddr_in *joinaddr)
1835 {
1836 if (debug)
1837 logdebug("Adding logical interface %s\n", li->li_name);
1838
1839 if ((!(li->li_physical->pi_state & ST_JOINED)) &&
1840 (!isbroadcast(joinaddr))) {
1841 struct ip_mreq mreq;
1842
1843 mreq.imr_multiaddr = joinaddr->sin_addr;
1844 mreq.imr_interface = li->li_address;
1845
1846 if (debug)
1847 logdebug("Joining MC on interface %s\n", li->li_name);
1848
1849 if (setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP,
1850 (char *)&mreq, sizeof (mreq)) < 0) {
1851 logperror("setsockopt (IP_ADD_MEMBERSHIP)");
1852 } else {
1853 li->li_physical->pi_state |= ST_JOINED;
1854 li->li_state |= ST_JOINED;
1855 }
1856 }
1857 }
1858
1859 /*
1860 * Leave the multicast address if this logical interface joined it.
1861 * Look for a replacement logical interface for the same physical interface.
1862 * Remove any routes which are no longer reachable.
1863 *
1864 * If newli is non-NULL, then it is likely that the address of a logical
1865 * interface has changed. In this case, the membership should be dropped using
1866 * the new address of the interface in question.
1867 *
1868 * XXX When a physical interface is being deleted by deleted_phyint(), this
1869 * routine will be called for each logical interface associated with the
1870 * physical one. This should be made more efficient as there is no point in
1871 * searching for an alternate logical interface to add group membership to as
1872 * they all are marked ST_DELETED.
1873 */
1874 static void
deleted_logint(struct logint * li,struct logint * newli,int s,struct sockaddr_in * joinaddr)1875 deleted_logint(struct logint *li, struct logint *newli, int s,
1876 struct sockaddr_in *joinaddr)
1877 {
1878 struct phyint *pi;
1879 struct logint *oli;
1880
1881 if (debug)
1882 logdebug("Deleting logical interface %s\n", li->li_name);
1883
1884 assert(li->li_state & ST_DELETED);
1885
1886 if (li->li_state & ST_JOINED) {
1887 struct ip_mreq mreq;
1888
1889 pi = li->li_physical;
1890 assert(pi->pi_state & ST_JOINED);
1891 assert(!isbroadcast(joinaddr));
1892
1893 mreq.imr_multiaddr = joinaddr->sin_addr;
1894 if (newli != NULL)
1895 mreq.imr_interface = newli->li_address;
1896 else
1897 mreq.imr_interface = li->li_address;
1898
1899 if (debug)
1900 logdebug("Leaving MC on interface %s\n", li->li_name);
1901
1902 if (setsockopt(s, IPPROTO_IP, IP_DROP_MEMBERSHIP,
1903 (char *)&mreq, sizeof (mreq)) < 0) {
1904 /*
1905 * EADDRNOTAVAIL will be returned if the interface has
1906 * been unplumbed or if the interface no longer has
1907 * IFF_MULTICAST set. The former is the common case
1908 * while the latter is rare so don't log the error
1909 * unless some other error was returned or if debug is
1910 * set.
1911 */
1912 if (errno != EADDRNOTAVAIL) {
1913 logperror("setsockopt (IP_DROP_MEMBERSHIP)");
1914 } else if (debug) {
1915 logdebug("%s: %s\n",
1916 "setsockopt (IP_DROP_MEMBERSHIP)",
1917 strerror(errno));
1918 }
1919 }
1920 li->li_physical->pi_state &= ~ST_JOINED;
1921 li->li_state &= ~ST_JOINED;
1922
1923 /* Is there another interface that can join? */
1924 for (oli = pi->pi_logical_first; oli != NULL;
1925 oli = oli->li_next) {
1926 if (oli->li_state & ST_DELETED)
1927 continue;
1928
1929 mreq.imr_multiaddr = joinaddr->sin_addr;
1930 mreq.imr_interface = oli->li_address;
1931
1932 if (debug)
1933 logdebug("Joining MC on interface %s\n",
1934 oli->li_name);
1935
1936 if (setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP,
1937 (char *)&mreq, sizeof (mreq)) < 0) {
1938 logperror("setsockopt (IP_ADD_MEMBERSHIP)");
1939 } else {
1940 pi->pi_state |= ST_JOINED;
1941 oli->li_state |= ST_JOINED;
1942 break;
1943 }
1944 }
1945 }
1946
1947 flush_unreachable_routers();
1948 }
1949
1950
1951
1952 /*
1953 * TABLES
1954 */
1955 struct table {
1956 struct in_addr router;
1957 int preference;
1958 int remaining_time;
1959 int in_kernel;
1960 struct table *next;
1961 };
1962
1963 struct table *table;
1964
1965 static void
report_routes(void)1966 report_routes(void)
1967 {
1968 struct table *tp;
1969
1970 logdebug("\nRoutes:\n\n");
1971 tp = table;
1972 while (tp) {
1973 logdebug("Router %s, pref 0x%x, time %d, %s kernel\n",
1974 pr_name(tp->router), tp->preference,
1975 tp->remaining_time,
1976 (tp->in_kernel ? "in" : "not in"));
1977 tp = tp->next;
1978 }
1979 }
1980
1981 static struct table *
find_router(struct in_addr addr)1982 find_router(struct in_addr addr)
1983 {
1984 struct table *tp;
1985
1986 tp = table;
1987 while (tp) {
1988 if (tp->router.s_addr == addr.s_addr)
1989 return (tp);
1990 tp = tp->next;
1991 }
1992 return (NULL);
1993 }
1994
1995 static int
max_preference(void)1996 max_preference(void)
1997 {
1998 struct table *tp;
1999 int max = (int)IGNORE_PREFERENCE;
2000
2001 tp = table;
2002 while (tp) {
2003 if (tp->preference > max)
2004 max = tp->preference;
2005 tp = tp->next;
2006 }
2007 return (max);
2008 }
2009
2010
2011 /* Note: this might leave the kernel with no default route for a short time. */
2012 static void
age_table(int time)2013 age_table(int time)
2014 {
2015 struct table **tpp, *tp;
2016 int recalculate_max = 0;
2017 int max = max_preference();
2018
2019 tpp = &table;
2020 while (*tpp != NULL) {
2021 tp = *tpp;
2022 tp->remaining_time -= time;
2023 if (tp->remaining_time <= 0) {
2024 *tpp = tp->next;
2025 if (debug) {
2026 logdebug("Timed out router %s\n",
2027 pr_name(tp->router));
2028 }
2029 if (tp->in_kernel)
2030 del_route(tp->router);
2031 if (best_preference &&
2032 tp->preference == max)
2033 recalculate_max++;
2034 free((char *)tp);
2035 } else {
2036 tpp = &tp->next;
2037 }
2038 }
2039 if (recalculate_max) {
2040 int max = max_preference();
2041
2042 if (max != IGNORE_PREFERENCE) {
2043 tp = table;
2044 while (tp) {
2045 if (tp->preference == max && !tp->in_kernel) {
2046 add_route(tp->router);
2047 tp->in_kernel++;
2048 }
2049 tp = tp->next;
2050 }
2051 }
2052 }
2053 }
2054
2055 /*
2056 * Remove any routes which are no longer directly connected.
2057 */
2058 static void
flush_unreachable_routers(void)2059 flush_unreachable_routers(void)
2060 {
2061 struct table **tpp, *tp;
2062 int recalculate_max = 0;
2063 int max = max_preference();
2064
2065 tpp = &table;
2066 while (*tpp != NULL) {
2067 tp = *tpp;
2068 if (find_directly_connected_logint(tp->router, NULL) == NULL) {
2069 *tpp = tp->next;
2070 if (debug) {
2071 logdebug("Unreachable router %s\n",
2072 pr_name(tp->router));
2073 }
2074 if (tp->in_kernel)
2075 del_route(tp->router);
2076 if (best_preference &&
2077 tp->preference == max)
2078 recalculate_max++;
2079 free((char *)tp);
2080 } else {
2081 tpp = &tp->next;
2082 }
2083 }
2084 if (recalculate_max) {
2085 int max = max_preference();
2086
2087 if (max != IGNORE_PREFERENCE) {
2088 tp = table;
2089 while (tp) {
2090 if (tp->preference == max && !tp->in_kernel) {
2091 add_route(tp->router);
2092 tp->in_kernel++;
2093 }
2094 tp = tp->next;
2095 }
2096 }
2097 }
2098 }
2099
2100 static void
record_router(struct in_addr router,long preference,int ttl)2101 record_router(struct in_addr router, long preference, int ttl)
2102 {
2103 struct table *tp;
2104 int old_max = max_preference();
2105 int changed_up = 0; /* max preference could have increased */
2106 int changed_down = 0; /* max preference could have decreased */
2107
2108 if (debug)
2109 logdebug("Recording %s, preference 0x%x\n",
2110 pr_name(router),
2111 preference);
2112 tp = find_router(router);
2113 if (tp) {
2114 if (tp->preference > preference &&
2115 tp->preference == old_max)
2116 changed_down++;
2117 else if (preference > tp->preference)
2118 changed_up++;
2119 tp->preference = preference;
2120 tp->remaining_time = ttl;
2121 } else {
2122 if (preference > old_max)
2123 changed_up++;
2124 tp = (struct table *)ALIGN(malloc(sizeof (struct table)));
2125 if (tp == NULL) {
2126 logerr("Out of memory\n");
2127 return;
2128 }
2129 tp->router = router;
2130 tp->preference = preference;
2131 tp->remaining_time = ttl;
2132 tp->in_kernel = 0;
2133 tp->next = table;
2134 table = tp;
2135 }
2136 if (!tp->in_kernel &&
2137 (!best_preference || tp->preference == max_preference()) &&
2138 tp->preference != IGNORE_PREFERENCE) {
2139 add_route(tp->router);
2140 tp->in_kernel++;
2141 }
2142 if (tp->preference == IGNORE_PREFERENCE && tp->in_kernel) {
2143 del_route(tp->router);
2144 tp->in_kernel = 0;
2145 }
2146 if (best_preference && changed_down) {
2147 /* Check if we should add routes */
2148 int new_max = max_preference();
2149 if (new_max != IGNORE_PREFERENCE) {
2150 tp = table;
2151 while (tp) {
2152 if (tp->preference == new_max &&
2153 !tp->in_kernel) {
2154 add_route(tp->router);
2155 tp->in_kernel++;
2156 }
2157 tp = tp->next;
2158 }
2159 }
2160 }
2161 if (best_preference && (changed_up || changed_down)) {
2162 /* Check if we should remove routes already in the kernel */
2163 int new_max = max_preference();
2164 tp = table;
2165 while (tp) {
2166 if (tp->preference < new_max && tp->in_kernel) {
2167 del_route(tp->router);
2168 tp->in_kernel = 0;
2169 }
2170 tp = tp->next;
2171 }
2172 }
2173 }
2174
2175
2176 #include <net/route.h>
2177
2178 static void
add_route(struct in_addr addr)2179 add_route(struct in_addr addr)
2180 {
2181 if (debug)
2182 logdebug("Add default route to %s\n", pr_name(addr));
2183 rtioctl(addr, SIOCADDRT);
2184 }
2185
2186 static void
del_route(struct in_addr addr)2187 del_route(struct in_addr addr)
2188 {
2189 if (debug)
2190 logdebug("Delete default route to %s\n", pr_name(addr));
2191 rtioctl(addr, SIOCDELRT);
2192 }
2193
2194 static void
rtioctl(struct in_addr addr,int op)2195 rtioctl(struct in_addr addr, int op)
2196 {
2197 int sock;
2198 struct rtentry rt;
2199 struct sockaddr_in *sin;
2200 bzero((char *)&rt, sizeof (struct rtentry));
2201 rt.rt_dst.sa_family = AF_INET;
2202 rt.rt_gateway.sa_family = AF_INET;
2203 sin = (struct sockaddr_in *)ALIGN(&rt.rt_gateway);
2204 sin->sin_addr = addr;
2205 rt.rt_flags = RTF_UP | RTF_GATEWAY;
2206
2207 sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
2208 if (sock < 0) {
2209 logperror("rtioctl: socket");
2210 return;
2211 }
2212 if (ioctl(sock, op, (char *)&rt) < 0) {
2213 if (!(op == SIOCADDRT && errno == EEXIST))
2214 logperror("ioctl (add/delete route)");
2215 }
2216 (void) close(sock);
2217 }
2218
2219
2220
2221 /*
2222 * LOGGER
2223 */
2224
2225 #include <syslog.h>
2226
2227 static int logging = 0;
2228
2229 static void
initlog(void)2230 initlog(void)
2231 {
2232 logging++;
2233 openlog("in.rdisc", LOG_PID | LOG_CONS, LOG_DAEMON);
2234 }
2235
2236 static void
logimpl(int pri,char * fmt,va_list ap)2237 logimpl(int pri, char *fmt, va_list ap)
2238 {
2239 FILE *log;
2240
2241 if (pri == LOG_ERR)
2242 log = stderr;
2243 else
2244 log = stdout;
2245
2246 if (logging)
2247 vsyslog(pri, fmt, ap);
2248 else
2249 (void) vfprintf(log, fmt, ap);
2250 }
2251
2252 static void
logerr(char * fmt,...)2253 logerr(char *fmt, ...)
2254 {
2255 va_list ap;
2256
2257 va_start(ap, fmt);
2258 logimpl(LOG_ERR, fmt, ap);
2259 va_end(ap);
2260 }
2261
2262 static void
logtrace(char * fmt,...)2263 logtrace(char *fmt, ...)
2264 {
2265 va_list ap;
2266
2267 va_start(ap, fmt);
2268 logimpl(LOG_INFO, fmt, ap);
2269 va_end(ap);
2270 }
2271
2272 static void
logdebug(char * fmt,...)2273 logdebug(char *fmt, ...)
2274 {
2275 va_list ap;
2276
2277 va_start(ap, fmt);
2278 logimpl(LOG_DEBUG, fmt, ap);
2279 va_end(ap);
2280 }
2281
2282 static void
logperror(char * str)2283 logperror(char *str)
2284 {
2285 if (logging)
2286 syslog(LOG_ERR, "%s: %s\n", str, strerror(errno));
2287 else
2288 (void) fprintf(stderr, "%s: %s\n", str, strerror(errno));
2289 }
2290