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