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