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 <stdlib.h> 47 #include <unistd.h> 48 #include <assert.h> 49 50 #ifdef lint 51 #define ALIGN(ptr) (ptr ? 0 : 0) 52 #else 53 #define ALIGN(ptr) (ptr) 54 #endif 55 56 #ifdef SYSV 57 #define signal(s, f) sigset(s, (void (*)(int))f) 58 #define random() rand() 59 #endif 60 61 #define ALL_HOSTS_ADDRESS "224.0.0.1" 62 #define ALL_ROUTERS_ADDRESS "224.0.0.2" 63 64 #define MAXIFS 256 65 66 /* For router advertisement */ 67 struct icmp_ra { 68 uchar_t icmp_type; /* type of message, see below */ 69 uchar_t icmp_code; /* type sub code */ 70 ushort_t icmp_cksum; /* ones complement cksum of struct */ 71 uchar_t icmp_num_addrs; 72 uchar_t icmp_wpa; /* Words per address */ 73 short icmp_lifetime; 74 }; 75 76 struct icmp_ra_addr { 77 ulong_t addr; 78 ulong_t preference; 79 }; 80 81 /* Router constants */ 82 #define MAX_INITIAL_ADVERT_INTERVAL 16 83 #define MAX_INITIAL_ADVERTISEMENTS 3 84 #define MAX_RESPONSE_DELAY 2 /* Not used */ 85 86 /* Host constants */ 87 #define MAX_SOLICITATIONS 3 88 #define SOLICITATION_INTERVAL 3 89 #define MAX_SOLICITATION_DELAY 1 /* Not used */ 90 91 #define IGNORE_PREFERENCE 0x80000000 /* Maximum negative */ 92 93 #define MAX_ADV_INT 600 94 95 96 /* 97 * A doubly linked list of all physical interfaces that each contain a 98 * doubly linked list of logical interfaces aka IP addresses. 99 */ 100 struct phyint { 101 char pi_name[IFNAMSIZ]; /* Used to identify it */ 102 int pi_state; /* See below */ 103 struct logint *pi_logical_first; 104 struct logint *pi_logical_last; 105 struct phyint *pi_next; 106 struct phyint *pi_prev; 107 }; 108 109 struct logint { 110 char li_name[IFNAMSIZ]; /* Used to identify it */ 111 int li_state; /* See below */ 112 struct in_addr li_address; /* Used to identify the interface */ 113 struct in_addr li_localaddr; /* Actual address of the interface */ 114 int li_preference; 115 int li_index; /* interface index (SIOCGLIFINDEX) */ 116 uint64_t li_flags; 117 struct in_addr li_bcastaddr; 118 struct in_addr li_remoteaddr; 119 struct in_addr li_netmask; 120 struct logint *li_next; /* Next logical for this physical */ 121 struct logint *li_prev; /* Prev logical for this physical */ 122 struct phyint *li_physical; /* Back pointer */ 123 }; 124 125 struct phyint *phyint; 126 int num_usable_interfaces; /* Num used for sending/receiving */ 127 128 /* 129 * State bits 130 */ 131 #define ST_MARKED 0x01 /* To determine removed interfaces */ 132 #define ST_JOINED 0x02 /* Joined multicast group */ 133 #define ST_DELETED 0x04 /* Interface should be ignored */ 134 135 /* Function prototypes */ 136 static void solicitor(struct sockaddr_in *sin); 137 static void advertise(struct sockaddr_in *sin); 138 139 static void age_table(int time); 140 static void flush_unreachable_routers(void); 141 static void record_router(struct in_addr router, long preference, int ttl); 142 143 static void add_route(struct in_addr addr); 144 static void del_route(struct in_addr addr); 145 static void rtioctl(struct in_addr addr, int op); 146 147 static int support_multicast(void); 148 static int sendbcast(int s, char *packet, int packetlen); 149 static int sendbcastif(int s, char *packet, int packetlen, 150 struct logint *li); 151 static int sendmcast(int s, char *packet, int packetlen, 152 struct sockaddr_in *sin); 153 static int sendmcastif(int s, char *packet, int packetlen, 154 struct sockaddr_in *sin, struct logint *li); 155 156 static int ismulticast(struct sockaddr_in *sin); 157 static int isbroadcast(struct sockaddr_in *sin); 158 int in_cksum(ushort_t *addr, int len); 159 static struct logint *find_directly_connected_logint(struct in_addr in, 160 struct phyint *pi); 161 static void force_preference(int preference); 162 163 static void timer(void); 164 static void finish(void); 165 static void report(void); 166 static void report_interfaces(void); 167 static void report_routes(void); 168 static void reinitifs(void); 169 170 static struct phyint *find_phyint(char *name); 171 static struct phyint *add_phyint(char *name); 172 static void free_phyint(struct phyint *pi); 173 static struct logint *find_logint(struct phyint *pi, char *name); 174 static struct logint *add_logint(struct phyint *pi, char *name); 175 static void free_logint(struct logint *li); 176 177 static void deleted_phyint(struct phyint *pi, int s, 178 struct sockaddr_in *joinaddr); 179 static void added_logint(struct logint *li, int s, 180 struct sockaddr_in *joinaddr); 181 static void deleted_logint(struct logint *li, struct logint *newli, int s, 182 struct sockaddr_in *joinaddr); 183 184 static int initifs(int s, struct sockaddr_in *joinaddr, int preference); 185 static boolean_t getconfig(int sock, uint64_t if_flags, struct sockaddr *addr, 186 struct ifreq *ifr, struct logint *li); 187 188 static void pr_pack(char *buf, int cc, struct sockaddr_in *from); 189 char *pr_name(struct in_addr addr); 190 char *pr_type(int t); 191 192 static void initlog(void); 193 void logerr(), logtrace(), logdebug(), logperror(); 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 240 prusage() 241 { 242 (void) fprintf(stderr, usage); 243 exit(1); 244 } 245 246 static int sock = -1; 247 248 static void 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 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 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 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 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 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 * 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 * 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 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 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 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 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 1111 isbroadcast(struct sockaddr_in *sin) 1112 { 1113 return (sin->sin_addr.s_addr == htonl(INADDR_BROADCAST)); 1114 } 1115 1116 static int 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 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 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 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 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 1274 reinitifs(void) 1275 { 1276 (void) initifs(s, &g_joinaddr, g_preference); 1277 } 1278 1279 static void 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 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 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 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 * 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 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 * 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 * 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 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 * 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 * 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 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 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 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 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 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 * 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 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 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 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 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 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 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 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 2230 initlog(void) 2231 { 2232 logging++; 2233 openlog("in.rdisc", LOG_PID | LOG_CONS, LOG_DAEMON); 2234 } 2235 2236 /* VARARGS1 */ 2237 void 2238 logerr(fmt, a, b, c, d, e, f, g, h) 2239 char *fmt; 2240 { 2241 if (logging) 2242 syslog(LOG_ERR, fmt, a, b, c, d, e, f, g, h); 2243 else 2244 (void) fprintf(stderr, fmt, a, b, c, d, e, f, g, h); 2245 } 2246 2247 /* VARARGS1 */ 2248 void 2249 logtrace(fmt, a, b, c, d, e, f, g, h) 2250 char *fmt; 2251 { 2252 if (logging) 2253 syslog(LOG_INFO, fmt, a, b, c, d, e, f, g, h); 2254 else 2255 (void) fprintf(stdout, fmt, a, b, c, d, e, f, g, h); 2256 } 2257 2258 /* VARARGS1 */ 2259 void 2260 logdebug(fmt, a, b, c, d, e, f, g, h) 2261 char *fmt; 2262 { 2263 if (logging) 2264 syslog(LOG_DEBUG, fmt, a, b, c, d, e, f, g, h); 2265 else 2266 (void) fprintf(stdout, fmt, a, b, c, d, e, f, g, h); 2267 } 2268 2269 void 2270 logperror(str) 2271 char *str; 2272 { 2273 if (logging) 2274 syslog(LOG_ERR, "%s: %s\n", str, strerror(errno)); 2275 else 2276 (void) fprintf(stderr, "%s: %s\n", str, strerror(errno)); 2277 } 2278