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