1 1.83 andvar /* $NetBSD: rtadvd.c,v 1.83 2025/02/26 04:49:46 andvar Exp $ */ 2 1.30 rpaulo /* $KAME: rtadvd.c,v 1.92 2005/10/17 14:40:02 suz Exp $ */ 3 1.2 itojun 4 1.1 itojun /* 5 1.1 itojun * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 6 1.1 itojun * All rights reserved. 7 1.61 roy * 8 1.1 itojun * Redistribution and use in source and binary forms, with or without 9 1.1 itojun * modification, are permitted provided that the following conditions 10 1.1 itojun * are met: 11 1.1 itojun * 1. Redistributions of source code must retain the above copyright 12 1.1 itojun * notice, this list of conditions and the following disclaimer. 13 1.1 itojun * 2. Redistributions in binary form must reproduce the above copyright 14 1.1 itojun * notice, this list of conditions and the following disclaimer in the 15 1.1 itojun * documentation and/or other materials provided with the distribution. 16 1.1 itojun * 3. Neither the name of the project nor the names of its contributors 17 1.1 itojun * may be used to endorse or promote products derived from this software 18 1.1 itojun * without specific prior written permission. 19 1.61 roy * 20 1.1 itojun * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 21 1.1 itojun * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 1.1 itojun * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 1.1 itojun * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 24 1.1 itojun * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 1.1 itojun * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 1.1 itojun * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 1.1 itojun * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 1.1 itojun * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 1.1 itojun * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 1.1 itojun * SUCH DAMAGE. 31 1.1 itojun */ 32 1.1 itojun 33 1.1 itojun #include <sys/param.h> 34 1.1 itojun #include <sys/socket.h> 35 1.1 itojun #include <sys/uio.h> 36 1.1 itojun #include <sys/time.h> 37 1.11 itojun #include <sys/queue.h> 38 1.1 itojun 39 1.1 itojun #include <net/if.h> 40 1.1 itojun #include <net/route.h> 41 1.1 itojun #include <net/if_dl.h> 42 1.1 itojun #include <netinet/in.h> 43 1.1 itojun #include <netinet/ip6.h> 44 1.1 itojun #include <netinet6/ip6_var.h> 45 1.1 itojun #include <netinet/icmp6.h> 46 1.1 itojun 47 1.1 itojun #include <arpa/inet.h> 48 1.1 itojun 49 1.1 itojun #include <time.h> 50 1.1 itojun #include <unistd.h> 51 1.1 itojun #include <stdio.h> 52 1.1 itojun #include <err.h> 53 1.1 itojun #include <errno.h> 54 1.1 itojun #include <string.h> 55 1.1 itojun #include <stdlib.h> 56 1.1 itojun #include <syslog.h> 57 1.76 christos #include <signal.h> 58 1.57 christos #include <stdarg.h> 59 1.39 roy #ifdef __NetBSD__ 60 1.17 itojun #include <util.h> 61 1.39 roy #endif 62 1.25 itojun #include <poll.h> 63 1.44 roy #include <pwd.h> 64 1.17 itojun 65 1.1 itojun #include "rtadvd.h" 66 1.1 itojun #include "advcap.h" 67 1.1 itojun #include "timer.h" 68 1.1 itojun #include "if.h" 69 1.1 itojun #include "config.h" 70 1.9 itojun #include "dump.h" 71 1.57 christos #include "logit.h" 72 1.51 ozaki #include "prog_ops.h" 73 1.67 christos #include "expandm.h" 74 1.1 itojun 75 1.1 itojun struct msghdr rcvmhdr; 76 1.36 roy static unsigned char *rcvcmsgbuf; 77 1.6 itojun static size_t rcvcmsgbuflen; 78 1.39 roy static unsigned char *sndcmsgbuf; 79 1.6 itojun static size_t sndcmsgbuflen; 80 1.18 itojun volatile sig_atomic_t do_dump; 81 1.39 roy volatile sig_atomic_t do_reconf; 82 1.18 itojun volatile sig_atomic_t do_die; 83 1.1 itojun struct msghdr sndmhdr; 84 1.1 itojun struct iovec rcviov[2]; 85 1.1 itojun struct iovec sndiov[2]; 86 1.30 rpaulo struct sockaddr_in6 rcvfrom; 87 1.36 roy static const char *dumpfilename = "/var/run/rtadvd.dump"; /* XXX configurable */ 88 1.12 itojun int sock; 89 1.12 itojun int rtsock = -1; 90 1.71 roy int Cflag = 0, dflag = 0, sflag = 0, Dflag; 91 1.76 christos static int after_daemon = 0; 92 1.1 itojun 93 1.39 roy static char **if_argv; 94 1.39 roy static int if_argc; 95 1.39 roy 96 1.31 mrg char *conffile = NULL; 97 1.1 itojun 98 1.36 roy struct ralist_head_t ralist = TAILQ_HEAD_INITIALIZER(ralist); 99 1.36 roy 100 1.1 itojun struct nd_optlist { 101 1.36 roy TAILQ_ENTRY(nd_optlist) next; 102 1.1 itojun struct nd_opt_hdr *opt; 103 1.1 itojun }; 104 1.1 itojun union nd_opts { 105 1.18 itojun struct nd_opt_hdr *nd_opt_array[9]; 106 1.1 itojun struct { 107 1.1 itojun struct nd_opt_hdr *zero; 108 1.1 itojun struct nd_opt_hdr *src_lladdr; 109 1.1 itojun struct nd_opt_hdr *tgt_lladdr; 110 1.1 itojun struct nd_opt_prefix_info *pi; 111 1.1 itojun struct nd_opt_rd_hdr *rh; 112 1.1 itojun struct nd_opt_mtu *mtu; 113 1.36 roy TAILQ_HEAD(, nd_optlist) list; 114 1.1 itojun } nd_opt_each; 115 1.1 itojun }; 116 1.1 itojun #define nd_opts_src_lladdr nd_opt_each.src_lladdr 117 1.1 itojun #define nd_opts_tgt_lladdr nd_opt_each.tgt_lladdr 118 1.1 itojun #define nd_opts_pi nd_opt_each.pi 119 1.1 itojun #define nd_opts_rh nd_opt_each.rh 120 1.1 itojun #define nd_opts_mtu nd_opt_each.mtu 121 1.1 itojun #define nd_opts_list nd_opt_each.list 122 1.1 itojun 123 1.36 roy #define NDOPT_FLAG_SRCLINKADDR (1 << 0) 124 1.36 roy #define NDOPT_FLAG_TGTLINKADDR (1 << 1) 125 1.36 roy #define NDOPT_FLAG_PREFIXINFO (1 << 2) 126 1.36 roy #define NDOPT_FLAG_RDHDR (1 << 3) 127 1.36 roy #define NDOPT_FLAG_MTU (1 << 4) 128 1.36 roy #define NDOPT_FLAG_RDNSS (1 << 5) 129 1.36 roy #define NDOPT_FLAG_DNSSL (1 << 6) 130 1.36 roy 131 1.36 roy uint32_t ndopt_flags[] = { 132 1.36 roy [ND_OPT_SOURCE_LINKADDR] = NDOPT_FLAG_SRCLINKADDR, 133 1.36 roy [ND_OPT_TARGET_LINKADDR] = NDOPT_FLAG_TGTLINKADDR, 134 1.36 roy [ND_OPT_PREFIX_INFORMATION] = NDOPT_FLAG_PREFIXINFO, 135 1.36 roy [ND_OPT_REDIRECTED_HEADER] = NDOPT_FLAG_RDHDR, 136 1.36 roy [ND_OPT_MTU] = NDOPT_FLAG_MTU, 137 1.36 roy [ND_OPT_RDNSS] = NDOPT_FLAG_RDNSS, 138 1.36 roy [ND_OPT_DNSSL] = NDOPT_FLAG_DNSSL, 139 1.36 roy }; 140 1.36 roy 141 1.36 roy struct sockaddr_in6 sin6_linklocal_allnodes = { 142 1.36 roy .sin6_len = sizeof(sin6_linklocal_allnodes), 143 1.36 roy .sin6_family = AF_INET6, 144 1.36 roy .sin6_addr = IN6ADDR_LINKLOCAL_ALLNODES_INIT, 145 1.36 roy }; 146 1.38 christos #ifdef notdef 147 1.36 roy struct sockaddr_in6 sin6_linklocal_allrouters = { 148 1.36 roy .sin6_len = sizeof(sin6_linklocal_allrouters), 149 1.36 roy .sin6_family = AF_INET6, 150 1.36 roy .sin6_addr = IN6ADDR_LINKLOCAL_ALLROUTERS_INIT, 151 1.36 roy }; 152 1.38 christos #endif 153 1.36 roy struct sockaddr_in6 sin6_sitelocal_allrouters = { 154 1.36 roy .sin6_len = sizeof(sin6_sitelocal_allrouters), 155 1.36 roy .sin6_family = AF_INET6, 156 1.36 roy .sin6_addr = IN6ADDR_SITELOCAL_ALLROUTERS_INIT, 157 1.1 itojun }; 158 1.1 itojun 159 1.36 roy static void set_die(int); 160 1.41 roy static void die(void); 161 1.39 roy static void set_reconf(int); 162 1.36 roy static void sock_open(void); 163 1.36 roy static void rtsock_open(void); 164 1.36 roy static void rtadvd_input(void); 165 1.36 roy static void rs_input(int, struct nd_router_solicit *, 166 1.36 roy struct in6_pktinfo *, struct sockaddr_in6 *); 167 1.36 roy static void ra_input(int, struct nd_router_advert *, 168 1.36 roy struct in6_pktinfo *, struct sockaddr_in6 *); 169 1.65 roy static struct rainfo *ra_output(struct rainfo *, bool); 170 1.36 roy static int prefix_check(struct nd_opt_prefix_info *, struct rainfo *, 171 1.36 roy struct sockaddr_in6 *); 172 1.36 roy static int nd6_options(struct nd_opt_hdr *, int, union nd_opts *, uint32_t); 173 1.36 roy static void free_ndopts(union nd_opts *); 174 1.36 roy static void rtmsg_input(void); 175 1.36 roy static void rtadvd_set_dump_file(int); 176 1.1 itojun 177 1.1 itojun int 178 1.36 roy main(int argc, char *argv[]) 179 1.1 itojun { 180 1.23 mycroft struct pollfd set[2]; 181 1.47 roy struct timespec *timeout; 182 1.1 itojun int i, ch; 183 1.14 itojun int fflag = 0, logopt; 184 1.44 roy struct passwd *pw; 185 1.52 ozaki const char *pidfilepath = NULL; 186 1.63 roy pid_t pid; 187 1.1 itojun 188 1.1 itojun /* get command line options and arguments */ 189 1.74 wiz #define OPTIONS "Cc:dDfp:s" 190 1.7 itojun while ((ch = getopt(argc, argv, OPTIONS)) != -1) { 191 1.7 itojun #undef OPTIONS 192 1.14 itojun switch (ch) { 193 1.14 itojun case 'c': 194 1.14 itojun conffile = optarg; 195 1.14 itojun break; 196 1.71 roy case 'C': 197 1.71 roy Cflag++; 198 1.71 roy break; 199 1.14 itojun case 'd': 200 1.57 christos dflag++; 201 1.14 itojun break; 202 1.14 itojun case 'D': 203 1.57 christos Dflag++; 204 1.14 itojun break; 205 1.14 itojun case 'f': 206 1.14 itojun fflag = 1; 207 1.14 itojun break; 208 1.52 ozaki case 'p': 209 1.52 ozaki pidfilepath = optarg; 210 1.52 ozaki break; 211 1.14 itojun case 's': 212 1.14 itojun sflag = 1; 213 1.14 itojun break; 214 1.1 itojun } 215 1.1 itojun } 216 1.1 itojun argc -= optind; 217 1.1 itojun argv += optind; 218 1.1 itojun if (argc == 0) { 219 1.76 christos fprintf(stderr, "Usage: %s [-CDdfs] [-c conffile]" 220 1.74 wiz " [-p pidfile] interface ...\n", getprogname()); 221 1.54 christos return EXIT_FAILURE; 222 1.1 itojun } 223 1.1 itojun 224 1.63 roy if ((pid = pidfile_lock(pidfilepath)) != 0) { 225 1.76 christos if (pid == -1) { 226 1.63 roy logit(LOG_ERR, "pidfile_lock: %m"); 227 1.76 christos } else { 228 1.63 roy logit(LOG_ERR, "Another instance of `%s' is running " 229 1.63 roy "(pid %d); exiting.", getprogname(), pid); 230 1.63 roy } 231 1.78 christos return EXIT_FAILURE; 232 1.63 roy } 233 1.63 roy 234 1.63 roy if (prog_init && prog_init() == -1) 235 1.54 christos err(EXIT_FAILURE, "init failed"); 236 1.51 ozaki 237 1.14 itojun logopt = LOG_NDELAY | LOG_PID; 238 1.14 itojun if (fflag) 239 1.14 itojun logopt |= LOG_PERROR; 240 1.14 itojun openlog("rtadvd", logopt, LOG_DAEMON); 241 1.14 itojun 242 1.1 itojun /* set log level */ 243 1.1 itojun if (dflag == 0) 244 1.1 itojun (void)setlogmask(LOG_UPTO(LOG_ERR)); 245 1.1 itojun if (dflag == 1) 246 1.1 itojun (void)setlogmask(LOG_UPTO(LOG_INFO)); 247 1.1 itojun 248 1.44 roy errno = 0; /* Ensure errno is 0 so we know if getpwnam errors or not */ 249 1.44 roy if ((pw = getpwnam(RTADVD_USER)) == NULL) { 250 1.44 roy if (errno == 0) 251 1.57 christos logit(LOG_ERR, 252 1.44 roy "user %s does not exist, aborting", 253 1.44 roy RTADVD_USER); 254 1.44 roy else 255 1.57 christos logit(LOG_ERR, "getpwnam: %s: %m", RTADVD_USER); 256 1.54 christos return EXIT_FAILURE; 257 1.44 roy } 258 1.44 roy 259 1.1 itojun /* timer initialization */ 260 1.1 itojun rtadvd_timer_init(); 261 1.1 itojun 262 1.39 roy if_argc = argc; 263 1.39 roy if_argv = argv; 264 1.1 itojun while (argc--) 265 1.39 roy getconfig(*argv++, 1); 266 1.1 itojun 267 1.63 roy if (!fflag) { 268 1.51 ozaki prog_daemon(1, 0); 269 1.76 christos after_daemon = 1; 270 1.63 roy if (pidfile_lock(pidfilepath) != 0) 271 1.63 roy logit(LOG_ERR, " pidfile_lock: %m"); 272 1.63 roy } 273 1.13 itojun 274 1.13 itojun sock_open(); 275 1.1 itojun 276 1.23 mycroft set[0].fd = sock; 277 1.23 mycroft set[0].events = POLLIN; 278 1.12 itojun if (sflag == 0) { 279 1.12 itojun rtsock_open(); 280 1.23 mycroft set[1].fd = rtsock; 281 1.23 mycroft set[1].events = POLLIN; 282 1.12 itojun } else 283 1.24 mycroft set[1].fd = -1; 284 1.19 itojun 285 1.57 christos logit(LOG_INFO, "dropping privileges to %s", RTADVD_USER); 286 1.82 christos tzset(); 287 1.51 ozaki if (prog_chroot(pw->pw_dir) == -1) { 288 1.57 christos logit(LOG_ERR, "chroot: %s: %m", pw->pw_dir); 289 1.54 christos return EXIT_FAILURE; 290 1.44 roy } 291 1.51 ozaki if (prog_chdir("/") == -1) { 292 1.57 christos logit(LOG_ERR, "chdir: /: %m"); 293 1.54 christos return EXIT_FAILURE; 294 1.44 roy } 295 1.51 ozaki if (prog_setgroups(1, &pw->pw_gid) == -1 || 296 1.51 ozaki prog_setgid(pw->pw_gid) == -1 || 297 1.51 ozaki prog_setuid(pw->pw_uid) == -1) 298 1.44 roy { 299 1.57 christos logit(LOG_ERR, "failed to drop privileges: %m"); 300 1.54 christos return EXIT_FAILURE; 301 1.44 roy } 302 1.44 roy 303 1.41 roy signal(SIGINT, set_die); 304 1.22 itojun signal(SIGTERM, set_die); 305 1.39 roy signal(SIGHUP, set_reconf); 306 1.22 itojun signal(SIGUSR1, rtadvd_set_dump_file); 307 1.5 itojun 308 1.23 mycroft for (;;) { 309 1.9 itojun if (do_dump) { /* SIGUSR1 */ 310 1.9 itojun do_dump = 0; 311 1.9 itojun rtadvd_dump_file(dumpfilename); 312 1.9 itojun } 313 1.9 itojun 314 1.39 roy if (do_reconf) { /* SIGHUP */ 315 1.39 roy do_reconf = 0; 316 1.57 christos logit(LOG_INFO, "%s: reloading config on SIGHUP", 317 1.39 roy __func__); 318 1.39 roy argc = if_argc; 319 1.39 roy argv = if_argv; 320 1.39 roy while (argc--) 321 1.39 roy getconfig(*argv++, 0); 322 1.39 roy } 323 1.39 roy 324 1.47 roy /* timer expiration check and reset the timer */ 325 1.47 roy timeout = rtadvd_check_timer(); 326 1.47 roy 327 1.11 itojun if (do_die) { 328 1.11 itojun die(); 329 1.11 itojun /*NOTREACHED*/ 330 1.11 itojun } 331 1.11 itojun 332 1.10 itojun if (timeout != NULL) { 333 1.57 christos logit(LOG_DEBUG, 334 1.56 christos "%s: set timer to %jd:%jd. waiting for " 335 1.21 itojun "inputs or timeout", __func__, 336 1.54 christos (intmax_t)timeout->tv_sec, 337 1.54 christos (intmax_t)timeout->tv_nsec); 338 1.10 itojun } else { 339 1.57 christos logit(LOG_DEBUG, 340 1.56 christos "%s: there's no timer. waiting for inputs", 341 1.21 itojun __func__); 342 1.10 itojun } 343 1.1 itojun 344 1.51 ozaki if ((i = prog_poll(set, 2, timeout ? (timeout->tv_sec * 1000 + 345 1.56 christos (timeout->tv_nsec + 999999) / 1000000) : INFTIM)) == -1) 346 1.47 roy { 347 1.9 itojun /* EINTR would occur upon SIGUSR1 for status dump */ 348 1.69 christos if (errno == EINTR) { 349 1.69 christos if (do_die) 350 1.69 christos die(); 351 1.57 christos continue; 352 1.69 christos } 353 1.57 christos 354 1.57 christos logit(LOG_ERR, "%s: poll: %m", __func__); 355 1.57 christos if (Dflag) 356 1.57 christos exit(1); 357 1.1 itojun } 358 1.1 itojun if (i == 0) /* timeout */ 359 1.1 itojun continue; 360 1.23 mycroft if (rtsock != -1 && set[1].revents & POLLIN) 361 1.1 itojun rtmsg_input(); 362 1.23 mycroft if (set[0].revents & POLLIN) 363 1.1 itojun rtadvd_input(); 364 1.1 itojun } 365 1.54 christos return EXIT_SUCCESS; /* NOTREACHED */ 366 1.1 itojun } 367 1.1 itojun 368 1.1 itojun static void 369 1.39 roy rtadvd_set_dump_file(__unused int sig) 370 1.9 itojun { 371 1.39 roy 372 1.9 itojun do_dump = 1; 373 1.9 itojun } 374 1.9 itojun 375 1.9 itojun static void 376 1.39 roy set_reconf(__unused int sig) 377 1.5 itojun { 378 1.39 roy 379 1.39 roy do_reconf = 1; 380 1.39 roy } 381 1.39 roy 382 1.39 roy static void 383 1.39 roy set_die(__unused int sig) 384 1.39 roy { 385 1.39 roy 386 1.11 itojun do_die = 1; 387 1.11 itojun } 388 1.11 itojun 389 1.11 itojun static void 390 1.36 roy die(void) 391 1.11 itojun { 392 1.41 roy static int waiting; 393 1.41 roy struct rainfo *rai, *ran; 394 1.39 roy struct rdnss *rdnss; 395 1.39 roy struct dnssl *dnssl; 396 1.5 itojun 397 1.41 roy if (waiting) { 398 1.41 roy if (TAILQ_FIRST(&ralist)) { 399 1.57 christos logit(LOG_INFO, 400 1.56 christos "%s: waiting for expiration of all RA timers", 401 1.41 roy __func__); 402 1.41 roy return; 403 1.41 roy } 404 1.57 christos logit(LOG_NOTICE, "%s: gracefully terminated", __func__); 405 1.41 roy free(rcvcmsgbuf); 406 1.41 roy free(sndcmsgbuf); 407 1.54 christos exit(EXIT_SUCCESS); 408 1.41 roy /* NOT REACHED */ 409 1.41 roy } 410 1.41 roy 411 1.43 roy if (TAILQ_FIRST(&ralist) == NULL) { 412 1.57 christos logit(LOG_NOTICE, "%s: gracefully terminated", __func__); 413 1.54 christos exit(EXIT_SUCCESS); 414 1.43 roy /* NOT REACHED */ 415 1.43 roy } 416 1.43 roy 417 1.41 roy waiting = 1; 418 1.57 christos logit(LOG_NOTICE, "%s: final RA transmission started", __func__); 419 1.41 roy 420 1.41 roy TAILQ_FOREACH_SAFE(rai, &ralist, next, ran) { 421 1.41 roy if (rai->leaving) { 422 1.41 roy TAILQ_REMOVE(&ralist, rai, next); 423 1.41 roy TAILQ_INSERT_HEAD(&ralist, rai->leaving, next); 424 1.41 roy rai->leaving->leaving = rai->leaving; 425 1.41 roy rai->leaving->leaving_for = rai->leaving; 426 1.41 roy free_rainfo(rai); 427 1.41 roy continue; 428 1.41 roy } 429 1.39 roy rai->lifetime = 0; 430 1.39 roy TAILQ_FOREACH(rdnss, &rai->rdnss, next) 431 1.39 roy rdnss->lifetime = 0; 432 1.39 roy TAILQ_FOREACH(dnssl, &rai->dnssl, next) 433 1.39 roy dnssl->lifetime = 0; 434 1.39 roy make_packet(rai); 435 1.41 roy rai->leaving = rai; 436 1.41 roy rai->leaving_for = rai; 437 1.41 roy rai->initcounter = MAX_INITIAL_RTR_ADVERTISEMENTS; 438 1.41 roy rai->mininterval = MIN_DELAY_BETWEEN_RAS; 439 1.41 roy rai->maxinterval = MIN_DELAY_BETWEEN_RAS; 440 1.41 roy rai->leaving_adv = MAX_FINAL_RTR_ADVERTISEMENTS; 441 1.65 roy ra_output(rai, false); 442 1.54 christos ra_timer_update(rai, &rai->timer->tm); 443 1.41 roy rtadvd_set_timer(&rai->timer->tm, rai->timer); 444 1.5 itojun } 445 1.69 christos exit(EXIT_SUCCESS); 446 1.5 itojun } 447 1.5 itojun 448 1.5 itojun static void 449 1.70 roy ra_timer_reset(struct rainfo *rai) 450 1.70 roy { 451 1.70 roy 452 1.70 roy rtadvd_remove_timer(&rai->timer); 453 1.70 roy rai->timer = rtadvd_add_timer(ra_timeout, ra_timer_update, rai, rai); 454 1.70 roy ra_timer_update(rai, &rai->timer->tm); 455 1.70 roy rtadvd_set_timer(&rai->timer->tm, rai->timer); 456 1.70 roy rtadvd_remove_timer(&rai->timer_sol); 457 1.70 roy rai->timer_sol = rtadvd_add_timer(ra_timeout_sol, NULL, rai, NULL); 458 1.70 roy } 459 1.70 roy 460 1.70 roy static void 461 1.36 roy rtmsg_input(void) 462 1.1 itojun { 463 1.9 itojun int n, type, ifindex = 0, plen; 464 1.2 itojun size_t len; 465 1.32 tron union rt_msghdr_buf { 466 1.32 tron struct rt_msghdr rt_msghdr; 467 1.32 tron char data[2048]; 468 1.32 tron } buffer; 469 1.39 roy char *msg, *next, *lim, **argv; 470 1.31 mrg char ifname[IF_NAMESIZE]; 471 1.1 itojun struct prefix *prefix; 472 1.1 itojun struct rainfo *rai; 473 1.80 christos const struct in6_addr *addr; 474 1.1 itojun char addrbuf[INET6_ADDRSTRLEN]; 475 1.39 roy int prefixchange = 0, argc; 476 1.1 itojun 477 1.39 roy memset(&buffer, 0, sizeof(buffer)); 478 1.51 ozaki n = prog_read(rtsock, &buffer, sizeof(buffer)); 479 1.41 roy 480 1.41 roy /* We read the buffer first to clear the FD */ 481 1.41 roy if (do_die) 482 1.41 roy return; 483 1.41 roy 484 1.32 tron msg = buffer.data; 485 1.1 itojun if (dflag > 1) { 486 1.57 christos logit(LOG_DEBUG, "%s: received a routing message " 487 1.80 christos "(type = %d [%s], len = %d)", __func__, rtmsg_type(msg), 488 1.80 christos rtmsg_typestr(msg), rtmsg_len(msg)); 489 1.1 itojun } 490 1.1 itojun if (n > rtmsg_len(msg)) { 491 1.1 itojun /* 492 1.1 itojun * This usually won't happen for messages received on 493 1.10 itojun * a routing socket. 494 1.1 itojun */ 495 1.1 itojun if (dflag > 1) 496 1.57 christos logit(LOG_DEBUG, 497 1.56 christos "%s: received data length is larger than " 498 1.14 itojun "1st routing message len. multiple messages? " 499 1.14 itojun "read %d bytes, but 1st msg len = %d", 500 1.21 itojun __func__, n, rtmsg_len(msg)); 501 1.1 itojun #if 0 502 1.1 itojun /* adjust length */ 503 1.1 itojun n = rtmsg_len(msg); 504 1.1 itojun #endif 505 1.1 itojun } 506 1.1 itojun 507 1.1 itojun lim = msg + n; 508 1.1 itojun for (next = msg; next < lim; next += len) { 509 1.10 itojun int oldifflags; 510 1.10 itojun 511 1.1 itojun next = get_next_msg(next, lim, 0, &len, 512 1.1 itojun RTADV_TYPE2BITMASK(RTM_ADD) | 513 1.1 itojun RTADV_TYPE2BITMASK(RTM_DELETE) | 514 1.1 itojun RTADV_TYPE2BITMASK(RTM_NEWADDR) | 515 1.1 itojun RTADV_TYPE2BITMASK(RTM_DELADDR) | 516 1.39 roy #ifdef RTM_IFANNOUNCE 517 1.39 roy RTADV_TYPE2BITMASK(RTM_IFANNOUNCE) | 518 1.39 roy #endif 519 1.1 itojun RTADV_TYPE2BITMASK(RTM_IFINFO)); 520 1.1 itojun if (len == 0) 521 1.1 itojun break; 522 1.1 itojun type = rtmsg_type(next); 523 1.1 itojun switch (type) { 524 1.1 itojun case RTM_ADD: 525 1.1 itojun case RTM_DELETE: 526 1.1 itojun ifindex = get_rtm_ifindex(next); 527 1.1 itojun break; 528 1.1 itojun case RTM_NEWADDR: 529 1.1 itojun case RTM_DELADDR: 530 1.1 itojun ifindex = get_ifam_ifindex(next); 531 1.1 itojun break; 532 1.39 roy #ifdef RTM_IFANNOUNCE 533 1.39 roy case RTM_IFANNOUNCE: 534 1.39 roy ifindex = get_ifan_ifindex(next); 535 1.39 roy if (get_ifan_what(next) == IFAN_ARRIVAL) { 536 1.57 christos logit(LOG_DEBUG, 537 1.61 roy "%s: interface %s arrived", 538 1.39 roy __func__, 539 1.39 roy if_indextoname(ifindex, ifname)); 540 1.39 roy if (if_argc == 0) { 541 1.39 roy getconfig(ifname, 0); 542 1.39 roy continue; 543 1.39 roy } 544 1.39 roy argc = if_argc; 545 1.39 roy argv = if_argv; 546 1.39 roy while (argc--) { 547 1.39 roy if (strcmp(ifname, *argv++) == 0) { 548 1.39 roy getconfig(ifname, 0); 549 1.39 roy break; 550 1.39 roy } 551 1.39 roy } 552 1.39 roy continue; 553 1.39 roy } 554 1.39 roy break; 555 1.39 roy #endif 556 1.1 itojun case RTM_IFINFO: 557 1.1 itojun ifindex = get_ifm_ifindex(next); 558 1.1 itojun break; 559 1.1 itojun default: 560 1.1 itojun /* should not reach here */ 561 1.1 itojun if (dflag > 1) { 562 1.57 christos logit(LOG_DEBUG, "%s: unknown rtmsg %d on %s", 563 1.56 christos __func__, type, 564 1.1 itojun if_indextoname(ifindex, ifname)); 565 1.1 itojun } 566 1.10 itojun continue; 567 1.1 itojun } 568 1.1 itojun 569 1.1 itojun if ((rai = if_indextorainfo(ifindex)) == NULL) { 570 1.1 itojun if (dflag > 1) { 571 1.57 christos logit(LOG_DEBUG, 572 1.56 christos "%s: route changed on " 573 1.39 roy "non advertising interface %s (%d)", 574 1.21 itojun __func__, 575 1.39 roy if_indextoname(ifindex, ifname), 576 1.39 roy ifindex); 577 1.1 itojun } 578 1.10 itojun continue; 579 1.1 itojun } 580 1.39 roy oldifflags = rai->ifflags; 581 1.1 itojun 582 1.14 itojun switch (type) { 583 1.14 itojun case RTM_ADD: 584 1.14 itojun /* init ifflags because it may have changed */ 585 1.39 roy rai->ifflags = if_getflags(ifindex, rai->ifflags); 586 1.14 itojun 587 1.14 itojun if (sflag) 588 1.14 itojun break; /* we aren't interested in prefixes */ 589 1.14 itojun 590 1.14 itojun addr = get_addr(msg); 591 1.14 itojun plen = get_prefixlen(msg); 592 1.14 itojun /* sanity check for plen */ 593 1.14 itojun /* as RFC2373, prefixlen is at least 4 */ 594 1.14 itojun if (plen < 4 || plen > 127) { 595 1.57 christos logit(LOG_INFO, "%s: new interface route's" 596 1.14 itojun "plen %d is invalid for a prefix", 597 1.21 itojun __func__, plen); 598 1.14 itojun break; 599 1.14 itojun } 600 1.14 itojun prefix = find_prefix(rai, addr, plen); 601 1.14 itojun if (prefix) { 602 1.30 rpaulo if (prefix->timer) { 603 1.30 rpaulo /* 604 1.30 rpaulo * If the prefix has been invalidated, 605 1.30 rpaulo * make it available again. 606 1.30 rpaulo */ 607 1.30 rpaulo update_prefix(prefix); 608 1.30 rpaulo prefixchange = 1; 609 1.30 rpaulo } else if (dflag > 1) { 610 1.57 christos logit(LOG_DEBUG, 611 1.56 christos "%s: new prefix(%s/%d) " 612 1.14 itojun "added on %s, " 613 1.14 itojun "but it was already in list", 614 1.21 itojun __func__, 615 1.14 itojun inet_ntop(AF_INET6, addr, 616 1.14 itojun (char *)addrbuf, INET6_ADDRSTRLEN), 617 1.14 itojun plen, rai->ifname); 618 1.14 itojun } 619 1.10 itojun break; 620 1.14 itojun } 621 1.73 roy add_prefix(rai, ifindex, addr, plen); 622 1.30 rpaulo prefixchange = 1; 623 1.14 itojun break; 624 1.14 itojun case RTM_DELETE: 625 1.14 itojun /* init ifflags because it may have changed */ 626 1.39 roy rai->ifflags = if_getflags(ifindex, rai->ifflags); 627 1.14 itojun 628 1.14 itojun if (sflag) 629 1.10 itojun break; 630 1.14 itojun 631 1.14 itojun addr = get_addr(msg); 632 1.14 itojun plen = get_prefixlen(msg); 633 1.14 itojun /* sanity check for plen */ 634 1.14 itojun /* as RFC2373, prefixlen is at least 4 */ 635 1.14 itojun if (plen < 4 || plen > 127) { 636 1.57 christos logit(LOG_INFO, 637 1.56 christos "%s: deleted interface route's " 638 1.14 itojun "plen %d is invalid for a prefix", 639 1.21 itojun __func__, plen); 640 1.14 itojun break; 641 1.14 itojun } 642 1.14 itojun prefix = find_prefix(rai, addr, plen); 643 1.14 itojun if (prefix == NULL) { 644 1.14 itojun if (dflag > 1) { 645 1.57 christos logit(LOG_DEBUG, 646 1.56 christos "%s: prefix(%s/%d) was " 647 1.14 itojun "deleted on %s, " 648 1.14 itojun "but it was not in list", 649 1.21 itojun __func__, 650 1.14 itojun inet_ntop(AF_INET6, addr, 651 1.14 itojun (char *)addrbuf, INET6_ADDRSTRLEN), 652 1.14 itojun plen, rai->ifname); 653 1.14 itojun } 654 1.14 itojun break; 655 1.14 itojun } 656 1.30 rpaulo invalidate_prefix(prefix); 657 1.30 rpaulo prefixchange = 1; 658 1.14 itojun break; 659 1.1 itojun case RTM_NEWADDR: 660 1.1 itojun case RTM_DELADDR: 661 1.14 itojun /* init ifflags because it may have changed */ 662 1.39 roy rai->ifflags = if_getflags(ifindex, rai->ifflags); 663 1.14 itojun break; 664 1.1 itojun case RTM_IFINFO: 665 1.39 roy rai->ifflags = get_ifm_flags(next); 666 1.14 itojun break; 667 1.39 roy #ifdef RTM_IFANNOUNCE 668 1.39 roy case RTM_IFANNOUNCE: 669 1.39 roy if (get_ifan_what(next) == IFAN_DEPARTURE) { 670 1.57 christos logit(LOG_DEBUG, 671 1.61 roy "%s: interface %s departed", 672 1.39 roy __func__, rai->ifname); 673 1.39 roy TAILQ_REMOVE(&ralist, rai, next); 674 1.39 roy if (rai->leaving) 675 1.39 roy free_rainfo(rai->leaving); 676 1.39 roy free_rainfo(rai); 677 1.39 roy continue; 678 1.39 roy } 679 1.39 roy break; 680 1.39 roy #endif 681 1.1 itojun default: 682 1.1 itojun /* should not reach here */ 683 1.1 itojun if (dflag > 1) { 684 1.57 christos logit(LOG_DEBUG, 685 1.56 christos "%s: unknown rtmsg %d on %s", 686 1.56 christos __func__, type, 687 1.14 itojun if_indextoname(ifindex, ifname)); 688 1.1 itojun } 689 1.1 itojun return; 690 1.1 itojun } 691 1.10 itojun 692 1.10 itojun /* check if an interface flag is changed */ 693 1.10 itojun if ((oldifflags & IFF_UP) != 0 && /* UP to DOWN */ 694 1.39 roy (rai->ifflags & IFF_UP) == 0) { 695 1.57 christos logit(LOG_INFO, 696 1.56 christos "%s: interface %s becomes down. stop timer.", 697 1.21 itojun __func__, rai->ifname); 698 1.10 itojun rtadvd_remove_timer(&rai->timer); 699 1.18 itojun } else if ((oldifflags & IFF_UP) == 0 && /* DOWN to UP */ 700 1.39 roy (rai->ifflags & IFF_UP) != 0) { 701 1.57 christos logit(LOG_INFO, 702 1.56 christos "%s: interface %s becomes up. restart timer.", 703 1.21 itojun __func__, rai->ifname); 704 1.10 itojun 705 1.10 itojun rai->initcounter = 0; /* reset the counter */ 706 1.10 itojun rai->waiting = 0; /* XXX */ 707 1.70 roy ra_timer_reset(rai); 708 1.39 roy } else if (prefixchange && rai->ifflags & IFF_UP) { 709 1.30 rpaulo /* 710 1.30 rpaulo * An advertised prefix has been added or invalidated. 711 1.30 rpaulo * Will notice the change in a short delay. 712 1.30 rpaulo */ 713 1.30 rpaulo rai->initcounter = 0; 714 1.65 roy ra_timer_set_short_delay(rai, rai->timer); 715 1.10 itojun } 716 1.1 itojun } 717 1.1 itojun 718 1.1 itojun return; 719 1.1 itojun } 720 1.1 itojun 721 1.1 itojun void 722 1.36 roy rtadvd_input(void) 723 1.1 itojun { 724 1.36 roy ssize_t i; 725 1.1 itojun int *hlimp = NULL; 726 1.1 itojun struct icmp6_hdr *icp; 727 1.1 itojun int ifindex = 0; 728 1.1 itojun struct cmsghdr *cm; 729 1.1 itojun struct in6_pktinfo *pi = NULL; 730 1.31 mrg char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ]; 731 1.39 roy struct rainfo *rai; 732 1.1 itojun 733 1.1 itojun /* 734 1.1 itojun * Get message. We reset msg_controllen since the field could 735 1.1 itojun * be modified if we had received a message before setting 736 1.1 itojun * receive options. 737 1.1 itojun */ 738 1.6 itojun rcvmhdr.msg_controllen = rcvcmsgbuflen; 739 1.56 christos if ((i = prog_recvmsg(sock, &rcvmhdr, 0)) == -1) 740 1.1 itojun return; 741 1.1 itojun 742 1.41 roy /* We read the buffer first to clear the FD */ 743 1.41 roy if (do_die) 744 1.41 roy return; 745 1.41 roy 746 1.1 itojun /* extract optional information via Advanced API */ 747 1.1 itojun for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&rcvmhdr); 748 1.1 itojun cm; 749 1.1 itojun cm = (struct cmsghdr *)CMSG_NXTHDR(&rcvmhdr, cm)) { 750 1.1 itojun if (cm->cmsg_level == IPPROTO_IPV6 && 751 1.1 itojun cm->cmsg_type == IPV6_PKTINFO && 752 1.1 itojun cm->cmsg_len == CMSG_LEN(sizeof(struct in6_pktinfo))) { 753 1.1 itojun pi = (struct in6_pktinfo *)(CMSG_DATA(cm)); 754 1.1 itojun ifindex = pi->ipi6_ifindex; 755 1.1 itojun } 756 1.1 itojun if (cm->cmsg_level == IPPROTO_IPV6 && 757 1.1 itojun cm->cmsg_type == IPV6_HOPLIMIT && 758 1.1 itojun cm->cmsg_len == CMSG_LEN(sizeof(int))) 759 1.1 itojun hlimp = (int *)CMSG_DATA(cm); 760 1.1 itojun } 761 1.1 itojun if (ifindex == 0) { 762 1.57 christos logit(LOG_ERR, 763 1.56 christos "%s: failed to get receiving interface", 764 1.21 itojun __func__); 765 1.1 itojun return; 766 1.1 itojun } 767 1.1 itojun if (hlimp == NULL) { 768 1.57 christos logit(LOG_ERR, 769 1.56 christos "%s: failed to get receiving hop limit", 770 1.21 itojun __func__); 771 1.1 itojun return; 772 1.1 itojun } 773 1.1 itojun 774 1.39 roy if ((rai = if_indextorainfo(pi->ipi6_ifindex)) == NULL) { 775 1.39 roy if (dflag > 1) { 776 1.57 christos logit(LOG_DEBUG, 777 1.56 christos "%s: received data for non advertising " 778 1.39 roy "interface (%s)", 779 1.39 roy __func__, 780 1.39 roy if_indextoname(pi->ipi6_ifindex, ifnamebuf)); 781 1.39 roy } 782 1.39 roy return; 783 1.39 roy } 784 1.10 itojun /* 785 1.10 itojun * If we happen to receive data on an interface which is now down, 786 1.10 itojun * just discard the data. 787 1.10 itojun */ 788 1.39 roy if ((rai->ifflags & IFF_UP) == 0) { 789 1.57 christos logit(LOG_INFO, 790 1.56 christos "%s: received data on a disabled interface (%s)", 791 1.21 itojun __func__, 792 1.10 itojun if_indextoname(pi->ipi6_ifindex, ifnamebuf)); 793 1.10 itojun return; 794 1.10 itojun } 795 1.10 itojun 796 1.36 roy if ((size_t)i < sizeof(struct icmp6_hdr)) { 797 1.57 christos logit(LOG_ERR, 798 1.56 christos "%s: packet size(%zd) is too short", 799 1.21 itojun __func__, i); 800 1.1 itojun return; 801 1.1 itojun } 802 1.1 itojun 803 1.1 itojun icp = (struct icmp6_hdr *)rcvmhdr.msg_iov[0].iov_base; 804 1.1 itojun 805 1.14 itojun switch (icp->icmp6_type) { 806 1.14 itojun case ND_ROUTER_SOLICIT: 807 1.14 itojun /* 808 1.14 itojun * Message verification - RFC-2461 6.1.1 809 1.14 itojun * XXX: these checks must be done in the kernel as well, 810 1.14 itojun * but we can't completely rely on them. 811 1.14 itojun */ 812 1.14 itojun if (*hlimp != 255) { 813 1.57 christos logit(LOG_NOTICE, 814 1.56 christos "%s: RS with invalid hop limit(%d) " 815 1.14 itojun "received from %s on %s", 816 1.21 itojun __func__, *hlimp, 817 1.30 rpaulo inet_ntop(AF_INET6, &rcvfrom.sin6_addr, ntopbuf, 818 1.14 itojun INET6_ADDRSTRLEN), 819 1.14 itojun if_indextoname(pi->ipi6_ifindex, ifnamebuf)); 820 1.14 itojun return; 821 1.14 itojun } 822 1.14 itojun if (icp->icmp6_code) { 823 1.57 christos logit(LOG_NOTICE, 824 1.56 christos "%s: RS with invalid ICMP6 code(%d) " 825 1.14 itojun "received from %s on %s", 826 1.21 itojun __func__, icp->icmp6_code, 827 1.30 rpaulo inet_ntop(AF_INET6, &rcvfrom.sin6_addr, ntopbuf, 828 1.14 itojun INET6_ADDRSTRLEN), 829 1.14 itojun if_indextoname(pi->ipi6_ifindex, ifnamebuf)); 830 1.14 itojun return; 831 1.14 itojun } 832 1.36 roy if ((size_t)i < sizeof(struct nd_router_solicit)) { 833 1.57 christos logit(LOG_NOTICE, 834 1.56 christos "%s: RS from %s on %s does not have enough " 835 1.36 roy "length (len = %zd)", 836 1.21 itojun __func__, 837 1.30 rpaulo inet_ntop(AF_INET6, &rcvfrom.sin6_addr, ntopbuf, 838 1.14 itojun INET6_ADDRSTRLEN), 839 1.14 itojun if_indextoname(pi->ipi6_ifindex, ifnamebuf), i); 840 1.14 itojun return; 841 1.14 itojun } 842 1.30 rpaulo rs_input(i, (struct nd_router_solicit *)icp, pi, &rcvfrom); 843 1.14 itojun break; 844 1.14 itojun case ND_ROUTER_ADVERT: 845 1.14 itojun /* 846 1.14 itojun * Message verification - RFC-2461 6.1.2 847 1.14 itojun * XXX: there's a same dilemma as above... 848 1.14 itojun */ 849 1.14 itojun if (*hlimp != 255) { 850 1.57 christos logit(LOG_NOTICE, 851 1.56 christos "%s: RA with invalid hop limit(%d) " 852 1.14 itojun "received from %s on %s", 853 1.21 itojun __func__, *hlimp, 854 1.30 rpaulo inet_ntop(AF_INET6, &rcvfrom.sin6_addr, ntopbuf, 855 1.14 itojun INET6_ADDRSTRLEN), 856 1.14 itojun if_indextoname(pi->ipi6_ifindex, ifnamebuf)); 857 1.14 itojun return; 858 1.14 itojun } 859 1.14 itojun if (icp->icmp6_code) { 860 1.57 christos logit(LOG_NOTICE, 861 1.56 christos "%s: RA with invalid ICMP6 code(%d) " 862 1.14 itojun "received from %s on %s", 863 1.21 itojun __func__, icp->icmp6_code, 864 1.30 rpaulo inet_ntop(AF_INET6, &rcvfrom.sin6_addr, ntopbuf, 865 1.14 itojun INET6_ADDRSTRLEN), 866 1.14 itojun if_indextoname(pi->ipi6_ifindex, ifnamebuf)); 867 1.14 itojun return; 868 1.14 itojun } 869 1.36 roy if ((size_t)i < sizeof(struct nd_router_advert)) { 870 1.57 christos logit(LOG_NOTICE, 871 1.56 christos "%s: RA from %s on %s does not have enough " 872 1.36 roy "length (len = %zd)", 873 1.21 itojun __func__, 874 1.30 rpaulo inet_ntop(AF_INET6, &rcvfrom.sin6_addr, ntopbuf, 875 1.14 itojun INET6_ADDRSTRLEN), 876 1.14 itojun if_indextoname(pi->ipi6_ifindex, ifnamebuf), i); 877 1.14 itojun return; 878 1.14 itojun } 879 1.30 rpaulo ra_input(i, (struct nd_router_advert *)icp, pi, &rcvfrom); 880 1.14 itojun break; 881 1.14 itojun default: 882 1.14 itojun /* 883 1.14 itojun * Note that this case is POSSIBLE, especially just 884 1.14 itojun * after invocation of the daemon. This is because we 885 1.14 itojun * could receive message after opening the socket and 886 1.14 itojun * before setting ICMP6 type filter(see sock_open()). 887 1.14 itojun */ 888 1.57 christos logit(LOG_ERR, "%s: invalid icmp type(%d)", 889 1.21 itojun __func__, icp->icmp6_type); 890 1.14 itojun return; 891 1.1 itojun } 892 1.1 itojun } 893 1.1 itojun 894 1.1 itojun static void 895 1.1 itojun rs_input(int len, struct nd_router_solicit *rs, 896 1.1 itojun struct in6_pktinfo *pi, struct sockaddr_in6 *from) 897 1.1 itojun { 898 1.31 mrg char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ]; 899 1.1 itojun union nd_opts ndopts; 900 1.39 roy struct rainfo *rai; 901 1.30 rpaulo struct soliciter *sol; 902 1.1 itojun 903 1.57 christos logit(LOG_DEBUG, 904 1.56 christos "%s: RS received from %s on %s", 905 1.21 itojun __func__, 906 1.1 itojun inet_ntop(AF_INET6, &from->sin6_addr, 907 1.1 itojun ntopbuf, INET6_ADDRSTRLEN), 908 1.1 itojun if_indextoname(pi->ipi6_ifindex, ifnamebuf)); 909 1.1 itojun 910 1.1 itojun /* ND option check */ 911 1.1 itojun memset(&ndopts, 0, sizeof(ndopts)); 912 1.36 roy TAILQ_INIT(&ndopts.nd_opts_list); 913 1.1 itojun if (nd6_options((struct nd_opt_hdr *)(rs + 1), 914 1.1 itojun len - sizeof(struct nd_router_solicit), 915 1.18 itojun &ndopts, NDOPT_FLAG_SRCLINKADDR)) { 916 1.57 christos logit(LOG_INFO, 917 1.56 christos "%s: ND option check failed for an RS from %s on %s", 918 1.21 itojun __func__, 919 1.1 itojun inet_ntop(AF_INET6, &from->sin6_addr, 920 1.1 itojun ntopbuf, INET6_ADDRSTRLEN), 921 1.1 itojun if_indextoname(pi->ipi6_ifindex, ifnamebuf)); 922 1.1 itojun return; 923 1.1 itojun } 924 1.1 itojun 925 1.1 itojun /* 926 1.1 itojun * If the IP source address is the unspecified address, there 927 1.1 itojun * must be no source link-layer address option in the message. 928 1.1 itojun * (RFC-2461 6.1.1) 929 1.1 itojun */ 930 1.1 itojun if (IN6_IS_ADDR_UNSPECIFIED(&from->sin6_addr) && 931 1.1 itojun ndopts.nd_opts_src_lladdr) { 932 1.57 christos logit(LOG_INFO, 933 1.56 christos "%s: RS from unspecified src on %s has a link-layer" 934 1.1 itojun " address option", 935 1.21 itojun __func__, 936 1.1 itojun if_indextoname(pi->ipi6_ifindex, ifnamebuf)); 937 1.1 itojun goto done; 938 1.1 itojun } 939 1.1 itojun 940 1.39 roy if ((rai = if_indextorainfo(pi->ipi6_ifindex)) == NULL) { 941 1.57 christos logit(LOG_INFO, 942 1.56 christos "%s: RS received on non advertising interface(%s)", 943 1.21 itojun __func__, 944 1.1 itojun if_indextoname(pi->ipi6_ifindex, ifnamebuf)); 945 1.1 itojun goto done; 946 1.1 itojun } 947 1.1 itojun 948 1.39 roy if (rai->leaving) { 949 1.57 christos logit(LOG_INFO, 950 1.56 christos "%s: RS received on reconfiguring advertising interface(%s)", 951 1.39 roy __func__, rai->ifname); 952 1.39 roy goto done; 953 1.39 roy } 954 1.39 roy 955 1.39 roy rai->rsinput++; /* increment statistics */ 956 1.9 itojun 957 1.1 itojun /* 958 1.1 itojun * Decide whether to send RA according to the rate-limit 959 1.1 itojun * consideration. 960 1.1 itojun */ 961 1.10 itojun 962 1.30 rpaulo /* record sockaddr waiting for RA, if possible */ 963 1.65 roy TAILQ_FOREACH(sol, &rai->soliciter, next) { 964 1.65 roy if (IN6_ARE_ADDR_EQUAL(&sol->addr.sin6_addr, &from->sin6_addr)) 965 1.65 roy break; 966 1.65 roy } 967 1.65 roy if (sol == NULL) { 968 1.65 roy sol = malloc(sizeof(*sol)); 969 1.65 roy if (sol == NULL) { 970 1.65 roy logit(LOG_ERR, "%s: malloc: %m", __func__); 971 1.65 roy } else { 972 1.65 roy sol->addr = *from; 973 1.65 roy /* XXX RFC2553 need clarification on flowinfo */ 974 1.65 roy sol->addr.sin6_flowinfo = 0; 975 1.65 roy TAILQ_INSERT_TAIL(&rai->soliciter, sol, next); 976 1.65 roy } 977 1.30 rpaulo } 978 1.30 rpaulo 979 1.30 rpaulo /* 980 1.30 rpaulo * If there is already a waiting RS packet, don't 981 1.30 rpaulo * update the timer. 982 1.30 rpaulo */ 983 1.39 roy if (rai->waiting++) 984 1.30 rpaulo goto done; 985 1.30 rpaulo 986 1.65 roy ra_timer_set_short_delay(rai, rai->timer_sol); 987 1.1 itojun 988 1.30 rpaulo done: 989 1.30 rpaulo free_ndopts(&ndopts); 990 1.30 rpaulo } 991 1.1 itojun 992 1.39 roy void 993 1.65 roy ra_timer_set_short_delay(struct rainfo *rai, struct rtadvd_timer *timer) 994 1.30 rpaulo { 995 1.30 rpaulo long delay; /* must not be greater than 1000000 */ 996 1.47 roy struct timespec interval, now, min_delay, tm_tmp, *rest; 997 1.1 itojun 998 1.30 rpaulo /* 999 1.30 rpaulo * Compute a random delay. If the computed value 1000 1.30 rpaulo * corresponds to a time later than the time the next 1001 1.30 rpaulo * multicast RA is scheduled to be sent, ignore the random 1002 1.30 rpaulo * delay and send the advertisement at the 1003 1.30 rpaulo * already-scheduled time. RFC2461 6.2.6 1004 1.30 rpaulo */ 1005 1.30 rpaulo delay = arc4random() % MAX_RA_DELAY_TIME; 1006 1.30 rpaulo interval.tv_sec = 0; 1007 1.47 roy interval.tv_nsec = delay; 1008 1.30 rpaulo rest = rtadvd_timer_rest(rai->timer); 1009 1.47 roy if (timespeccmp(rest, &interval, <)) { 1010 1.57 christos logit(LOG_DEBUG, "%s: random delay is larger than " 1011 1.30 rpaulo "the rest of current timer", __func__); 1012 1.30 rpaulo interval = *rest; 1013 1.1 itojun } 1014 1.1 itojun 1015 1.30 rpaulo /* 1016 1.30 rpaulo * If we sent a multicast Router Advertisement within 1017 1.30 rpaulo * the last MIN_DELAY_BETWEEN_RAS seconds, schedule 1018 1.30 rpaulo * the advertisement to be sent at a time corresponding to 1019 1.30 rpaulo * MIN_DELAY_BETWEEN_RAS plus the random value after the 1020 1.30 rpaulo * previous advertisement was sent. 1021 1.30 rpaulo */ 1022 1.51 ozaki prog_clock_gettime(CLOCK_MONOTONIC, &now); 1023 1.47 roy timespecsub(&now, &rai->lastsent, &tm_tmp); 1024 1.30 rpaulo min_delay.tv_sec = MIN_DELAY_BETWEEN_RAS; 1025 1.47 roy min_delay.tv_nsec = 0; 1026 1.47 roy if (timespeccmp(&tm_tmp, &min_delay, <)) { 1027 1.47 roy timespecsub(&min_delay, &tm_tmp, &min_delay); 1028 1.47 roy timespecadd(&min_delay, &interval, &interval); 1029 1.30 rpaulo } 1030 1.65 roy rtadvd_set_timer(&interval, timer); 1031 1.1 itojun } 1032 1.1 itojun 1033 1.1 itojun static void 1034 1.1 itojun ra_input(int len, struct nd_router_advert *ra, 1035 1.1 itojun struct in6_pktinfo *pi, struct sockaddr_in6 *from) 1036 1.1 itojun { 1037 1.1 itojun struct rainfo *rai; 1038 1.31 mrg char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ]; 1039 1.1 itojun union nd_opts ndopts; 1040 1.36 roy const char *on_off[] = {"OFF", "ON"}; 1041 1.36 roy uint32_t reachabletime, retranstimer, mtu; 1042 1.36 roy struct nd_optlist *optp; 1043 1.9 itojun int inconsistent = 0; 1044 1.1 itojun 1045 1.57 christos logit(LOG_DEBUG, 1046 1.56 christos "%s: RA received from %s on %s", 1047 1.21 itojun __func__, 1048 1.1 itojun inet_ntop(AF_INET6, &from->sin6_addr, 1049 1.1 itojun ntopbuf, INET6_ADDRSTRLEN), 1050 1.1 itojun if_indextoname(pi->ipi6_ifindex, ifnamebuf)); 1051 1.36 roy 1052 1.1 itojun /* ND option check */ 1053 1.1 itojun memset(&ndopts, 0, sizeof(ndopts)); 1054 1.36 roy TAILQ_INIT(&ndopts.nd_opts_list); 1055 1.1 itojun if (nd6_options((struct nd_opt_hdr *)(ra + 1), 1056 1.36 roy len - sizeof(struct nd_router_advert), 1057 1.36 roy &ndopts, NDOPT_FLAG_SRCLINKADDR | 1058 1.36 roy NDOPT_FLAG_PREFIXINFO | NDOPT_FLAG_MTU | 1059 1.36 roy NDOPT_FLAG_RDNSS | NDOPT_FLAG_DNSSL)) 1060 1.36 roy { 1061 1.57 christos logit(LOG_INFO, 1062 1.56 christos "%s: ND option check failed for an RA from %s on %s", 1063 1.36 roy __func__, 1064 1.36 roy inet_ntop(AF_INET6, &from->sin6_addr, 1065 1.36 roy ntopbuf, INET6_ADDRSTRLEN), 1066 1.36 roy if_indextoname(pi->ipi6_ifindex, ifnamebuf)); 1067 1.1 itojun return; 1068 1.1 itojun } 1069 1.1 itojun 1070 1.1 itojun /* 1071 1.1 itojun * RA consistency check according to RFC-2461 6.2.7 1072 1.1 itojun */ 1073 1.1 itojun if ((rai = if_indextorainfo(pi->ipi6_ifindex)) == 0) { 1074 1.57 christos logit(LOG_INFO, 1075 1.56 christos "%s: received RA from %s on non-advertising" 1076 1.1 itojun " interface(%s)", 1077 1.21 itojun __func__, 1078 1.1 itojun inet_ntop(AF_INET6, &from->sin6_addr, 1079 1.1 itojun ntopbuf, INET6_ADDRSTRLEN), 1080 1.1 itojun if_indextoname(pi->ipi6_ifindex, ifnamebuf)); 1081 1.1 itojun goto done; 1082 1.1 itojun } 1083 1.39 roy if (rai->leaving) { 1084 1.57 christos logit(LOG_DEBUG, 1085 1.56 christos "%s: received RA on re-configuring interface (%s)", 1086 1.39 roy __func__, rai->ifname); 1087 1.39 roy goto done; 1088 1.39 roy } 1089 1.9 itojun rai->rainput++; /* increment statistics */ 1090 1.61 roy 1091 1.1 itojun /* Cur Hop Limit value */ 1092 1.1 itojun if (ra->nd_ra_curhoplimit && rai->hoplimit && 1093 1.1 itojun ra->nd_ra_curhoplimit != rai->hoplimit) { 1094 1.57 christos logit(LOG_INFO, 1095 1.56 christos "%s: CurHopLimit inconsistent on %s:" 1096 1.1 itojun " %d from %s, %d from us", 1097 1.21 itojun __func__, 1098 1.1 itojun rai->ifname, 1099 1.1 itojun ra->nd_ra_curhoplimit, 1100 1.1 itojun inet_ntop(AF_INET6, &from->sin6_addr, 1101 1.1 itojun ntopbuf, INET6_ADDRSTRLEN), 1102 1.1 itojun rai->hoplimit); 1103 1.9 itojun inconsistent++; 1104 1.1 itojun } 1105 1.1 itojun /* M flag */ 1106 1.1 itojun if ((ra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) != 1107 1.1 itojun rai->managedflg) { 1108 1.57 christos logit(LOG_INFO, 1109 1.56 christos "%s: M flag inconsistent on %s:" 1110 1.1 itojun " %s from %s, %s from us", 1111 1.21 itojun __func__, 1112 1.1 itojun rai->ifname, 1113 1.1 itojun on_off[!rai->managedflg], 1114 1.1 itojun inet_ntop(AF_INET6, &from->sin6_addr, 1115 1.1 itojun ntopbuf, INET6_ADDRSTRLEN), 1116 1.1 itojun on_off[rai->managedflg]); 1117 1.9 itojun inconsistent++; 1118 1.1 itojun } 1119 1.1 itojun /* O flag */ 1120 1.1 itojun if ((ra->nd_ra_flags_reserved & ND_RA_FLAG_OTHER) != 1121 1.1 itojun rai->otherflg) { 1122 1.57 christos logit(LOG_INFO, 1123 1.56 christos "%s: O flag inconsistent on %s:" 1124 1.1 itojun " %s from %s, %s from us", 1125 1.21 itojun __func__, 1126 1.1 itojun rai->ifname, 1127 1.1 itojun on_off[!rai->otherflg], 1128 1.1 itojun inet_ntop(AF_INET6, &from->sin6_addr, 1129 1.1 itojun ntopbuf, INET6_ADDRSTRLEN), 1130 1.1 itojun on_off[rai->otherflg]); 1131 1.9 itojun inconsistent++; 1132 1.1 itojun } 1133 1.1 itojun /* Reachable Time */ 1134 1.1 itojun reachabletime = ntohl(ra->nd_ra_reachable); 1135 1.1 itojun if (reachabletime && rai->reachabletime && 1136 1.1 itojun reachabletime != rai->reachabletime) { 1137 1.57 christos logit(LOG_INFO, 1138 1.56 christos "%s: ReachableTime inconsistent on %s:" 1139 1.1 itojun " %d from %s, %d from us", 1140 1.21 itojun __func__, 1141 1.1 itojun rai->ifname, 1142 1.1 itojun reachabletime, 1143 1.1 itojun inet_ntop(AF_INET6, &from->sin6_addr, 1144 1.1 itojun ntopbuf, INET6_ADDRSTRLEN), 1145 1.1 itojun rai->reachabletime); 1146 1.9 itojun inconsistent++; 1147 1.1 itojun } 1148 1.1 itojun /* Retrans Timer */ 1149 1.1 itojun retranstimer = ntohl(ra->nd_ra_retransmit); 1150 1.1 itojun if (retranstimer && rai->retranstimer && 1151 1.1 itojun retranstimer != rai->retranstimer) { 1152 1.57 christos logit(LOG_INFO, 1153 1.56 christos "%s: RetranceTimer inconsistent on %s:" 1154 1.1 itojun " %d from %s, %d from us", 1155 1.21 itojun __func__, 1156 1.1 itojun rai->ifname, 1157 1.1 itojun retranstimer, 1158 1.1 itojun inet_ntop(AF_INET6, &from->sin6_addr, 1159 1.1 itojun ntopbuf, INET6_ADDRSTRLEN), 1160 1.1 itojun rai->retranstimer); 1161 1.9 itojun inconsistent++; 1162 1.1 itojun } 1163 1.1 itojun /* Values in the MTU options */ 1164 1.1 itojun if (ndopts.nd_opts_mtu) { 1165 1.1 itojun mtu = ntohl(ndopts.nd_opts_mtu->nd_opt_mtu_mtu); 1166 1.1 itojun if (mtu && rai->linkmtu && mtu != rai->linkmtu) { 1167 1.57 christos logit(LOG_INFO, 1168 1.56 christos "%s: MTU option value inconsistent on %s:" 1169 1.1 itojun " %d from %s, %d from us", 1170 1.21 itojun __func__, 1171 1.1 itojun rai->ifname, mtu, 1172 1.1 itojun inet_ntop(AF_INET6, &from->sin6_addr, 1173 1.1 itojun ntopbuf, INET6_ADDRSTRLEN), 1174 1.1 itojun rai->linkmtu); 1175 1.9 itojun inconsistent++; 1176 1.1 itojun } 1177 1.1 itojun } 1178 1.1 itojun /* Preferred and Valid Lifetimes for prefixes */ 1179 1.36 roy if (ndopts.nd_opts_pi) 1180 1.36 roy if (prefix_check(ndopts.nd_opts_pi, rai, from)) 1181 1.36 roy inconsistent++; 1182 1.36 roy TAILQ_FOREACH(optp, &ndopts.nd_opts_list, next) 1183 1.36 roy if (prefix_check((struct nd_opt_prefix_info *)optp->opt, 1184 1.36 roy rai, from)) 1185 1.36 roy inconsistent++; 1186 1.9 itojun 1187 1.11 itojun if (inconsistent) 1188 1.9 itojun rai->rainconsistent++; 1189 1.61 roy 1190 1.30 rpaulo done: 1191 1.1 itojun free_ndopts(&ndopts); 1192 1.1 itojun } 1193 1.1 itojun 1194 1.9 itojun /* return a non-zero value if the received prefix is inconsitent with ours */ 1195 1.9 itojun static int 1196 1.1 itojun prefix_check(struct nd_opt_prefix_info *pinfo, 1197 1.1 itojun struct rainfo *rai, struct sockaddr_in6 *from) 1198 1.1 itojun { 1199 1.36 roy uint32_t preferred_time, valid_time; 1200 1.1 itojun struct prefix *pp; 1201 1.9 itojun int inconsistent = 0; 1202 1.31 mrg char ntopbuf[INET6_ADDRSTRLEN], prefixbuf[INET6_ADDRSTRLEN]; 1203 1.47 roy struct timespec now; 1204 1.60 roy struct in6_addr prefix; 1205 1.1 itojun 1206 1.1 itojun #if 0 /* impossible */ 1207 1.1 itojun if (pinfo->nd_opt_pi_type != ND_OPT_PREFIX_INFORMATION) 1208 1.54 christos return 0; 1209 1.1 itojun #endif 1210 1.1 itojun 1211 1.60 roy memcpy(&prefix, &pinfo->nd_opt_pi_prefix, sizeof(prefix)); 1212 1.60 roy 1213 1.1 itojun /* 1214 1.1 itojun * log if the adveritsed prefix has link-local scope(sanity check?) 1215 1.1 itojun */ 1216 1.60 roy if (IN6_IS_ADDR_LINKLOCAL(&prefix)) { 1217 1.57 christos logit(LOG_INFO, 1218 1.56 christos "%s: link-local prefix %s/%d is advertised " 1219 1.1 itojun "from %s on %s", 1220 1.21 itojun __func__, 1221 1.60 roy inet_ntop(AF_INET6, &prefix, 1222 1.1 itojun prefixbuf, INET6_ADDRSTRLEN), 1223 1.1 itojun pinfo->nd_opt_pi_prefix_len, 1224 1.1 itojun inet_ntop(AF_INET6, &from->sin6_addr, 1225 1.1 itojun ntopbuf, INET6_ADDRSTRLEN), 1226 1.1 itojun rai->ifname); 1227 1.1 itojun } 1228 1.1 itojun 1229 1.60 roy if ((pp = find_prefix(rai, &prefix, 1230 1.1 itojun pinfo->nd_opt_pi_prefix_len)) == NULL) { 1231 1.57 christos logit(LOG_INFO, 1232 1.56 christos "%s: prefix %s/%d from %s on %s is not in our list", 1233 1.21 itojun __func__, 1234 1.60 roy inet_ntop(AF_INET6, &prefix, 1235 1.1 itojun prefixbuf, INET6_ADDRSTRLEN), 1236 1.1 itojun pinfo->nd_opt_pi_prefix_len, 1237 1.1 itojun inet_ntop(AF_INET6, &from->sin6_addr, 1238 1.1 itojun ntopbuf, INET6_ADDRSTRLEN), 1239 1.1 itojun rai->ifname); 1240 1.54 christos return 0; 1241 1.1 itojun } 1242 1.1 itojun 1243 1.1 itojun preferred_time = ntohl(pinfo->nd_opt_pi_preferred_time); 1244 1.11 itojun if (pp->pltimeexpire) { 1245 1.11 itojun /* 1246 1.11 itojun * The lifetime is decremented in real time, so we should 1247 1.11 itojun * compare the expiration time. 1248 1.11 itojun * (RFC 2461 Section 6.2.7.) 1249 1.11 itojun * XXX: can we really expect that all routers on the link 1250 1.11 itojun * have synchronized clocks? 1251 1.11 itojun */ 1252 1.51 ozaki prog_clock_gettime(CLOCK_MONOTONIC, &now); 1253 1.11 itojun preferred_time += now.tv_sec; 1254 1.11 itojun 1255 1.30 rpaulo if (!pp->timer && rai->clockskew && 1256 1.46 joerg llabs((long long)preferred_time - pp->pltimeexpire) > rai->clockskew) { 1257 1.57 christos logit(LOG_INFO, 1258 1.56 christos "%s: preferred lifetime for %s/%d" 1259 1.11 itojun " (decr. in real time) inconsistent on %s:" 1260 1.11 itojun " %d from %s, %ld from us", 1261 1.21 itojun __func__, 1262 1.60 roy inet_ntop(AF_INET6, &prefix, 1263 1.11 itojun prefixbuf, INET6_ADDRSTRLEN), 1264 1.11 itojun pinfo->nd_opt_pi_prefix_len, 1265 1.11 itojun rai->ifname, preferred_time, 1266 1.11 itojun inet_ntop(AF_INET6, &from->sin6_addr, 1267 1.11 itojun ntopbuf, INET6_ADDRSTRLEN), 1268 1.11 itojun pp->pltimeexpire); 1269 1.11 itojun inconsistent++; 1270 1.11 itojun } 1271 1.30 rpaulo } else if (!pp->timer && preferred_time != pp->preflifetime) { 1272 1.57 christos logit(LOG_INFO, 1273 1.56 christos "%s: preferred lifetime for %s/%d" 1274 1.1 itojun " inconsistent on %s:" 1275 1.1 itojun " %d from %s, %d from us", 1276 1.21 itojun __func__, 1277 1.60 roy inet_ntop(AF_INET6, &prefix, 1278 1.1 itojun prefixbuf, INET6_ADDRSTRLEN), 1279 1.1 itojun pinfo->nd_opt_pi_prefix_len, 1280 1.1 itojun rai->ifname, preferred_time, 1281 1.1 itojun inet_ntop(AF_INET6, &from->sin6_addr, 1282 1.1 itojun ntopbuf, INET6_ADDRSTRLEN), 1283 1.1 itojun pp->preflifetime); 1284 1.9 itojun } 1285 1.1 itojun 1286 1.1 itojun valid_time = ntohl(pinfo->nd_opt_pi_valid_time); 1287 1.11 itojun if (pp->vltimeexpire) { 1288 1.51 ozaki prog_clock_gettime(CLOCK_MONOTONIC, &now); 1289 1.11 itojun valid_time += now.tv_sec; 1290 1.11 itojun 1291 1.30 rpaulo if (!pp->timer && rai->clockskew && 1292 1.46 joerg llabs((long long)valid_time - pp->vltimeexpire) > rai->clockskew) { 1293 1.57 christos logit(LOG_INFO, 1294 1.56 christos "%s: valid lifetime for %s/%d" 1295 1.11 itojun " (decr. in real time) inconsistent on %s:" 1296 1.11 itojun " %d from %s, %ld from us", 1297 1.21 itojun __func__, 1298 1.60 roy inet_ntop(AF_INET6, &prefix, 1299 1.11 itojun prefixbuf, INET6_ADDRSTRLEN), 1300 1.11 itojun pinfo->nd_opt_pi_prefix_len, 1301 1.11 itojun rai->ifname, preferred_time, 1302 1.11 itojun inet_ntop(AF_INET6, &from->sin6_addr, 1303 1.11 itojun ntopbuf, INET6_ADDRSTRLEN), 1304 1.11 itojun pp->vltimeexpire); 1305 1.11 itojun inconsistent++; 1306 1.11 itojun } 1307 1.30 rpaulo } else if (!pp->timer && valid_time != pp->validlifetime) { 1308 1.57 christos logit(LOG_INFO, 1309 1.56 christos "%s: valid lifetime for %s/%d" 1310 1.1 itojun " inconsistent on %s:" 1311 1.1 itojun " %d from %s, %d from us", 1312 1.21 itojun __func__, 1313 1.60 roy inet_ntop(AF_INET6, &prefix, 1314 1.1 itojun prefixbuf, INET6_ADDRSTRLEN), 1315 1.1 itojun pinfo->nd_opt_pi_prefix_len, 1316 1.1 itojun rai->ifname, valid_time, 1317 1.1 itojun inet_ntop(AF_INET6, &from->sin6_addr, 1318 1.1 itojun ntopbuf, INET6_ADDRSTRLEN), 1319 1.1 itojun pp->validlifetime); 1320 1.9 itojun inconsistent++; 1321 1.9 itojun } 1322 1.9 itojun 1323 1.54 christos return inconsistent; 1324 1.1 itojun } 1325 1.1 itojun 1326 1.1 itojun struct prefix * 1327 1.80 christos find_prefix(struct rainfo *rai, const struct in6_addr *prefix, int plen) 1328 1.1 itojun { 1329 1.1 itojun struct prefix *pp; 1330 1.1 itojun int bytelen, bitlen; 1331 1.36 roy unsigned char bitmask; 1332 1.1 itojun 1333 1.36 roy TAILQ_FOREACH(pp, &rai->prefix, next) { 1334 1.1 itojun if (plen != pp->prefixlen) 1335 1.1 itojun continue; 1336 1.1 itojun bytelen = plen / 8; 1337 1.1 itojun bitlen = plen % 8; 1338 1.15 itojun bitmask = 0xff << (8 - bitlen); 1339 1.54 christos if (memcmp(prefix, &pp->prefix, bytelen)) 1340 1.1 itojun continue; 1341 1.15 itojun if (bitlen == 0 || 1342 1.61 roy ((prefix->s6_addr[bytelen] & bitmask) == 1343 1.15 itojun (pp->prefix.s6_addr[bytelen] & bitmask))) { 1344 1.54 christos return pp; 1345 1.15 itojun } 1346 1.1 itojun } 1347 1.1 itojun 1348 1.54 christos return NULL; 1349 1.1 itojun } 1350 1.1 itojun 1351 1.11 itojun /* check if p0/plen0 matches p1/plen1; return 1 if matches, otherwise 0. */ 1352 1.11 itojun int 1353 1.11 itojun prefix_match(struct in6_addr *p0, int plen0, 1354 1.11 itojun struct in6_addr *p1, int plen1) 1355 1.11 itojun { 1356 1.11 itojun int bytelen, bitlen; 1357 1.36 roy unsigned char bitmask; 1358 1.11 itojun 1359 1.11 itojun if (plen0 < plen1) 1360 1.54 christos return 0; 1361 1.11 itojun bytelen = plen1 / 8; 1362 1.11 itojun bitlen = plen1 % 8; 1363 1.15 itojun bitmask = 0xff << (8 - bitlen); 1364 1.54 christos if (memcmp(p0, p1, bytelen)) 1365 1.54 christos return 0; 1366 1.15 itojun if (bitlen == 0 || 1367 1.15 itojun ((p0->s6_addr[bytelen] & bitmask) == 1368 1.61 roy (p1->s6_addr[bytelen] & bitmask))) { 1369 1.54 christos return 1; 1370 1.15 itojun } 1371 1.11 itojun 1372 1.54 christos return 0; 1373 1.11 itojun } 1374 1.11 itojun 1375 1.1 itojun static int 1376 1.1 itojun nd6_options(struct nd_opt_hdr *hdr, int limit, 1377 1.36 roy union nd_opts *ndopts, uint32_t optflags) 1378 1.1 itojun { 1379 1.1 itojun int optlen = 0; 1380 1.1 itojun 1381 1.1 itojun for (; limit > 0; limit -= optlen) { 1382 1.36 roy if ((size_t)limit < sizeof(struct nd_opt_hdr)) { 1383 1.57 christos logit(LOG_INFO, "%s: short option header", __func__); 1384 1.27 itojun goto bad; 1385 1.27 itojun } 1386 1.27 itojun 1387 1.36 roy hdr = (struct nd_opt_hdr *)((char *)hdr + optlen); 1388 1.1 itojun if (hdr->nd_opt_len == 0) { 1389 1.57 christos logit(LOG_INFO, 1390 1.56 christos "%s: bad ND option length(0) (type = %d)", 1391 1.21 itojun __func__, hdr->nd_opt_type); 1392 1.1 itojun goto bad; 1393 1.1 itojun } 1394 1.27 itojun optlen = hdr->nd_opt_len << 3; 1395 1.27 itojun if (optlen > limit) { 1396 1.57 christos logit(LOG_INFO, "%s: short option", __func__); 1397 1.27 itojun goto bad; 1398 1.27 itojun } 1399 1.1 itojun 1400 1.36 roy if (hdr->nd_opt_type > ND_OPT_MTU && 1401 1.36 roy hdr->nd_opt_type != ND_OPT_RDNSS && 1402 1.36 roy hdr->nd_opt_type != ND_OPT_DNSSL) 1403 1.17 itojun { 1404 1.57 christos logit(LOG_INFO, "%s: unknown ND option(type %d)", 1405 1.21 itojun __func__, hdr->nd_opt_type); 1406 1.1 itojun continue; 1407 1.1 itojun } 1408 1.1 itojun 1409 1.1 itojun if ((ndopt_flags[hdr->nd_opt_type] & optflags) == 0) { 1410 1.57 christos logit(LOG_INFO, "%s: unexpected ND option(type %d)", 1411 1.21 itojun __func__, hdr->nd_opt_type); 1412 1.1 itojun continue; 1413 1.1 itojun } 1414 1.1 itojun 1415 1.27 itojun /* 1416 1.27 itojun * Option length check. Do it here for all fixed-length 1417 1.27 itojun * options. 1418 1.27 itojun */ 1419 1.27 itojun if ((hdr->nd_opt_type == ND_OPT_MTU && 1420 1.27 itojun (optlen != sizeof(struct nd_opt_mtu))) || 1421 1.27 itojun ((hdr->nd_opt_type == ND_OPT_PREFIX_INFORMATION && 1422 1.42 roy optlen != sizeof(struct nd_opt_prefix_info))) || 1423 1.42 roy (hdr->nd_opt_type == ND_OPT_RDNSS && 1424 1.42 roy ((optlen < (int)sizeof(struct nd_opt_rdnss) || 1425 1.42 roy (optlen - sizeof(struct nd_opt_rdnss)) % 16 != 0))) || 1426 1.42 roy (hdr->nd_opt_type == ND_OPT_DNSSL && 1427 1.42 roy optlen < (int)sizeof(struct nd_opt_dnssl))) 1428 1.42 roy { 1429 1.57 christos logit(LOG_INFO, "%s: invalid option length", 1430 1.27 itojun __func__); 1431 1.27 itojun continue; 1432 1.27 itojun } 1433 1.27 itojun 1434 1.14 itojun switch (hdr->nd_opt_type) { 1435 1.14 itojun case ND_OPT_TARGET_LINKADDR: 1436 1.14 itojun case ND_OPT_REDIRECTED_HEADER: 1437 1.42 roy case ND_OPT_RDNSS: 1438 1.42 roy case ND_OPT_DNSSL: 1439 1.27 itojun break; /* we don't care about these options */ 1440 1.30 rpaulo case ND_OPT_SOURCE_LINKADDR: 1441 1.14 itojun case ND_OPT_MTU: 1442 1.14 itojun if (ndopts->nd_opt_array[hdr->nd_opt_type]) { 1443 1.57 christos logit(LOG_INFO, 1444 1.56 christos "%s: duplicated ND option (type = %d)", 1445 1.21 itojun __func__, hdr->nd_opt_type); 1446 1.14 itojun } 1447 1.14 itojun ndopts->nd_opt_array[hdr->nd_opt_type] = hdr; 1448 1.14 itojun break; 1449 1.14 itojun case ND_OPT_PREFIX_INFORMATION: 1450 1.14 itojun { 1451 1.14 itojun struct nd_optlist *pfxlist; 1452 1.14 itojun 1453 1.14 itojun if (ndopts->nd_opts_pi == 0) { 1454 1.14 itojun ndopts->nd_opts_pi = 1455 1.14 itojun (struct nd_opt_prefix_info *)hdr; 1456 1.14 itojun continue; 1457 1.14 itojun } 1458 1.14 itojun if ((pfxlist = malloc(sizeof(*pfxlist))) == NULL) { 1459 1.57 christos logit(LOG_ERR, "%s: can't allocate memory", 1460 1.21 itojun __func__); 1461 1.14 itojun goto bad; 1462 1.14 itojun } 1463 1.14 itojun pfxlist->opt = hdr; 1464 1.36 roy TAILQ_INSERT_TAIL(&ndopts->nd_opts_list, pfxlist, next); 1465 1.14 itojun 1466 1.14 itojun break; 1467 1.14 itojun } 1468 1.14 itojun default: /* impossible */ 1469 1.14 itojun break; 1470 1.1 itojun } 1471 1.1 itojun } 1472 1.1 itojun 1473 1.54 christos return 0; 1474 1.1 itojun 1475 1.1 itojun bad: 1476 1.1 itojun free_ndopts(ndopts); 1477 1.54 christos return -1; 1478 1.1 itojun } 1479 1.1 itojun 1480 1.1 itojun static void 1481 1.1 itojun free_ndopts(union nd_opts *ndopts) 1482 1.1 itojun { 1483 1.36 roy struct nd_optlist *opt; 1484 1.1 itojun 1485 1.36 roy while ((opt = TAILQ_FIRST(&ndopts->nd_opts_list)) != NULL) { 1486 1.36 roy TAILQ_REMOVE(&ndopts->nd_opts_list, opt, next); 1487 1.1 itojun free(opt); 1488 1.1 itojun } 1489 1.1 itojun } 1490 1.1 itojun 1491 1.1 itojun void 1492 1.36 roy sock_open(void) 1493 1.1 itojun { 1494 1.1 itojun struct icmp6_filter filt; 1495 1.1 itojun struct ipv6_mreq mreq; 1496 1.36 roy struct rainfo *ra; 1497 1.1 itojun int on; 1498 1.1 itojun /* XXX: should be max MTU attached to the node */ 1499 1.36 roy static unsigned char answer[1500]; 1500 1.6 itojun 1501 1.6 itojun rcvcmsgbuflen = CMSG_SPACE(sizeof(struct in6_pktinfo)) + 1502 1.6 itojun CMSG_SPACE(sizeof(int)); 1503 1.36 roy rcvcmsgbuf = malloc(rcvcmsgbuflen); 1504 1.6 itojun if (rcvcmsgbuf == NULL) { 1505 1.57 christos logit(LOG_ERR, "%s: malloc: %m", __func__); 1506 1.54 christos exit(EXIT_FAILURE); 1507 1.6 itojun } 1508 1.6 itojun 1509 1.66 roy sndcmsgbuflen = CMSG_SPACE(sizeof(struct in6_pktinfo)); 1510 1.36 roy sndcmsgbuf = malloc(sndcmsgbuflen); 1511 1.6 itojun if (sndcmsgbuf == NULL) { 1512 1.57 christos logit(LOG_ERR, "%s: malloc: %m", __func__); 1513 1.54 christos exit(EXIT_FAILURE); 1514 1.6 itojun } 1515 1.1 itojun 1516 1.56 christos if ((sock = prog_socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) == -1) { 1517 1.57 christos logit(LOG_ERR, "%s: socket: %m", __func__); 1518 1.54 christos exit(EXIT_FAILURE); 1519 1.1 itojun } 1520 1.1 itojun 1521 1.48 roy /* RFC 4861 Section 4.2 */ 1522 1.48 roy on = 255; 1523 1.51 ozaki if (prog_setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &on, 1524 1.48 roy sizeof(on)) == -1) { 1525 1.57 christos logit(LOG_ERR, "%s: IPV6_MULTICAST_HOPS: %m", __func__); 1526 1.54 christos exit(EXIT_FAILURE); 1527 1.48 roy } 1528 1.65 roy on = 255; 1529 1.65 roy if (prog_setsockopt(sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &on, 1530 1.65 roy sizeof(on)) == -1) { 1531 1.65 roy logit(LOG_ERR, "%s: IPV6_UNICAST_HOPS: %m", __func__); 1532 1.65 roy exit(EXIT_FAILURE); 1533 1.65 roy } 1534 1.48 roy 1535 1.1 itojun /* specify to tell receiving interface */ 1536 1.1 itojun on = 1; 1537 1.51 ozaki if (prog_setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, 1538 1.56 christos sizeof(on)) == -1) { 1539 1.57 christos logit(LOG_ERR, "%s: IPV6_RECVPKTINFO: %m", __func__); 1540 1.54 christos exit(EXIT_FAILURE); 1541 1.5 itojun } 1542 1.1 itojun 1543 1.1 itojun on = 1; 1544 1.1 itojun /* specify to tell value of hoplimit field of received IP6 hdr */ 1545 1.51 ozaki if (prog_setsockopt(sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on, 1546 1.56 christos sizeof(on)) == -1) { 1547 1.57 christos logit(LOG_ERR, "%s: IPV6_RECVHOPLIMIT: %m", __func__); 1548 1.54 christos exit(EXIT_FAILURE); 1549 1.5 itojun } 1550 1.1 itojun 1551 1.1 itojun ICMP6_FILTER_SETBLOCKALL(&filt); 1552 1.1 itojun ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filt); 1553 1.1 itojun ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filt); 1554 1.51 ozaki if (prog_setsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filt, 1555 1.56 christos sizeof(filt)) == -1) { 1556 1.57 christos logit(LOG_ERR, "%s: IICMP6_FILTER: %m", __func__); 1557 1.54 christos exit(EXIT_FAILURE); 1558 1.1 itojun } 1559 1.1 itojun 1560 1.1 itojun /* 1561 1.1 itojun * join all routers multicast address on each advertising interface. 1562 1.1 itojun */ 1563 1.11 itojun if (inet_pton(AF_INET6, ALLROUTERS_LINK, 1564 1.36 roy mreq.ipv6mr_multiaddr.s6_addr) != 1) 1565 1.36 roy { 1566 1.57 christos logit(LOG_ERR, "%s: inet_pton failed(library bug?)", 1567 1.36 roy __func__); 1568 1.54 christos exit(EXIT_FAILURE); 1569 1.1 itojun } 1570 1.36 roy TAILQ_FOREACH(ra, &ralist, next) { 1571 1.1 itojun mreq.ipv6mr_interface = ra->ifindex; 1572 1.51 ozaki if (prog_setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, 1573 1.56 christos sizeof(mreq)) == -1) { 1574 1.57 christos logit(LOG_ERR, "%s: IPV6_JOIN_GROUP(link) on %s: %m", 1575 1.49 roy __func__, ra->ifname); 1576 1.56 christos continue; 1577 1.1 itojun } 1578 1.1 itojun } 1579 1.11 itojun 1580 1.1 itojun /* initialize msghdr for receiving packets */ 1581 1.36 roy rcviov[0].iov_base = answer; 1582 1.1 itojun rcviov[0].iov_len = sizeof(answer); 1583 1.36 roy rcvmhdr.msg_name = &rcvfrom; 1584 1.30 rpaulo rcvmhdr.msg_namelen = sizeof(rcvfrom); 1585 1.1 itojun rcvmhdr.msg_iov = rcviov; 1586 1.1 itojun rcvmhdr.msg_iovlen = 1; 1587 1.36 roy rcvmhdr.msg_control = rcvcmsgbuf; 1588 1.6 itojun rcvmhdr.msg_controllen = rcvcmsgbuflen; 1589 1.1 itojun 1590 1.1 itojun /* initialize msghdr for sending packets */ 1591 1.1 itojun sndmhdr.msg_namelen = sizeof(struct sockaddr_in6); 1592 1.1 itojun sndmhdr.msg_iov = sndiov; 1593 1.1 itojun sndmhdr.msg_iovlen = 1; 1594 1.54 christos sndmhdr.msg_control = sndcmsgbuf; 1595 1.6 itojun sndmhdr.msg_controllen = sndcmsgbuflen; 1596 1.1 itojun } 1597 1.1 itojun 1598 1.1 itojun /* open a routing socket to watch the routing table */ 1599 1.1 itojun static void 1600 1.36 roy rtsock_open(void) 1601 1.1 itojun { 1602 1.53 roy #ifdef RO_MSGFILTER 1603 1.53 roy unsigned char msgfilter[] = { 1604 1.53 roy RTM_ADD, RTM_DELETE, 1605 1.53 roy RTM_NEWADDR, RTM_DELADDR, 1606 1.53 roy #ifdef RTM_IFANNOUNCE 1607 1.53 roy RTM_IFANNOUNCE, 1608 1.53 roy #endif 1609 1.53 roy RTM_IFINFO, 1610 1.53 roy }; 1611 1.53 roy #endif 1612 1.53 roy 1613 1.56 christos if ((rtsock = prog_socket(PF_ROUTE, SOCK_RAW, 0)) == -1) { 1614 1.57 christos logit(LOG_ERR, "%s: socket: %m", __func__); 1615 1.54 christos exit(EXIT_FAILURE); 1616 1.1 itojun } 1617 1.53 roy #ifdef RO_MSGFILTER 1618 1.79 rjs if (prog_setsockopt(rtsock, PF_ROUTE, RO_MSGFILTER, 1619 1.81 christos &msgfilter, sizeof(msgfilter)) == -1) 1620 1.57 christos logit(LOG_ERR, "%s: RO_MSGFILTER: %m", __func__); 1621 1.53 roy #endif 1622 1.1 itojun } 1623 1.1 itojun 1624 1.11 itojun struct rainfo * 1625 1.36 roy if_indextorainfo(unsigned int idx) 1626 1.1 itojun { 1627 1.36 roy struct rainfo *rai; 1628 1.1 itojun 1629 1.36 roy TAILQ_FOREACH(rai, &ralist, next) { 1630 1.35 lukem if (rai->ifindex == idx) 1631 1.54 christos return rai; 1632 1.1 itojun } 1633 1.1 itojun 1634 1.54 christos return NULL; /* search failed */ 1635 1.1 itojun } 1636 1.1 itojun 1637 1.39 roy struct rainfo * 1638 1.65 roy ra_output(struct rainfo *rai, bool solicited) 1639 1.1 itojun { 1640 1.1 itojun int i; 1641 1.1 itojun struct cmsghdr *cm; 1642 1.1 itojun struct in6_pktinfo *pi; 1643 1.36 roy struct soliciter *sol; 1644 1.10 itojun 1645 1.39 roy if ((rai->ifflags & IFF_UP) == 0) { 1646 1.57 christos logit(LOG_DEBUG, "%s: %s is not up, skip sending RA", 1647 1.39 roy __func__, rai->ifname); 1648 1.39 roy return NULL; 1649 1.10 itojun } 1650 1.1 itojun 1651 1.39 roy make_packet(rai); /* XXX: inefficient */ 1652 1.11 itojun 1653 1.36 roy sndmhdr.msg_name = (void *)&sin6_linklocal_allnodes; 1654 1.39 roy sndmhdr.msg_iov[0].iov_base = (void *)rai->ra_data; 1655 1.39 roy sndmhdr.msg_iov[0].iov_len = rai->ra_datalen; 1656 1.1 itojun 1657 1.65 roy /* specify the outgoing interface */ 1658 1.1 itojun cm = CMSG_FIRSTHDR(&sndmhdr); 1659 1.1 itojun cm->cmsg_level = IPPROTO_IPV6; 1660 1.1 itojun cm->cmsg_type = IPV6_PKTINFO; 1661 1.1 itojun cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); 1662 1.1 itojun pi = (struct in6_pktinfo *)CMSG_DATA(cm); 1663 1.1 itojun memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr)); /*XXX*/ 1664 1.39 roy pi->ipi6_ifindex = rai->ifindex; 1665 1.1 itojun 1666 1.57 christos logit(LOG_DEBUG, 1667 1.56 christos "%s: send RA on %s, # of waitings = %d", 1668 1.39 roy __func__, rai->ifname, rai->waiting); 1669 1.1 itojun 1670 1.65 roy if (solicited) { 1671 1.65 roy /* unicast solicited RA's as per RFC 7772 */ 1672 1.65 roy while ((sol = TAILQ_FIRST(&rai->soliciter)) != NULL) { 1673 1.65 roy sndmhdr.msg_name = (void *)&sol->addr; 1674 1.65 roy i = prog_sendmsg(sock, &sndmhdr, 0); 1675 1.65 roy if (i < 0 || (size_t)i != rai->ra_datalen) { 1676 1.65 roy if (i < 0) { 1677 1.65 roy logit(LOG_ERR, 1678 1.65 roy "%s: unicast sendmsg on %s: %m", 1679 1.65 roy __func__, rai->ifname); 1680 1.65 roy } 1681 1.65 roy } 1682 1.65 roy TAILQ_REMOVE(&rai->soliciter, sol, next); 1683 1.65 roy free(sol); 1684 1.65 roy } 1685 1.65 roy 1686 1.83 andvar /* reset waiting counter */ 1687 1.65 roy rai->waiting = 0; 1688 1.65 roy 1689 1.65 roy /* disable timer */ 1690 1.65 roy rai->timer_sol->enabled = false; 1691 1.65 roy 1692 1.65 roy return rai; 1693 1.65 roy } 1694 1.65 roy 1695 1.51 ozaki i = prog_sendmsg(sock, &sndmhdr, 0); 1696 1.39 roy if (i < 0 || (size_t)i != rai->ra_datalen) { 1697 1.1 itojun if (i < 0) { 1698 1.57 christos logit(LOG_ERR, "%s: sendmsg on %s: %m", 1699 1.49 roy __func__, rai->ifname); 1700 1.1 itojun } 1701 1.1 itojun } 1702 1.1 itojun 1703 1.39 roy if (rai->leaving_adv > 0) { 1704 1.39 roy if (--(rai->leaving_adv) == 0) { 1705 1.41 roy /* leaving for ourself means we're shutting down */ 1706 1.41 roy if (rai->leaving_for == rai) { 1707 1.41 roy TAILQ_REMOVE(&ralist, rai, next); 1708 1.41 roy free_rainfo(rai); 1709 1.41 roy return NULL; 1710 1.41 roy } 1711 1.57 christos logit(LOG_DEBUG, 1712 1.56 christos "%s: expired RA," 1713 1.39 roy " new config active for interface (%s)", 1714 1.39 roy __func__, rai->ifname); 1715 1.70 roy ra_timer_reset(rai->leaving_for); 1716 1.39 roy rai->leaving_for->leaving = NULL; 1717 1.39 roy free_rainfo(rai); 1718 1.39 roy return NULL; 1719 1.39 roy } 1720 1.39 roy } 1721 1.39 roy 1722 1.1 itojun /* update counter */ 1723 1.39 roy if (rai->initcounter < MAX_INITIAL_RTR_ADVERTISEMENTS) 1724 1.39 roy rai->initcounter++; 1725 1.39 roy rai->raoutput++; 1726 1.1 itojun 1727 1.1 itojun /* update timestamp */ 1728 1.51 ozaki prog_clock_gettime(CLOCK_MONOTONIC, &rai->lastsent); 1729 1.39 roy return rai; 1730 1.1 itojun } 1731 1.1 itojun 1732 1.65 roy /* process unsolicited RA timer */ 1733 1.30 rpaulo struct rtadvd_timer * 1734 1.1 itojun ra_timeout(void *data) 1735 1.1 itojun { 1736 1.1 itojun struct rainfo *rai = (struct rainfo *)data; 1737 1.1 itojun 1738 1.65 roy logit(LOG_DEBUG, 1739 1.65 roy "%s: unsolicited RA timer on %s is expired", 1740 1.65 roy __func__, rai->ifname); 1741 1.65 roy 1742 1.65 roy if (ra_output(rai, false)) 1743 1.65 roy return rai->timer; 1744 1.65 roy return NULL; 1745 1.65 roy } 1746 1.65 roy 1747 1.65 roy /* process solicited RA timer */ 1748 1.65 roy struct rtadvd_timer * 1749 1.65 roy ra_timeout_sol(void *data) 1750 1.65 roy { 1751 1.65 roy struct rainfo *rai = (struct rainfo *)data; 1752 1.1 itojun 1753 1.57 christos logit(LOG_DEBUG, 1754 1.65 roy "%s: solicited RA timer on %s is expired", 1755 1.21 itojun __func__, rai->ifname); 1756 1.1 itojun 1757 1.65 roy if (ra_output(rai, true)) 1758 1.65 roy return rai->timer_sol; 1759 1.39 roy return NULL; 1760 1.1 itojun } 1761 1.1 itojun 1762 1.1 itojun /* update RA timer */ 1763 1.1 itojun void 1764 1.47 roy ra_timer_update(void *data, struct timespec *tm) 1765 1.1 itojun { 1766 1.1 itojun struct rainfo *rai = (struct rainfo *)data; 1767 1.1 itojun long interval; 1768 1.1 itojun 1769 1.1 itojun /* 1770 1.1 itojun * Whenever a multicast advertisement is sent from an interface, 1771 1.1 itojun * the timer is reset to a uniformly-distributed random value 1772 1.1 itojun * between the interface's configured MinRtrAdvInterval and 1773 1.11 itojun * MaxRtrAdvInterval (RFC2461 6.2.4). 1774 1.1 itojun */ 1775 1.39 roy interval = rai->mininterval; 1776 1.39 roy if (rai->mininterval != rai->maxinterval) 1777 1.39 roy interval += arc4random() % (rai->maxinterval-rai->mininterval); 1778 1.1 itojun 1779 1.1 itojun /* 1780 1.1 itojun * For the first few advertisements (up to 1781 1.1 itojun * MAX_INITIAL_RTR_ADVERTISEMENTS), if the randomly chosen interval 1782 1.1 itojun * is greater than MAX_INITIAL_RTR_ADVERT_INTERVAL, the timer 1783 1.1 itojun * SHOULD be set to MAX_INITIAL_RTR_ADVERT_INTERVAL instead. 1784 1.1 itojun * (RFC-2461 6.2.4) 1785 1.1 itojun */ 1786 1.1 itojun if (rai->initcounter < MAX_INITIAL_RTR_ADVERTISEMENTS && 1787 1.1 itojun interval > MAX_INITIAL_RTR_ADVERT_INTERVAL) 1788 1.1 itojun interval = MAX_INITIAL_RTR_ADVERT_INTERVAL; 1789 1.1 itojun 1790 1.1 itojun tm->tv_sec = interval; 1791 1.47 roy tm->tv_nsec = 0; 1792 1.1 itojun 1793 1.57 christos logit(LOG_DEBUG, 1794 1.56 christos "%s: RA timer on %s is set to %jd:%jd", 1795 1.21 itojun __func__, rai->ifname, 1796 1.54 christos (intmax_t)tm->tv_sec, (intmax_t)tm->tv_nsec); 1797 1.1 itojun } 1798 1.57 christos 1799 1.57 christos void 1800 1.57 christos logit(int level, const char *fmt, ...) 1801 1.57 christos { 1802 1.57 christos va_list ap; 1803 1.67 christos char *buf; 1804 1.57 christos 1805 1.57 christos va_start(ap, fmt); 1806 1.76 christos if (!Dflag && after_daemon) { 1807 1.57 christos vsyslog(level, fmt, ap); 1808 1.81 christos goto out; 1809 1.81 christos } 1810 1.81 christos if (level >= LOG_INFO && !dflag) { 1811 1.81 christos goto out; 1812 1.57 christos } 1813 1.57 christos 1814 1.80 christos vwarnx(expandm(fmt, "", &buf), ap); 1815 1.68 christos free(buf); 1816 1.81 christos out: 1817 1.57 christos va_end(ap); 1818 1.57 christos } 1819