1 /* $KAME: rtsold.c,v 1.67 2003/05/17 18:16:15 itojun Exp $ */ 2 3 /*- 4 * SPDX-License-Identifier: BSD-3-Clause 5 * 6 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. Neither the name of the project nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * $FreeBSD$ 34 */ 35 36 #include <sys/param.h> 37 #include <sys/capsicum.h> 38 #include <sys/event.h> 39 #include <sys/ioctl.h> 40 #include <sys/socket.h> 41 42 #include <net/if.h> 43 #include <net/if_dl.h> 44 45 #include <netinet/in.h> 46 #include <netinet/icmp6.h> 47 #include <netinet/in_var.h> 48 #include <arpa/inet.h> 49 50 #include <netinet6/nd6.h> 51 52 #include <capsicum_helpers.h> 53 #include <err.h> 54 #include <errno.h> 55 #include <ifaddrs.h> 56 #include <libgen.h> 57 #include <signal.h> 58 #include <stdarg.h> 59 #include <stdio.h> 60 #include <stdlib.h> 61 #include <string.h> 62 #include <syslog.h> 63 #include <time.h> 64 #include <unistd.h> 65 66 #include <libcasper.h> 67 #include <casper/cap_syslog.h> 68 #include <libutil.h> 69 70 #include "rtsold.h" 71 72 #define RTSOL_DUMPFILE "/var/run/rtsold.dump" 73 74 struct timespec tm_max; 75 static int log_upto = 999; 76 static int fflag = 0; 77 78 int Fflag = 0; /* force setting sysctl parameters */ 79 int aflag = 0; 80 int dflag = 0; 81 int uflag = 0; 82 83 const char *managedconf_script; 84 const char *otherconf_script; 85 const char *alwaysconf_script; 86 const char *resolvconf_script = "/sbin/resolvconf"; 87 88 cap_channel_t *capllflags, *capscript, *capsendmsg, *capsyslog; 89 90 /* protocol constants */ 91 #define MAX_RTR_SOLICITATION_DELAY 1 /* second */ 92 #define RTR_SOLICITATION_INTERVAL 4 /* seconds */ 93 #define MAX_RTR_SOLICITATIONS 3 /* times */ 94 95 /* 96 * implementation dependent constants in seconds 97 * XXX: should be configurable 98 */ 99 #define PROBE_INTERVAL 60 100 101 /* static variables and functions */ 102 static int mobile_node = 0; 103 static int no_solicitation_delay = 0; 104 105 static sig_atomic_t do_dump, do_exit; 106 static struct pidfh *pfh; 107 108 static char **autoifprobe(void); 109 static int ifconfig(char *ifname); 110 static int init_capabilities(void); 111 static int make_packet(struct ifinfo *); 112 static struct timespec *rtsol_check_timer(void); 113 114 static void set_dumpfile(int); 115 static void set_exit(int); 116 static void usage(const char *progname); 117 118 int 119 main(int argc, char **argv) 120 { 121 struct kevent events[2]; 122 FILE *dumpfp; 123 struct ifinfo *ifi; 124 struct timespec *timeout; 125 const char *opts, *pidfilepath, *progname; 126 int ch, error, kq, once, rcvsock, rtsock; 127 128 progname = basename(argv[0]); 129 if (strcmp(progname, "rtsold") == 0) { 130 opts = "adDfFim1M:O:A:p:R:u"; 131 once = 0; 132 pidfilepath = NULL; 133 } else { 134 opts = "adDFiM:O:A:R:u"; 135 fflag = 1; 136 once = 1; 137 } 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 'i': 157 no_solicitation_delay = 1; 158 break; 159 case 'm': 160 mobile_node = 1; 161 break; 162 case '1': 163 once = 1; 164 break; 165 case 'M': 166 managedconf_script = optarg; 167 break; 168 case 'O': 169 otherconf_script = optarg; 170 break; 171 case 'A': 172 alwaysconf_script = optarg; 173 break; 174 case 'p': 175 pidfilepath = optarg; 176 break; 177 case 'R': 178 resolvconf_script = optarg; 179 break; 180 case 'u': 181 uflag = 1; 182 break; 183 default: 184 usage(progname); 185 } 186 } 187 argc -= optind; 188 argv += optind; 189 190 if ((!aflag && argc == 0) || (aflag && argc != 0)) 191 usage(progname); 192 193 /* Generate maximum time in timespec. */ 194 tm_max.tv_sec = (-1) & ~((time_t)1 << ((sizeof(tm_max.tv_sec) * 8) - 1)); 195 tm_max.tv_nsec = (-1) & ~((long)1 << ((sizeof(tm_max.tv_nsec) * 8) - 1)); 196 197 /* set log level */ 198 if (dflag > 1) 199 log_upto = LOG_DEBUG; 200 else if (dflag > 0) 201 log_upto = LOG_INFO; 202 else 203 log_upto = LOG_NOTICE; 204 205 if (managedconf_script != NULL && *managedconf_script != '/') 206 errx(1, "configuration script (%s) must be an absolute path", 207 managedconf_script); 208 if (otherconf_script != NULL && *otherconf_script != '/') 209 errx(1, "configuration script (%s) must be an absolute path", 210 otherconf_script); 211 if (alwaysconf_script != NULL && *alwaysconf_script != '/') 212 errx(1, "configuration script (%s) must be an absolute path", 213 alwaysconf_script); 214 if (*resolvconf_script != '/') 215 errx(1, "configuration script (%s) must be an absolute path", 216 resolvconf_script); 217 218 if (!fflag) { 219 pfh = pidfile_open(pidfilepath, 0644, NULL); 220 if (pfh == NULL) 221 errx(1, "failed to open pidfile: %s", strerror(errno)); 222 if (daemon(0, 0) != 0) 223 errx(1, "failed to daemonize"); 224 } 225 226 if ((error = init_capabilities()) != 0) 227 err(1, "failed to initialize capabilities"); 228 229 if (!fflag) { 230 cap_openlog(capsyslog, progname, LOG_NDELAY | LOG_PID, 231 LOG_DAEMON); 232 if (log_upto >= 0) 233 (void)cap_setlogmask(capsyslog, LOG_UPTO(log_upto)); 234 (void)signal(SIGTERM, set_exit); 235 (void)signal(SIGINT, set_exit); 236 (void)signal(SIGUSR1, set_dumpfile); 237 dumpfp = rtsold_init_dumpfile(RTSOL_DUMPFILE); 238 } else 239 dumpfp = NULL; 240 241 kq = kqueue(); 242 if (kq < 0) { 243 warnmsg(LOG_ERR, __func__, "failed to create a kqueue: %s", 244 strerror(errno)); 245 exit(1); 246 } 247 248 /* Open global sockets and register for read events. */ 249 if ((rtsock = rtsock_open()) < 0) { 250 warnmsg(LOG_ERR, __func__, "failed to open routing socket"); 251 exit(1); 252 } 253 if ((rcvsock = recvsockopen()) < 0) { 254 warnmsg(LOG_ERR, __func__, "failed to open receive socket"); 255 exit(1); 256 } 257 EV_SET(&events[0], rtsock, EVFILT_READ, EV_ADD, 0, 0, NULL); 258 EV_SET(&events[1], rcvsock, EVFILT_READ, EV_ADD, 0, 0, NULL); 259 if (kevent(kq, events, 2, NULL, 0, NULL) < 0) { 260 warnmsg(LOG_ERR, __func__, "kevent(): %s", strerror(errno)); 261 exit(1); 262 } 263 264 /* Probe network interfaces and set up tracking info. */ 265 if (ifinit() != 0) { 266 warnmsg(LOG_ERR, __func__, "failed to initialize interfaces"); 267 exit(1); 268 } 269 if (aflag) 270 argv = autoifprobe(); 271 while (argv && *argv) { 272 if (ifconfig(*argv)) { 273 warnmsg(LOG_ERR, __func__, 274 "failed to initialize %s", *argv); 275 exit(1); 276 } 277 argv++; 278 } 279 280 /* Write to our pidfile. */ 281 if (pfh != NULL && pidfile_write(pfh) != 0) { 282 warnmsg(LOG_ERR, __func__, 283 "failed to open pidfile: %s", strerror(errno)); 284 exit(1); 285 } 286 287 /* Enter capability mode. */ 288 caph_cache_catpages(); 289 if (caph_enter_casper() != 0) { 290 warnmsg(LOG_ERR, __func__, "caph_enter(): %s", strerror(errno)); 291 exit(1); 292 } 293 294 for (;;) { 295 if (do_exit) { 296 /* Handle SIGTERM, SIGINT. */ 297 if (pfh != NULL) 298 pidfile_remove(pfh); 299 break; 300 } 301 if (do_dump) { 302 /* Handle SIGUSR1. */ 303 do_dump = 0; 304 if (dumpfp != NULL) 305 rtsold_dump(dumpfp); 306 } 307 308 timeout = rtsol_check_timer(); 309 310 if (once) { 311 /* if we have no timeout, we are done (or failed) */ 312 if (timeout == NULL) 313 break; 314 315 /* if all interfaces have got RA packet, we are done */ 316 TAILQ_FOREACH(ifi, &ifinfo_head, ifi_next) { 317 if (ifi->state != IFS_DOWN && ifi->racnt == 0) 318 break; 319 } 320 if (ifi == NULL) 321 break; 322 } 323 324 error = kevent(kq, NULL, 0, &events[0], 1, timeout); 325 if (error < 1) { 326 if (error < 0 && errno != EINTR) 327 warnmsg(LOG_ERR, __func__, "kevent(): %s", 328 strerror(errno)); 329 continue; 330 } 331 332 if (events[0].ident == (uintptr_t)rtsock) 333 rtsock_input(rtsock); 334 else 335 rtsol_input(rcvsock); 336 } 337 338 return (0); 339 } 340 341 static int 342 init_capabilities(void) 343 { 344 #ifdef WITH_CASPER 345 const char *const scripts[] = 346 { resolvconf_script, managedconf_script, otherconf_script, 347 alwaysconf_script }; 348 cap_channel_t *capcasper; 349 nvlist_t *limits; 350 351 capcasper = cap_init(); 352 if (capcasper == NULL) 353 return (-1); 354 355 capllflags = cap_service_open(capcasper, "rtsold.llflags"); 356 if (capllflags == NULL) 357 return (-1); 358 359 capscript = cap_service_open(capcasper, "rtsold.script"); 360 if (capscript == NULL) 361 return (-1); 362 limits = nvlist_create(0); 363 for (size_t i = 0; i < nitems(scripts); i++) 364 if (scripts[i] != NULL) 365 nvlist_append_string_array(limits, "scripts", 366 scripts[i]); 367 if (cap_limit_set(capscript, limits) != 0) 368 return (-1); 369 370 capsendmsg = cap_service_open(capcasper, "rtsold.sendmsg"); 371 if (capsendmsg == NULL) 372 return (-1); 373 374 if (!fflag) { 375 capsyslog = cap_service_open(capcasper, "system.syslog"); 376 if (capsyslog == NULL) 377 return (-1); 378 } 379 380 cap_close(capcasper); 381 #endif /* WITH_CASPER */ 382 return (0); 383 } 384 385 static int 386 ifconfig(char *ifname) 387 { 388 struct ifinfo *ifi; 389 struct sockaddr_dl *sdl; 390 int flags; 391 392 ifi = NULL; 393 if ((sdl = if_nametosdl(ifname)) == NULL) { 394 warnmsg(LOG_ERR, __func__, 395 "failed to get link layer information for %s", ifname); 396 goto bad; 397 } 398 if (find_ifinfo(sdl->sdl_index)) { 399 warnmsg(LOG_ERR, __func__, 400 "interface %s was already configured", ifname); 401 goto bad; 402 } 403 404 if (Fflag) { 405 struct in6_ndireq nd; 406 int s; 407 408 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 409 warnmsg(LOG_ERR, __func__, "socket() failed."); 410 goto bad; 411 } 412 memset(&nd, 0, sizeof(nd)); 413 strlcpy(nd.ifname, ifname, sizeof(nd.ifname)); 414 if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd) < 0) { 415 warnmsg(LOG_ERR, __func__, 416 "cannot get accept_rtadv flag"); 417 (void)close(s); 418 goto bad; 419 } 420 nd.ndi.flags |= ND6_IFF_ACCEPT_RTADV; 421 if (ioctl(s, SIOCSIFINFO_IN6, (caddr_t)&nd) < 0) { 422 warnmsg(LOG_ERR, __func__, 423 "cannot set accept_rtadv flag"); 424 (void)close(s); 425 goto bad; 426 } 427 (void)close(s); 428 } 429 430 if ((ifi = malloc(sizeof(*ifi))) == NULL) { 431 warnmsg(LOG_ERR, __func__, "memory allocation failed"); 432 goto bad; 433 } 434 memset(ifi, 0, sizeof(*ifi)); 435 ifi->sdl = sdl; 436 ifi->ifi_rdnss = IFI_DNSOPT_STATE_NOINFO; 437 ifi->ifi_dnssl = IFI_DNSOPT_STATE_NOINFO; 438 TAILQ_INIT(&ifi->ifi_rainfo); 439 strlcpy(ifi->ifname, ifname, sizeof(ifi->ifname)); 440 441 /* construct a router solicitation message */ 442 if (make_packet(ifi)) 443 goto bad; 444 445 /* set link ID of this interface. */ 446 #ifdef HAVE_SCOPELIB 447 if (inet_zoneid(AF_INET6, 2, ifname, &ifi->linkid)) 448 goto bad; 449 #else 450 /* XXX: assume interface IDs as link IDs */ 451 ifi->linkid = ifi->sdl->sdl_index; 452 #endif 453 454 /* 455 * check if the interface is available. 456 * also check if SIOCGIFMEDIA ioctl is OK on the interface. 457 */ 458 ifi->mediareqok = 1; 459 ifi->active = interface_status(ifi); 460 if (!ifi->mediareqok) { 461 /* 462 * probe routers periodically even if the link status 463 * does not change. 464 */ 465 ifi->probeinterval = PROBE_INTERVAL; 466 } 467 468 /* activate interface: interface_up returns 0 on success */ 469 flags = interface_up(ifi->ifname); 470 if (flags == 0) 471 ifi->state = IFS_DELAY; 472 else if (flags == IFS_TENTATIVE) 473 ifi->state = IFS_TENTATIVE; 474 else 475 ifi->state = IFS_DOWN; 476 477 rtsol_timer_update(ifi); 478 479 TAILQ_INSERT_TAIL(&ifinfo_head, ifi, ifi_next); 480 return (0); 481 482 bad: 483 free(sdl); 484 free(ifi); 485 return (-1); 486 } 487 488 struct rainfo * 489 find_rainfo(struct ifinfo *ifi, struct sockaddr_in6 *sin6) 490 { 491 struct rainfo *rai; 492 493 TAILQ_FOREACH(rai, &ifi->ifi_rainfo, rai_next) 494 if (memcmp(&rai->rai_saddr.sin6_addr, &sin6->sin6_addr, 495 sizeof(rai->rai_saddr.sin6_addr)) == 0) 496 return (rai); 497 498 return (NULL); 499 } 500 501 struct ifinfo * 502 find_ifinfo(int ifindex) 503 { 504 struct ifinfo *ifi; 505 506 TAILQ_FOREACH(ifi, &ifinfo_head, ifi_next) { 507 if (ifi->sdl->sdl_index == ifindex) 508 return (ifi); 509 } 510 return (NULL); 511 } 512 513 static int 514 make_packet(struct ifinfo *ifi) 515 { 516 size_t packlen = sizeof(struct nd_router_solicit), lladdroptlen = 0; 517 struct nd_router_solicit *rs; 518 char *buf; 519 520 if ((lladdroptlen = lladdropt_length(ifi->sdl)) == 0) { 521 warnmsg(LOG_INFO, __func__, 522 "link-layer address option has null length" 523 " on %s. Treat as not included.", ifi->ifname); 524 } 525 packlen += lladdroptlen; 526 ifi->rs_datalen = packlen; 527 528 /* allocate buffer */ 529 if ((buf = malloc(packlen)) == NULL) { 530 warnmsg(LOG_ERR, __func__, 531 "memory allocation failed for %s", ifi->ifname); 532 return (-1); 533 } 534 ifi->rs_data = buf; 535 536 /* fill in the message */ 537 rs = (struct nd_router_solicit *)buf; 538 rs->nd_rs_type = ND_ROUTER_SOLICIT; 539 rs->nd_rs_code = 0; 540 rs->nd_rs_cksum = 0; 541 rs->nd_rs_reserved = 0; 542 buf += sizeof(*rs); 543 544 /* fill in source link-layer address option */ 545 if (lladdroptlen) 546 lladdropt_fill(ifi->sdl, (struct nd_opt_hdr *)buf); 547 548 return (0); 549 } 550 551 static struct timespec * 552 rtsol_check_timer(void) 553 { 554 static struct timespec returnval; 555 struct timespec now, rtsol_timer; 556 struct ifinfo *ifi; 557 struct rainfo *rai; 558 struct ra_opt *rao, *raotmp; 559 int error, flags; 560 561 clock_gettime(CLOCK_MONOTONIC_FAST, &now); 562 563 rtsol_timer = tm_max; 564 565 TAILQ_FOREACH(ifi, &ifinfo_head, ifi_next) { 566 if (TS_CMP(&ifi->expire, &now, <=)) { 567 warnmsg(LOG_DEBUG, __func__, "timer expiration on %s, " 568 "state = %d", ifi->ifname, ifi->state); 569 570 while((rai = TAILQ_FIRST(&ifi->ifi_rainfo)) != NULL) { 571 /* Remove all RA options. */ 572 TAILQ_REMOVE(&ifi->ifi_rainfo, rai, rai_next); 573 while ((rao = TAILQ_FIRST(&rai->rai_ra_opt)) != 574 NULL) { 575 TAILQ_REMOVE(&rai->rai_ra_opt, rao, 576 rao_next); 577 if (rao->rao_msg != NULL) 578 free(rao->rao_msg); 579 free(rao); 580 } 581 free(rai); 582 } 583 switch (ifi->state) { 584 case IFS_DOWN: 585 case IFS_TENTATIVE: 586 /* interface_up returns 0 on success */ 587 flags = interface_up(ifi->ifname); 588 if (flags == 0) 589 ifi->state = IFS_DELAY; 590 else if (flags == IFS_TENTATIVE) 591 ifi->state = IFS_TENTATIVE; 592 else 593 ifi->state = IFS_DOWN; 594 break; 595 case IFS_IDLE: 596 { 597 int oldstatus = ifi->active; 598 int probe = 0; 599 600 ifi->active = interface_status(ifi); 601 602 if (oldstatus != ifi->active) { 603 warnmsg(LOG_DEBUG, __func__, 604 "%s status is changed" 605 " from %d to %d", 606 ifi->ifname, 607 oldstatus, ifi->active); 608 probe = 1; 609 ifi->state = IFS_DELAY; 610 } else if (ifi->probeinterval && 611 (ifi->probetimer -= 612 ifi->timer.tv_sec) <= 0) { 613 /* probe timer expired */ 614 ifi->probetimer = 615 ifi->probeinterval; 616 probe = 1; 617 ifi->state = IFS_PROBE; 618 } 619 620 /* 621 * If we need a probe, clear the previous 622 * status wrt the "managed/other" configuration. 623 */ 624 if (probe) { 625 ifi->managedconfig = 0; 626 ifi->otherconfig = 0; 627 ifi->alwaysconfig = 0; 628 } 629 if (probe && mobile_node) { 630 error = cap_probe_defrouters(capsendmsg, 631 ifi); 632 if (error != 0) 633 warnmsg(LOG_DEBUG, __func__, 634 "failed to probe routers: %d", 635 error); 636 } 637 break; 638 } 639 case IFS_DELAY: 640 ifi->state = IFS_PROBE; 641 (void)cap_rssend(capsendmsg, ifi); 642 break; 643 case IFS_PROBE: 644 if (ifi->probes < MAX_RTR_SOLICITATIONS) 645 (void)cap_rssend(capsendmsg, ifi); 646 else { 647 warnmsg(LOG_INFO, __func__, 648 "No answer after sending %d RSs", 649 ifi->probes); 650 ifi->probes = 0; 651 ifi->state = IFS_IDLE; 652 } 653 break; 654 } 655 rtsol_timer_update(ifi); 656 } else { 657 /* Expiration check for RA options. */ 658 int expire = 0; 659 660 TAILQ_FOREACH(rai, &ifi->ifi_rainfo, rai_next) { 661 TAILQ_FOREACH_SAFE(rao, &rai->rai_ra_opt, 662 rao_next, raotmp) { 663 warnmsg(LOG_DEBUG, __func__, 664 "RA expiration timer: " 665 "type=%d, msg=%s, expire=%s", 666 rao->rao_type, (char *)rao->rao_msg, 667 sec2str(&rao->rao_expire)); 668 if (TS_CMP(&now, &rao->rao_expire, 669 >=)) { 670 warnmsg(LOG_DEBUG, __func__, 671 "RA expiration timer: " 672 "expired."); 673 TAILQ_REMOVE(&rai->rai_ra_opt, 674 rao, rao_next); 675 if (rao->rao_msg != NULL) 676 free(rao->rao_msg); 677 free(rao); 678 expire = 1; 679 } 680 } 681 } 682 if (expire) 683 ra_opt_handler(ifi); 684 } 685 if (TS_CMP(&ifi->expire, &rtsol_timer, <)) 686 rtsol_timer = ifi->expire; 687 } 688 689 if (TS_CMP(&rtsol_timer, &tm_max, ==)) { 690 warnmsg(LOG_DEBUG, __func__, "there is no timer"); 691 return (NULL); 692 } else if (TS_CMP(&rtsol_timer, &now, <)) 693 /* this may occur when the interval is too small */ 694 returnval.tv_sec = returnval.tv_nsec = 0; 695 else 696 TS_SUB(&rtsol_timer, &now, &returnval); 697 698 now.tv_sec += returnval.tv_sec; 699 now.tv_nsec += returnval.tv_nsec; 700 warnmsg(LOG_DEBUG, __func__, "New timer is %s", 701 sec2str(&now)); 702 703 return (&returnval); 704 } 705 706 void 707 rtsol_timer_update(struct ifinfo *ifi) 708 { 709 #define MILLION 1000000 710 #define DADRETRY 10 /* XXX: adhoc */ 711 long interval; 712 struct timespec now; 713 714 bzero(&ifi->timer, sizeof(ifi->timer)); 715 716 switch (ifi->state) { 717 case IFS_DOWN: 718 case IFS_TENTATIVE: 719 if (++ifi->dadcount > DADRETRY) { 720 ifi->dadcount = 0; 721 ifi->timer.tv_sec = PROBE_INTERVAL; 722 } else 723 ifi->timer.tv_sec = 1; 724 break; 725 case IFS_IDLE: 726 if (mobile_node) 727 /* XXX should be configurable */ 728 ifi->timer.tv_sec = 3; 729 else 730 ifi->timer = tm_max; /* stop timer(valid?) */ 731 break; 732 case IFS_DELAY: 733 if (no_solicitation_delay) 734 interval = 0; 735 else 736 interval = arc4random_uniform(MAX_RTR_SOLICITATION_DELAY * MILLION); 737 ifi->timer.tv_sec = interval / MILLION; 738 ifi->timer.tv_nsec = (interval % MILLION) * 1000; 739 break; 740 case IFS_PROBE: 741 if (ifi->probes < MAX_RTR_SOLICITATIONS) 742 ifi->timer.tv_sec = RTR_SOLICITATION_INTERVAL; 743 else 744 /* 745 * After sending MAX_RTR_SOLICITATIONS solicitations, 746 * we're just waiting for possible replies; there 747 * will be no more solicitation. Thus, we change 748 * the timer value to MAX_RTR_SOLICITATION_DELAY based 749 * on RFC 2461, Section 6.3.7. 750 */ 751 ifi->timer.tv_sec = MAX_RTR_SOLICITATION_DELAY; 752 break; 753 default: 754 warnmsg(LOG_ERR, __func__, 755 "illegal interface state(%d) on %s", 756 ifi->state, ifi->ifname); 757 return; 758 } 759 760 /* reset the timer */ 761 if (TS_CMP(&ifi->timer, &tm_max, ==)) { 762 ifi->expire = tm_max; 763 warnmsg(LOG_DEBUG, __func__, 764 "stop timer for %s", ifi->ifname); 765 } else { 766 clock_gettime(CLOCK_MONOTONIC_FAST, &now); 767 TS_ADD(&now, &ifi->timer, &ifi->expire); 768 769 now.tv_sec += ifi->timer.tv_sec; 770 now.tv_nsec += ifi->timer.tv_nsec; 771 warnmsg(LOG_DEBUG, __func__, "set timer for %s to %s", 772 ifi->ifname, sec2str(&now)); 773 } 774 775 #undef MILLION 776 } 777 778 static void 779 set_dumpfile(int sig __unused) 780 { 781 782 do_dump = 1; 783 } 784 785 static void 786 set_exit(int sig __unused) 787 { 788 789 do_exit = 1; 790 } 791 792 static void 793 usage(const char *progname) 794 { 795 796 if (strcmp(progname, "rtsold") == 0) { 797 fprintf(stderr, "usage: rtsold [-dDfFm1] [-O script-name] " 798 "[-M script-name ] [-A script-name ] " 799 "[-p pidfile] [-R script-name] interface ...\n"); 800 fprintf(stderr, "usage: rtsold [-dDfFm1] [-O script-name] " 801 "[-M script-name ] [-A script-name ] " 802 "[-p pidfile] [-R script-name] -a\n"); 803 } else { 804 fprintf(stderr, "usage: rtsol [-dDF] [-O script-name] " 805 "[-M script-name ] [-A script-name ] " 806 "[-p pidfile] [-R script-name] interface ...\n"); 807 fprintf(stderr, "usage: rtsol [-dDF] [-O script-name] " 808 "[-M script-name ] [-A script-name ] " 809 "[-p pidfile] [-R script-name] -a\n"); 810 } 811 exit(1); 812 } 813 814 void 815 warnmsg(int priority, const char *func, const char *msg, ...) 816 { 817 va_list ap; 818 char buf[BUFSIZ]; 819 820 va_start(ap, msg); 821 if (fflag) { 822 if (priority <= log_upto) 823 vwarnx(msg, ap); 824 } else { 825 snprintf(buf, sizeof(buf), "<%s> %s", func, msg); 826 msg = buf; 827 cap_vsyslog(capsyslog, priority, msg, ap); 828 } 829 va_end(ap); 830 } 831 832 /* 833 * return a list of interfaces which is suitable to sending an RS. 834 */ 835 static char ** 836 autoifprobe(void) 837 { 838 static char **argv = NULL; 839 static int n = 0; 840 char **a; 841 int s = 0, i, found; 842 struct ifaddrs *ifap, *ifa; 843 struct in6_ndireq nd; 844 845 /* initialize */ 846 while (n--) 847 free(argv[n]); 848 if (argv) { 849 free(argv); 850 argv = NULL; 851 } 852 n = 0; 853 854 if (getifaddrs(&ifap) != 0) 855 return (NULL); 856 857 if (!Fflag && (s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 858 warnmsg(LOG_ERR, __func__, "socket"); 859 exit(1); 860 } 861 862 /* find an ethernet */ 863 for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 864 if ((ifa->ifa_flags & IFF_UP) == 0) 865 continue; 866 if ((ifa->ifa_flags & IFF_LOOPBACK) != 0) 867 continue; 868 if ((ifa->ifa_flags & IFF_MULTICAST) == 0) 869 continue; 870 871 if (ifa->ifa_addr->sa_family != AF_INET6) 872 continue; 873 874 found = 0; 875 for (i = 0; i < n; i++) { 876 if (strcmp(argv[i], ifa->ifa_name) == 0) { 877 found++; 878 break; 879 } 880 } 881 if (found) 882 continue; 883 884 /* 885 * Skip the interfaces which IPv6 and/or accepting RA 886 * is disabled. 887 */ 888 if (!Fflag) { 889 memset(&nd, 0, sizeof(nd)); 890 strlcpy(nd.ifname, ifa->ifa_name, sizeof(nd.ifname)); 891 if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd) < 0) { 892 warnmsg(LOG_ERR, __func__, 893 "ioctl(SIOCGIFINFO_IN6)"); 894 exit(1); 895 } 896 if ((nd.ndi.flags & ND6_IFF_IFDISABLED)) 897 continue; 898 if (!(nd.ndi.flags & ND6_IFF_ACCEPT_RTADV)) 899 continue; 900 } 901 902 /* if we find multiple candidates, just warn. */ 903 if (n != 0 && dflag > 1) 904 warnmsg(LOG_WARNING, __func__, 905 "multiple interfaces found"); 906 907 a = realloc(argv, (n + 1) * sizeof(char *)); 908 if (a == NULL) { 909 warnmsg(LOG_ERR, __func__, "realloc"); 910 exit(1); 911 } 912 argv = a; 913 argv[n] = strdup(ifa->ifa_name); 914 if (!argv[n]) { 915 warnmsg(LOG_ERR, __func__, "malloc"); 916 exit(1); 917 } 918 n++; 919 } 920 921 if (n) { 922 a = realloc(argv, (n + 1) * sizeof(char *)); 923 if (a == NULL) { 924 warnmsg(LOG_ERR, __func__, "realloc"); 925 exit(1); 926 } 927 argv = a; 928 argv[n] = NULL; 929 930 if (dflag > 0) { 931 for (i = 0; i < n; i++) 932 warnmsg(LOG_WARNING, __func__, "probing %s", 933 argv[i]); 934 } 935 } 936 if (!Fflag) 937 close(s); 938 freeifaddrs(ifap); 939 return (argv); 940 } 941