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