1 /* $KAME: rtsold.c,v 1.67 2003/05/17 18:16:15 itojun Exp $ */ 2 3 /* 4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the project nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 * 31 * $FreeBSD$ 32 */ 33 34 #include <sys/types.h> 35 #include <sys/time.h> 36 #include <sys/socket.h> 37 #include <sys/param.h> 38 39 #include <net/if.h> 40 #include <net/if_dl.h> 41 42 #include <netinet/in.h> 43 #include <netinet/icmp6.h> 44 45 #include <signal.h> 46 #include <unistd.h> 47 #include <syslog.h> 48 #include <string.h> 49 #include <stdlib.h> 50 #include <stdio.h> 51 #include <errno.h> 52 #include <err.h> 53 #include <stdarg.h> 54 #include <ifaddrs.h> 55 #ifdef HAVE_POLL_H 56 #include <poll.h> 57 #endif 58 59 #include "rtsold.h" 60 61 struct ifinfo *iflist; 62 struct timeval tm_max = {0x7fffffff, 0x7fffffff}; 63 static int log_upto = 999; 64 static int fflag = 0; 65 66 int Fflag = 0; /* force setting sysctl parameters */ 67 int aflag = 0; 68 int dflag = 0; 69 70 char *otherconf_script; 71 72 /* protocol constants */ 73 #define MAX_RTR_SOLICITATION_DELAY 1 /* second */ 74 #define RTR_SOLICITATION_INTERVAL 4 /* seconds */ 75 #define MAX_RTR_SOLICITATIONS 3 /* times */ 76 77 /* 78 * implementation dependent constants in seconds 79 * XXX: should be configurable 80 */ 81 #define PROBE_INTERVAL 60 82 83 int main(int, char **); 84 85 /* static variables and functions */ 86 static int mobile_node = 0; 87 #ifndef SMALL 88 static int do_dump; 89 static char *dumpfilename = "/var/run/rtsold.dump"; /* XXX: should be configurable */ 90 #endif 91 #if 1 92 static char *pidfilename = "/var/run/rtsold.pid"; /* should be configurable */ 93 #endif 94 95 #if 0 96 static int ifreconfig(char *); 97 #endif 98 static int make_packet(struct ifinfo *); 99 static struct timeval *rtsol_check_timer(void); 100 101 #ifndef SMALL 102 static void rtsold_set_dump_file(int); 103 #endif 104 static void usage(char *); 105 106 int 107 main(int argc, char **argv) 108 { 109 int s, ch, once = 0; 110 struct timeval *timeout; 111 char *argv0, *opts; 112 #ifdef HAVE_POLL_H 113 struct pollfd set[2]; 114 #else 115 fd_set *fdsetp, *selectfdp; 116 int fdmasks; 117 int maxfd; 118 #endif 119 int rtsock; 120 121 /* 122 * Initialization 123 */ 124 argv0 = argv[0]; 125 126 /* get option */ 127 if (argv0 && argv0[strlen(argv0) - 1] != 'd') { 128 fflag = 1; 129 once = 1; 130 opts = "adDFO:"; 131 } else 132 opts = "adDfFm1O:"; 133 134 while ((ch = getopt(argc, argv, opts)) != -1) { 135 switch (ch) { 136 case 'a': 137 aflag = 1; 138 break; 139 case 'd': 140 dflag = 1; 141 break; 142 case 'D': 143 dflag = 2; 144 break; 145 case 'f': 146 fflag = 1; 147 break; 148 case 'F': 149 Fflag = 1; 150 break; 151 case 'm': 152 mobile_node = 1; 153 break; 154 case '1': 155 once = 1; 156 break; 157 case 'O': 158 otherconf_script = optarg; 159 break; 160 default: 161 usage(argv0); 162 /*NOTREACHED*/ 163 } 164 } 165 argc -= optind; 166 argv += optind; 167 168 if ((!aflag && argc == 0) || (aflag && argc != 0)) { 169 usage(argv0); 170 /*NOTREACHED*/ 171 } 172 173 /* set log level */ 174 if (dflag == 0) 175 log_upto = LOG_NOTICE; 176 if (!fflag) { 177 char *ident; 178 179 ident = strrchr(argv0, '/'); 180 if (!ident) 181 ident = argv0; 182 else 183 ident++; 184 openlog(ident, LOG_NDELAY|LOG_PID, LOG_DAEMON); 185 if (log_upto >= 0) 186 setlogmask(LOG_UPTO(log_upto)); 187 } 188 189 if (otherconf_script && *otherconf_script != '/') { 190 errx(1, "configuration script (%s) must be an absolute path", 191 otherconf_script); 192 } 193 194 #ifndef HAVE_ARC4RANDOM 195 /* random value initialization */ 196 srandom((u_long)time(NULL)); 197 #endif 198 199 if (Fflag) { 200 setinet6sysctl(IPV6CTL_FORWARDING, 0); 201 } else { 202 /* warn if forwarding is up */ 203 if (getinet6sysctl(IPV6CTL_FORWARDING)) 204 warnx("kernel is configured as a router, not a host"); 205 } 206 207 #ifndef SMALL 208 /* initialization to dump internal status to a file */ 209 signal(SIGUSR1, rtsold_set_dump_file); 210 #endif 211 212 if (!fflag) 213 daemon(0, 0); /* act as a daemon */ 214 215 /* 216 * Open a socket for sending RS and receiving RA. 217 * This should be done before calling ifinit(), since the function 218 * uses the socket. 219 */ 220 if ((s = sockopen()) < 0) { 221 warnmsg(LOG_ERR, __func__, "failed to open a socket"); 222 exit(1); 223 /*NOTREACHED*/ 224 } 225 #ifdef HAVE_POLL_H 226 set[0].fd = s; 227 set[0].events = POLLIN; 228 #else 229 maxfd = s; 230 #endif 231 232 #ifdef HAVE_POLL_H 233 set[1].fd = -1; 234 #endif 235 236 if ((rtsock = rtsock_open()) < 0) { 237 warnmsg(LOG_ERR, __func__, "failed to open a socket"); 238 exit(1); 239 /*NOTREACHED*/ 240 } 241 #ifdef HAVE_POLL_H 242 set[1].fd = rtsock; 243 set[1].events = POLLIN; 244 #else 245 if (rtsock > maxfd) 246 maxfd = rtsock; 247 #endif 248 249 #ifndef HAVE_POLL_H 250 fdmasks = howmany(maxfd + 1, NFDBITS) * sizeof(fd_mask); 251 if ((fdsetp = malloc(fdmasks)) == NULL) { 252 err(1, "malloc"); 253 /*NOTREACHED*/ 254 } 255 if ((selectfdp = malloc(fdmasks)) == NULL) { 256 err(1, "malloc"); 257 /*NOTREACHED*/ 258 } 259 #endif 260 261 /* configuration per interface */ 262 if (ifinit()) { 263 warnmsg(LOG_ERR, __func__, 264 "failed to initialize interfaces"); 265 exit(1); 266 /*NOTREACHED*/ 267 } 268 if (aflag) 269 argv = autoifprobe(); 270 while (argv && *argv) { 271 if (ifconfig(*argv)) { 272 warnmsg(LOG_ERR, __func__, 273 "failed to initialize %s", *argv); 274 exit(1); 275 /*NOTREACHED*/ 276 } 277 argv++; 278 } 279 280 /* setup for probing default routers */ 281 if (probe_init()) { 282 warnmsg(LOG_ERR, __func__, 283 "failed to setup for probing routers"); 284 exit(1); 285 /*NOTREACHED*/ 286 } 287 288 #if 1 289 /* dump the current pid */ 290 if (!once) { 291 pid_t pid = getpid(); 292 FILE *fp; 293 294 if ((fp = fopen(pidfilename, "w")) == NULL) 295 warnmsg(LOG_ERR, __func__, 296 "failed to open a pid log file(%s): %s", 297 pidfilename, strerror(errno)); 298 else { 299 fprintf(fp, "%d\n", pid); 300 fclose(fp); 301 } 302 } 303 #endif 304 305 #ifndef HAVE_POLL_H 306 memset(fdsetp, 0, fdmasks); 307 FD_SET(s, fdsetp); 308 FD_SET(rtsock, fdsetp); 309 #endif 310 while (1) { /* main loop */ 311 int e; 312 313 #ifndef HAVE_POLL_H 314 memcpy(selectfdp, fdsetp, fdmasks); 315 #endif 316 317 #ifndef SMALL 318 if (do_dump) { /* SIGUSR1 */ 319 do_dump = 0; 320 rtsold_dump_file(dumpfilename); 321 } 322 #endif 323 324 timeout = rtsol_check_timer(); 325 326 if (once) { 327 struct ifinfo *ifi; 328 329 /* if we have no timeout, we are done (or failed) */ 330 if (timeout == NULL) 331 break; 332 333 /* if all interfaces have got RA packet, we are done */ 334 for (ifi = iflist; ifi; ifi = ifi->next) { 335 if (ifi->state != IFS_DOWN && ifi->racnt == 0) 336 break; 337 } 338 if (ifi == NULL) 339 break; 340 } 341 #ifdef HAVE_POLL_H 342 e = poll(set, 2, timeout ? (timeout->tv_sec * 1000 + timeout->tv_usec / 1000) : INFTIM); 343 #else 344 e = select(maxfd + 1, selectfdp, NULL, NULL, timeout); 345 #endif 346 if (e < 1) { 347 if (e < 0 && errno != EINTR) { 348 warnmsg(LOG_ERR, __func__, "select: %s", 349 strerror(errno)); 350 } 351 continue; 352 } 353 354 /* packet reception */ 355 #ifdef HAVE_POLL_H 356 if (set[1].revents & POLLIN) 357 #else 358 if (FD_ISSET(rtsock, selectfdp)) 359 #endif 360 rtsock_input(rtsock); 361 #ifdef HAVE_POLL_H 362 if (set[0].revents & POLLIN) 363 #else 364 if (FD_ISSET(s, selectfdp)) 365 #endif 366 rtsol_input(s); 367 } 368 /* NOTREACHED */ 369 370 return 0; 371 } 372 373 int 374 ifconfig(char *ifname) 375 { 376 struct ifinfo *ifinfo; 377 struct sockaddr_dl *sdl; 378 int flags; 379 380 if ((sdl = if_nametosdl(ifname)) == NULL) { 381 warnmsg(LOG_ERR, __func__, 382 "failed to get link layer information for %s", ifname); 383 return(-1); 384 } 385 if (find_ifinfo(sdl->sdl_index)) { 386 warnmsg(LOG_ERR, __func__, 387 "interface %s was already configured", ifname); 388 free(sdl); 389 return(-1); 390 } 391 392 if ((ifinfo = malloc(sizeof(*ifinfo))) == NULL) { 393 warnmsg(LOG_ERR, __func__, "memory allocation failed"); 394 free(sdl); 395 return(-1); 396 } 397 memset(ifinfo, 0, sizeof(*ifinfo)); 398 ifinfo->sdl = sdl; 399 400 strlcpy(ifinfo->ifname, ifname, sizeof(ifinfo->ifname)); 401 402 /* construct a router solicitation message */ 403 if (make_packet(ifinfo)) 404 goto bad; 405 406 /* set link ID of this interface. */ 407 #ifdef HAVE_SCOPELIB 408 if (inet_zoneid(AF_INET6, 2, ifname, &ifinfo->linkid)) 409 goto bad; 410 #else 411 /* XXX: assume interface IDs as link IDs */ 412 ifinfo->linkid = ifinfo->sdl->sdl_index; 413 #endif 414 415 /* 416 * check if the interface is available. 417 * also check if SIOCGIFMEDIA ioctl is OK on the interface. 418 */ 419 ifinfo->mediareqok = 1; 420 ifinfo->active = interface_status(ifinfo); 421 if (!ifinfo->mediareqok) { 422 /* 423 * probe routers periodically even if the link status 424 * does not change. 425 */ 426 ifinfo->probeinterval = PROBE_INTERVAL; 427 } 428 429 /* activate interface: interface_up returns 0 on success */ 430 flags = interface_up(ifinfo->ifname); 431 if (flags == 0) 432 ifinfo->state = IFS_DELAY; 433 else if (flags == IFS_TENTATIVE) 434 ifinfo->state = IFS_TENTATIVE; 435 else 436 ifinfo->state = IFS_DOWN; 437 438 rtsol_timer_update(ifinfo); 439 440 /* link into chain */ 441 if (iflist) 442 ifinfo->next = iflist; 443 iflist = ifinfo; 444 445 return(0); 446 447 bad: 448 free(ifinfo->sdl); 449 free(ifinfo); 450 return(-1); 451 } 452 453 void 454 iflist_init(void) 455 { 456 struct ifinfo *ifi, *next; 457 458 for (ifi = iflist; ifi; ifi = next) { 459 next = ifi->next; 460 if (ifi->sdl) 461 free(ifi->sdl); 462 if (ifi->rs_data) 463 free(ifi->rs_data); 464 free(ifi); 465 iflist = NULL; 466 } 467 } 468 469 #if 0 470 static int 471 ifreconfig(char *ifname) 472 { 473 struct ifinfo *ifi, *prev; 474 int rv; 475 476 prev = NULL; 477 for (ifi = iflist; ifi; ifi = ifi->next) { 478 if (strncmp(ifi->ifname, ifname, sizeof(ifi->ifname)) == 0) 479 break; 480 prev = ifi; 481 } 482 prev->next = ifi->next; 483 484 rv = ifconfig(ifname); 485 486 /* reclaim it after ifconfig() in case ifname is pointer inside ifi */ 487 if (ifi->rs_data) 488 free(ifi->rs_data); 489 free(ifi->sdl); 490 free(ifi); 491 return rv; 492 } 493 #endif 494 495 struct ifinfo * 496 find_ifinfo(int ifindex) 497 { 498 struct ifinfo *ifi; 499 500 for (ifi = iflist; ifi; ifi = ifi->next) 501 if (ifi->sdl->sdl_index == ifindex) 502 return(ifi); 503 return(NULL); 504 } 505 506 static int 507 make_packet(struct ifinfo *ifinfo) 508 { 509 size_t packlen = sizeof(struct nd_router_solicit), lladdroptlen = 0; 510 struct nd_router_solicit *rs; 511 char *buf; 512 513 if ((lladdroptlen = lladdropt_length(ifinfo->sdl)) == 0) { 514 warnmsg(LOG_INFO, __func__, 515 "link-layer address option has null length" 516 " on %s. Treat as not included.", ifinfo->ifname); 517 } 518 packlen += lladdroptlen; 519 ifinfo->rs_datalen = packlen; 520 521 /* allocate buffer */ 522 if ((buf = malloc(packlen)) == NULL) { 523 warnmsg(LOG_ERR, __func__, 524 "memory allocation failed for %s", ifinfo->ifname); 525 return(-1); 526 } 527 ifinfo->rs_data = buf; 528 529 /* fill in the message */ 530 rs = (struct nd_router_solicit *)buf; 531 rs->nd_rs_type = ND_ROUTER_SOLICIT; 532 rs->nd_rs_code = 0; 533 rs->nd_rs_cksum = 0; 534 rs->nd_rs_reserved = 0; 535 buf += sizeof(*rs); 536 537 /* fill in source link-layer address option */ 538 if (lladdroptlen) 539 lladdropt_fill(ifinfo->sdl, (struct nd_opt_hdr *)buf); 540 541 return(0); 542 } 543 544 static struct timeval * 545 rtsol_check_timer(void) 546 { 547 static struct timeval returnval; 548 struct timeval now, rtsol_timer; 549 struct ifinfo *ifinfo; 550 int flags; 551 552 gettimeofday(&now, NULL); 553 554 rtsol_timer = tm_max; 555 556 for (ifinfo = iflist; ifinfo; ifinfo = ifinfo->next) { 557 if (timercmp(&ifinfo->expire, &now, <=)) { 558 if (dflag > 1) 559 warnmsg(LOG_DEBUG, __func__, 560 "timer expiration on %s, " 561 "state = %d", ifinfo->ifname, 562 ifinfo->state); 563 564 switch (ifinfo->state) { 565 case IFS_DOWN: 566 case IFS_TENTATIVE: 567 /* interface_up returns 0 on success */ 568 flags = interface_up(ifinfo->ifname); 569 if (flags == 0) 570 ifinfo->state = IFS_DELAY; 571 else if (flags == IFS_TENTATIVE) 572 ifinfo->state = IFS_TENTATIVE; 573 else 574 ifinfo->state = IFS_DOWN; 575 break; 576 case IFS_IDLE: 577 { 578 int oldstatus = ifinfo->active; 579 int probe = 0; 580 581 ifinfo->active = interface_status(ifinfo); 582 583 if (oldstatus != ifinfo->active) { 584 warnmsg(LOG_DEBUG, __func__, 585 "%s status is changed" 586 " from %d to %d", 587 ifinfo->ifname, 588 oldstatus, ifinfo->active); 589 probe = 1; 590 ifinfo->state = IFS_DELAY; 591 } else if (ifinfo->probeinterval && 592 (ifinfo->probetimer -= 593 ifinfo->timer.tv_sec) <= 0) { 594 /* probe timer expired */ 595 ifinfo->probetimer = 596 ifinfo->probeinterval; 597 probe = 1; 598 ifinfo->state = IFS_PROBE; 599 } 600 601 /* 602 * If we need a probe, clear the previous 603 * status wrt the "other" configuration. 604 */ 605 if (probe) 606 ifinfo->otherconfig = 0; 607 608 if (probe && mobile_node) 609 defrouter_probe(ifinfo); 610 break; 611 } 612 case IFS_DELAY: 613 ifinfo->state = IFS_PROBE; 614 sendpacket(ifinfo); 615 break; 616 case IFS_PROBE: 617 if (ifinfo->probes < MAX_RTR_SOLICITATIONS) 618 sendpacket(ifinfo); 619 else { 620 warnmsg(LOG_INFO, __func__, 621 "No answer after sending %d RSs", 622 ifinfo->probes); 623 ifinfo->probes = 0; 624 ifinfo->state = IFS_IDLE; 625 } 626 break; 627 } 628 rtsol_timer_update(ifinfo); 629 } 630 631 if (timercmp(&ifinfo->expire, &rtsol_timer, <)) 632 rtsol_timer = ifinfo->expire; 633 } 634 635 if (timercmp(&rtsol_timer, &tm_max, ==)) { 636 warnmsg(LOG_DEBUG, __func__, "there is no timer"); 637 return(NULL); 638 } else if (timercmp(&rtsol_timer, &now, <)) 639 /* this may occur when the interval is too small */ 640 returnval.tv_sec = returnval.tv_usec = 0; 641 else 642 timersub(&rtsol_timer, &now, &returnval); 643 644 if (dflag > 1) 645 warnmsg(LOG_DEBUG, __func__, "New timer is %ld:%08ld", 646 (long)returnval.tv_sec, (long)returnval.tv_usec); 647 648 return(&returnval); 649 } 650 651 void 652 rtsol_timer_update(struct ifinfo *ifinfo) 653 { 654 #define MILLION 1000000 655 #define DADRETRY 10 /* XXX: adhoc */ 656 long interval; 657 struct timeval now; 658 659 bzero(&ifinfo->timer, sizeof(ifinfo->timer)); 660 661 switch (ifinfo->state) { 662 case IFS_DOWN: 663 case IFS_TENTATIVE: 664 if (++ifinfo->dadcount > DADRETRY) { 665 ifinfo->dadcount = 0; 666 ifinfo->timer.tv_sec = PROBE_INTERVAL; 667 } else 668 ifinfo->timer.tv_sec = 1; 669 break; 670 case IFS_IDLE: 671 if (mobile_node) { 672 /* XXX should be configurable */ 673 ifinfo->timer.tv_sec = 3; 674 } 675 else 676 ifinfo->timer = tm_max; /* stop timer(valid?) */ 677 break; 678 case IFS_DELAY: 679 #ifndef HAVE_ARC4RANDOM 680 interval = random() % (MAX_RTR_SOLICITATION_DELAY * MILLION); 681 #else 682 interval = arc4random_uniform(MAX_RTR_SOLICITATION_DELAY * MILLION); 683 #endif 684 ifinfo->timer.tv_sec = interval / MILLION; 685 ifinfo->timer.tv_usec = interval % MILLION; 686 break; 687 case IFS_PROBE: 688 if (ifinfo->probes < MAX_RTR_SOLICITATIONS) 689 ifinfo->timer.tv_sec = RTR_SOLICITATION_INTERVAL; 690 else { 691 /* 692 * After sending MAX_RTR_SOLICITATIONS solicitations, 693 * we're just waiting for possible replies; there 694 * will be no more solicitation. Thus, we change 695 * the timer value to MAX_RTR_SOLICITATION_DELAY based 696 * on RFC 2461, Section 6.3.7. 697 */ 698 ifinfo->timer.tv_sec = MAX_RTR_SOLICITATION_DELAY; 699 } 700 break; 701 default: 702 warnmsg(LOG_ERR, __func__, 703 "illegal interface state(%d) on %s", 704 ifinfo->state, ifinfo->ifname); 705 return; 706 } 707 708 /* reset the timer */ 709 if (timercmp(&ifinfo->timer, &tm_max, ==)) { 710 ifinfo->expire = tm_max; 711 warnmsg(LOG_DEBUG, __func__, 712 "stop timer for %s", ifinfo->ifname); 713 } else { 714 gettimeofday(&now, NULL); 715 timeradd(&now, &ifinfo->timer, &ifinfo->expire); 716 717 if (dflag > 1) 718 warnmsg(LOG_DEBUG, __func__, 719 "set timer for %s to %d:%d", ifinfo->ifname, 720 (int)ifinfo->timer.tv_sec, 721 (int)ifinfo->timer.tv_usec); 722 } 723 724 #undef MILLION 725 } 726 727 /* timer related utility functions */ 728 #define MILLION 1000000 729 730 #ifndef SMALL 731 static void 732 rtsold_set_dump_file(int sig) 733 { 734 do_dump = 1; 735 } 736 #endif 737 738 static void 739 usage(char *progname) 740 { 741 if (progname && progname[strlen(progname) - 1] != 'd') { 742 fprintf(stderr, "usage: rtsol [-dDF] interfaces...\n"); 743 fprintf(stderr, "usage: rtsol [-dDF] -a\n"); 744 } else { 745 fprintf(stderr, "usage: rtsold [-adDfFm1] interfaces...\n"); 746 fprintf(stderr, "usage: rtsold [-dDfFm1] -a\n"); 747 } 748 exit(1); 749 } 750 751 void 752 #if __STDC__ 753 warnmsg(int priority, const char *func, const char *msg, ...) 754 #else 755 warnmsg(priority, func, msg, va_alist) 756 int priority; 757 const char *func; 758 const char *msg; 759 va_dcl 760 #endif 761 { 762 va_list ap; 763 char buf[BUFSIZ]; 764 765 va_start(ap, msg); 766 if (fflag) { 767 if (priority <= log_upto) { 768 (void)vfprintf(stderr, msg, ap); 769 (void)fprintf(stderr, "\n"); 770 } 771 } else { 772 snprintf(buf, sizeof(buf), "<%s> %s", func, msg); 773 msg = buf; 774 vsyslog(priority, msg, ap); 775 } 776 va_end(ap); 777 } 778 779 /* 780 * return a list of interfaces which is suitable to sending an RS. 781 */ 782 char ** 783 autoifprobe(void) 784 { 785 static char **argv = NULL; 786 static int n = 0; 787 char **a; 788 int i, found; 789 struct ifaddrs *ifap, *ifa, *target; 790 791 /* initialize */ 792 while (n--) 793 free(argv[n]); 794 if (argv) { 795 free(argv); 796 argv = NULL; 797 } 798 n = 0; 799 800 if (getifaddrs(&ifap) != 0) 801 return NULL; 802 803 target = NULL; 804 /* find an ethernet */ 805 for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 806 if ((ifa->ifa_flags & IFF_UP) == 0) 807 continue; 808 if ((ifa->ifa_flags & IFF_POINTOPOINT) != 0) 809 continue; 810 if ((ifa->ifa_flags & IFF_LOOPBACK) != 0) 811 continue; 812 if ((ifa->ifa_flags & IFF_MULTICAST) == 0) 813 continue; 814 815 if (ifa->ifa_addr->sa_family != AF_INET6) 816 continue; 817 818 found = 0; 819 for (i = 0; i < n; i++) { 820 if (strcmp(argv[i], ifa->ifa_name) == 0) { 821 found++; 822 break; 823 } 824 } 825 if (found) 826 continue; 827 828 /* if we find multiple candidates, just warn. */ 829 if (n != 0 && dflag > 1) 830 warnx("multiple interfaces found"); 831 832 a = (char **)realloc(argv, (n + 1) * sizeof(char **)); 833 if (a == NULL) 834 err(1, "realloc"); 835 argv = a; 836 argv[n] = strdup(ifa->ifa_name); 837 if (!argv[n]) 838 err(1, "malloc"); 839 n++; 840 argv[n] = NULL; 841 } 842 843 if (n) { 844 a = (char **)realloc(argv, (n + 1) * sizeof(char **)); 845 if (a == NULL) 846 err(1, "realloc"); 847 argv = a; 848 argv[n] = NULL; 849 850 if (dflag > 0) { 851 for (i = 0; i < n; i++) 852 warnx("probing %s", argv[i]); 853 } 854 } 855 freeifaddrs(ifap); 856 return argv; 857 } 858