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 static int Fflag = 0; /* force setting sysctl parameters */ 66 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_ACCEPT_RTADV, 1); 201 setinet6sysctl(IPV6CTL_FORWARDING, 0); 202 } else { 203 /* warn if accept_rtadv is down */ 204 if (!getinet6sysctl(IPV6CTL_ACCEPT_RTADV)) 205 warnx("kernel is configured not to accept RAs"); 206 /* warn if forwarding is up */ 207 if (getinet6sysctl(IPV6CTL_FORWARDING)) 208 warnx("kernel is configured as a router, not a host"); 209 } 210 211 #ifndef SMALL 212 /* initialization to dump internal status to a file */ 213 signal(SIGUSR1, rtsold_set_dump_file); 214 #endif 215 216 if (!fflag) 217 daemon(0, 0); /* act as a daemon */ 218 219 /* 220 * Open a socket for sending RS and receiving RA. 221 * This should be done before calling ifinit(), since the function 222 * uses the socket. 223 */ 224 if ((s = sockopen()) < 0) { 225 warnmsg(LOG_ERR, __func__, "failed to open a socket"); 226 exit(1); 227 /*NOTREACHED*/ 228 } 229 #ifdef HAVE_POLL_H 230 set[0].fd = s; 231 set[0].events = POLLIN; 232 #else 233 maxfd = s; 234 #endif 235 236 #ifdef HAVE_POLL_H 237 set[1].fd = -1; 238 #endif 239 240 if ((rtsock = rtsock_open()) < 0) { 241 warnmsg(LOG_ERR, __func__, "failed to open a socket"); 242 exit(1); 243 /*NOTREACHED*/ 244 } 245 #ifdef HAVE_POLL_H 246 set[1].fd = rtsock; 247 set[1].events = POLLIN; 248 #else 249 if (rtsock > maxfd) 250 maxfd = rtsock; 251 #endif 252 253 #ifndef HAVE_POLL_H 254 fdmasks = howmany(maxfd + 1, NFDBITS) * sizeof(fd_mask); 255 if ((fdsetp = malloc(fdmasks)) == NULL) { 256 err(1, "malloc"); 257 /*NOTREACHED*/ 258 } 259 if ((selectfdp = malloc(fdmasks)) == NULL) { 260 err(1, "malloc"); 261 /*NOTREACHED*/ 262 } 263 #endif 264 265 /* configuration per interface */ 266 if (ifinit()) { 267 warnmsg(LOG_ERR, __func__, 268 "failed to initialize interfaces"); 269 exit(1); 270 /*NOTREACHED*/ 271 } 272 if (aflag) 273 argv = autoifprobe(); 274 while (argv && *argv) { 275 if (ifconfig(*argv)) { 276 warnmsg(LOG_ERR, __func__, 277 "failed to initialize %s", *argv); 278 exit(1); 279 /*NOTREACHED*/ 280 } 281 argv++; 282 } 283 284 /* setup for probing default routers */ 285 if (probe_init()) { 286 warnmsg(LOG_ERR, __func__, 287 "failed to setup for probing routers"); 288 exit(1); 289 /*NOTREACHED*/ 290 } 291 292 #if 1 293 /* dump the current pid */ 294 if (!once) { 295 pid_t pid = getpid(); 296 FILE *fp; 297 298 if ((fp = fopen(pidfilename, "w")) == NULL) 299 warnmsg(LOG_ERR, __func__, 300 "failed to open a pid log file(%s): %s", 301 pidfilename, strerror(errno)); 302 else { 303 fprintf(fp, "%d\n", pid); 304 fclose(fp); 305 } 306 } 307 #endif 308 309 #ifndef HAVE_POLL_H 310 memset(fdsetp, 0, fdmasks); 311 FD_SET(s, fdsetp); 312 FD_SET(rtsock, fdsetp); 313 #endif 314 while (1) { /* main loop */ 315 int e; 316 317 #ifndef HAVE_POLL_H 318 memcpy(selectfdp, fdsetp, fdmasks); 319 #endif 320 321 #ifndef SMALL 322 if (do_dump) { /* SIGUSR1 */ 323 do_dump = 0; 324 rtsold_dump_file(dumpfilename); 325 } 326 #endif 327 328 timeout = rtsol_check_timer(); 329 330 if (once) { 331 struct ifinfo *ifi; 332 333 /* if we have no timeout, we are done (or failed) */ 334 if (timeout == NULL) 335 break; 336 337 /* if all interfaces have got RA packet, we are done */ 338 for (ifi = iflist; ifi; ifi = ifi->next) { 339 if (ifi->state != IFS_DOWN && ifi->racnt == 0) 340 break; 341 } 342 if (ifi == NULL) 343 break; 344 } 345 #ifdef HAVE_POLL_H 346 e = poll(set, 2, timeout ? (timeout->tv_sec * 1000 + timeout->tv_usec / 1000) : INFTIM); 347 #else 348 e = select(maxfd + 1, selectfdp, NULL, NULL, timeout); 349 #endif 350 if (e < 1) { 351 if (e < 0 && errno != EINTR) { 352 warnmsg(LOG_ERR, __func__, "select: %s", 353 strerror(errno)); 354 } 355 continue; 356 } 357 358 /* packet reception */ 359 #ifdef HAVE_POLL_H 360 if (set[1].revents & POLLIN) 361 #else 362 if (FD_ISSET(rtsock, selectfdp)) 363 #endif 364 rtsock_input(rtsock); 365 #ifdef HAVE_POLL_H 366 if (set[0].revents & POLLIN) 367 #else 368 if (FD_ISSET(s, selectfdp)) 369 #endif 370 rtsol_input(s); 371 } 372 /* NOTREACHED */ 373 374 return 0; 375 } 376 377 int 378 ifconfig(char *ifname) 379 { 380 struct ifinfo *ifinfo; 381 struct sockaddr_dl *sdl; 382 int flags; 383 384 if ((sdl = if_nametosdl(ifname)) == NULL) { 385 warnmsg(LOG_ERR, __func__, 386 "failed to get link layer information for %s", ifname); 387 return(-1); 388 } 389 if (find_ifinfo(sdl->sdl_index)) { 390 warnmsg(LOG_ERR, __func__, 391 "interface %s was already configured", ifname); 392 free(sdl); 393 return(-1); 394 } 395 396 if ((ifinfo = malloc(sizeof(*ifinfo))) == NULL) { 397 warnmsg(LOG_ERR, __func__, "memory allocation failed"); 398 free(sdl); 399 return(-1); 400 } 401 memset(ifinfo, 0, sizeof(*ifinfo)); 402 ifinfo->sdl = sdl; 403 404 strlcpy(ifinfo->ifname, ifname, sizeof(ifinfo->ifname)); 405 406 /* construct a router solicitation message */ 407 if (make_packet(ifinfo)) 408 goto bad; 409 410 /* set link ID of this interface. */ 411 #ifdef HAVE_SCOPELIB 412 if (inet_zoneid(AF_INET6, 2, ifname, &ifinfo->linkid)) 413 goto bad; 414 #else 415 /* XXX: assume interface IDs as link IDs */ 416 ifinfo->linkid = ifinfo->sdl->sdl_index; 417 #endif 418 419 /* 420 * check if the interface is available. 421 * also check if SIOCGIFMEDIA ioctl is OK on the interface. 422 */ 423 ifinfo->mediareqok = 1; 424 ifinfo->active = interface_status(ifinfo); 425 if (!ifinfo->mediareqok) { 426 /* 427 * probe routers periodically even if the link status 428 * does not change. 429 */ 430 ifinfo->probeinterval = PROBE_INTERVAL; 431 } 432 433 /* activate interface: interface_up returns 0 on success */ 434 flags = interface_up(ifinfo->ifname); 435 if (flags == 0) 436 ifinfo->state = IFS_DELAY; 437 else if (flags == IFS_TENTATIVE) 438 ifinfo->state = IFS_TENTATIVE; 439 else 440 ifinfo->state = IFS_DOWN; 441 442 rtsol_timer_update(ifinfo); 443 444 /* link into chain */ 445 if (iflist) 446 ifinfo->next = iflist; 447 iflist = ifinfo; 448 449 return(0); 450 451 bad: 452 free(ifinfo->sdl); 453 free(ifinfo); 454 return(-1); 455 } 456 457 void 458 iflist_init(void) 459 { 460 struct ifinfo *ifi, *next; 461 462 for (ifi = iflist; ifi; ifi = next) { 463 next = ifi->next; 464 if (ifi->sdl) 465 free(ifi->sdl); 466 if (ifi->rs_data) 467 free(ifi->rs_data); 468 free(ifi); 469 iflist = NULL; 470 } 471 } 472 473 #if 0 474 static int 475 ifreconfig(char *ifname) 476 { 477 struct ifinfo *ifi, *prev; 478 int rv; 479 480 prev = NULL; 481 for (ifi = iflist; ifi; ifi = ifi->next) { 482 if (strncmp(ifi->ifname, ifname, sizeof(ifi->ifname)) == 0) 483 break; 484 prev = ifi; 485 } 486 prev->next = ifi->next; 487 488 rv = ifconfig(ifname); 489 490 /* reclaim it after ifconfig() in case ifname is pointer inside ifi */ 491 if (ifi->rs_data) 492 free(ifi->rs_data); 493 free(ifi->sdl); 494 free(ifi); 495 return rv; 496 } 497 #endif 498 499 struct ifinfo * 500 find_ifinfo(int ifindex) 501 { 502 struct ifinfo *ifi; 503 504 for (ifi = iflist; ifi; ifi = ifi->next) 505 if (ifi->sdl->sdl_index == ifindex) 506 return(ifi); 507 return(NULL); 508 } 509 510 static int 511 make_packet(struct ifinfo *ifinfo) 512 { 513 size_t packlen = sizeof(struct nd_router_solicit), lladdroptlen = 0; 514 struct nd_router_solicit *rs; 515 char *buf; 516 517 if ((lladdroptlen = lladdropt_length(ifinfo->sdl)) == 0) { 518 warnmsg(LOG_INFO, __func__, 519 "link-layer address option has null length" 520 " on %s. Treat as not included.", ifinfo->ifname); 521 } 522 packlen += lladdroptlen; 523 ifinfo->rs_datalen = packlen; 524 525 /* allocate buffer */ 526 if ((buf = malloc(packlen)) == NULL) { 527 warnmsg(LOG_ERR, __func__, 528 "memory allocation failed for %s", ifinfo->ifname); 529 return(-1); 530 } 531 ifinfo->rs_data = buf; 532 533 /* fill in the message */ 534 rs = (struct nd_router_solicit *)buf; 535 rs->nd_rs_type = ND_ROUTER_SOLICIT; 536 rs->nd_rs_code = 0; 537 rs->nd_rs_cksum = 0; 538 rs->nd_rs_reserved = 0; 539 buf += sizeof(*rs); 540 541 /* fill in source link-layer address option */ 542 if (lladdroptlen) 543 lladdropt_fill(ifinfo->sdl, (struct nd_opt_hdr *)buf); 544 545 return(0); 546 } 547 548 static struct timeval * 549 rtsol_check_timer(void) 550 { 551 static struct timeval returnval; 552 struct timeval now, rtsol_timer; 553 struct ifinfo *ifinfo; 554 int flags; 555 556 gettimeofday(&now, NULL); 557 558 rtsol_timer = tm_max; 559 560 for (ifinfo = iflist; ifinfo; ifinfo = ifinfo->next) { 561 if (timercmp(&ifinfo->expire, &now, <=)) { 562 if (dflag > 1) 563 warnmsg(LOG_DEBUG, __func__, 564 "timer expiration on %s, " 565 "state = %d", ifinfo->ifname, 566 ifinfo->state); 567 568 switch (ifinfo->state) { 569 case IFS_DOWN: 570 case IFS_TENTATIVE: 571 /* interface_up returns 0 on success */ 572 flags = interface_up(ifinfo->ifname); 573 if (flags == 0) 574 ifinfo->state = IFS_DELAY; 575 else if (flags == IFS_TENTATIVE) 576 ifinfo->state = IFS_TENTATIVE; 577 else 578 ifinfo->state = IFS_DOWN; 579 break; 580 case IFS_IDLE: 581 { 582 int oldstatus = ifinfo->active; 583 int probe = 0; 584 585 ifinfo->active = interface_status(ifinfo); 586 587 if (oldstatus != ifinfo->active) { 588 warnmsg(LOG_DEBUG, __func__, 589 "%s status is changed" 590 " from %d to %d", 591 ifinfo->ifname, 592 oldstatus, ifinfo->active); 593 probe = 1; 594 ifinfo->state = IFS_DELAY; 595 } else if (ifinfo->probeinterval && 596 (ifinfo->probetimer -= 597 ifinfo->timer.tv_sec) <= 0) { 598 /* probe timer expired */ 599 ifinfo->probetimer = 600 ifinfo->probeinterval; 601 probe = 1; 602 ifinfo->state = IFS_PROBE; 603 } 604 605 /* 606 * If we need a probe, clear the previous 607 * status wrt the "other" configuration. 608 */ 609 if (probe) 610 ifinfo->otherconfig = 0; 611 612 if (probe && mobile_node) 613 defrouter_probe(ifinfo); 614 break; 615 } 616 case IFS_DELAY: 617 ifinfo->state = IFS_PROBE; 618 sendpacket(ifinfo); 619 break; 620 case IFS_PROBE: 621 if (ifinfo->probes < MAX_RTR_SOLICITATIONS) 622 sendpacket(ifinfo); 623 else { 624 warnmsg(LOG_INFO, __func__, 625 "No answer after sending %d RSs", 626 ifinfo->probes); 627 ifinfo->probes = 0; 628 ifinfo->state = IFS_IDLE; 629 } 630 break; 631 } 632 rtsol_timer_update(ifinfo); 633 } 634 635 if (timercmp(&ifinfo->expire, &rtsol_timer, <)) 636 rtsol_timer = ifinfo->expire; 637 } 638 639 if (timercmp(&rtsol_timer, &tm_max, ==)) { 640 warnmsg(LOG_DEBUG, __func__, "there is no timer"); 641 return(NULL); 642 } else if (timercmp(&rtsol_timer, &now, <)) 643 /* this may occur when the interval is too small */ 644 returnval.tv_sec = returnval.tv_usec = 0; 645 else 646 timersub(&rtsol_timer, &now, &returnval); 647 648 if (dflag > 1) 649 warnmsg(LOG_DEBUG, __func__, "New timer is %ld:%08ld", 650 (long)returnval.tv_sec, (long)returnval.tv_usec); 651 652 return(&returnval); 653 } 654 655 void 656 rtsol_timer_update(struct ifinfo *ifinfo) 657 { 658 #define MILLION 1000000 659 #define DADRETRY 10 /* XXX: adhoc */ 660 long interval; 661 struct timeval now; 662 663 bzero(&ifinfo->timer, sizeof(ifinfo->timer)); 664 665 switch (ifinfo->state) { 666 case IFS_DOWN: 667 case IFS_TENTATIVE: 668 if (++ifinfo->dadcount > DADRETRY) { 669 ifinfo->dadcount = 0; 670 ifinfo->timer.tv_sec = PROBE_INTERVAL; 671 } else 672 ifinfo->timer.tv_sec = 1; 673 break; 674 case IFS_IDLE: 675 if (mobile_node) { 676 /* XXX should be configurable */ 677 ifinfo->timer.tv_sec = 3; 678 } 679 else 680 ifinfo->timer = tm_max; /* stop timer(valid?) */ 681 break; 682 case IFS_DELAY: 683 #ifndef HAVE_ARC4RANDOM 684 interval = random() % (MAX_RTR_SOLICITATION_DELAY * MILLION); 685 #else 686 interval = arc4random() % (MAX_RTR_SOLICITATION_DELAY * MILLION); 687 #endif 688 ifinfo->timer.tv_sec = interval / MILLION; 689 ifinfo->timer.tv_usec = interval % MILLION; 690 break; 691 case IFS_PROBE: 692 if (ifinfo->probes < MAX_RTR_SOLICITATIONS) 693 ifinfo->timer.tv_sec = RTR_SOLICITATION_INTERVAL; 694 else { 695 /* 696 * After sending MAX_RTR_SOLICITATIONS solicitations, 697 * we're just waiting for possible replies; there 698 * will be no more solicitation. Thus, we change 699 * the timer value to MAX_RTR_SOLICITATION_DELAY based 700 * on RFC 2461, Section 6.3.7. 701 */ 702 ifinfo->timer.tv_sec = MAX_RTR_SOLICITATION_DELAY; 703 } 704 break; 705 default: 706 warnmsg(LOG_ERR, __func__, 707 "illegal interface state(%d) on %s", 708 ifinfo->state, ifinfo->ifname); 709 return; 710 } 711 712 /* reset the timer */ 713 if (timercmp(&ifinfo->timer, &tm_max, ==)) { 714 ifinfo->expire = tm_max; 715 warnmsg(LOG_DEBUG, __func__, 716 "stop timer for %s", ifinfo->ifname); 717 } else { 718 gettimeofday(&now, NULL); 719 timeradd(&now, &ifinfo->timer, &ifinfo->expire); 720 721 if (dflag > 1) 722 warnmsg(LOG_DEBUG, __func__, 723 "set timer for %s to %d:%d", ifinfo->ifname, 724 (int)ifinfo->timer.tv_sec, 725 (int)ifinfo->timer.tv_usec); 726 } 727 728 #undef MILLION 729 } 730 731 /* timer related utility functions */ 732 #define MILLION 1000000 733 734 #ifndef SMALL 735 static void 736 rtsold_set_dump_file(int sig) 737 { 738 do_dump = 1; 739 } 740 #endif 741 742 static void 743 usage(char *progname) 744 { 745 if (progname && progname[strlen(progname) - 1] != 'd') { 746 fprintf(stderr, "usage: rtsol [-dDF] interfaces...\n"); 747 fprintf(stderr, "usage: rtsol [-dDF] -a\n"); 748 } else { 749 fprintf(stderr, "usage: rtsold [-adDfFm1] interfaces...\n"); 750 fprintf(stderr, "usage: rtsold [-dDfFm1] -a\n"); 751 } 752 exit(1); 753 } 754 755 void 756 #if __STDC__ 757 warnmsg(int priority, const char *func, const char *msg, ...) 758 #else 759 warnmsg(priority, func, msg, va_alist) 760 int priority; 761 const char *func; 762 const char *msg; 763 va_dcl 764 #endif 765 { 766 va_list ap; 767 char buf[BUFSIZ]; 768 769 va_start(ap, msg); 770 if (fflag) { 771 if (priority <= log_upto) { 772 (void)vfprintf(stderr, msg, ap); 773 (void)fprintf(stderr, "\n"); 774 } 775 } else { 776 snprintf(buf, sizeof(buf), "<%s> %s", func, msg); 777 msg = buf; 778 vsyslog(priority, msg, ap); 779 } 780 va_end(ap); 781 } 782 783 /* 784 * return a list of interfaces which is suitable to sending an RS. 785 */ 786 char ** 787 autoifprobe(void) 788 { 789 static char **argv = NULL; 790 static int n = 0; 791 char **a; 792 int i, found; 793 struct ifaddrs *ifap, *ifa, *target; 794 795 /* initialize */ 796 while (n--) 797 free(argv[n]); 798 if (argv) { 799 free(argv); 800 argv = NULL; 801 } 802 n = 0; 803 804 if (getifaddrs(&ifap) != 0) 805 return NULL; 806 807 target = NULL; 808 /* find an ethernet */ 809 for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 810 if ((ifa->ifa_flags & IFF_UP) == 0) 811 continue; 812 if ((ifa->ifa_flags & IFF_POINTOPOINT) != 0) 813 continue; 814 if ((ifa->ifa_flags & IFF_LOOPBACK) != 0) 815 continue; 816 if ((ifa->ifa_flags & IFF_MULTICAST) == 0) 817 continue; 818 819 if (ifa->ifa_addr->sa_family != AF_INET6) 820 continue; 821 822 found = 0; 823 for (i = 0; i < n; i++) { 824 if (strcmp(argv[i], ifa->ifa_name) == 0) { 825 found++; 826 break; 827 } 828 } 829 if (found) 830 continue; 831 832 /* if we find multiple candidates, just warn. */ 833 if (n != 0 && dflag > 1) 834 warnx("multiple interfaces found"); 835 836 a = (char **)realloc(argv, (n + 1) * sizeof(char **)); 837 if (a == NULL) 838 err(1, "realloc"); 839 argv = a; 840 argv[n] = strdup(ifa->ifa_name); 841 if (!argv[n]) 842 err(1, "malloc"); 843 n++; 844 argv[n] = NULL; 845 } 846 847 if (n) { 848 a = (char **)realloc(argv, (n + 1) * sizeof(char **)); 849 if (a == NULL) 850 err(1, "realloc"); 851 argv = a; 852 argv[n] = NULL; 853 854 if (dflag > 0) { 855 for (i = 0; i < n; i++) 856 warnx("probing %s", argv[i]); 857 } 858 } 859 freeifaddrs(ifap); 860 return argv; 861 } 862