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