1 /* $NetBSD: config.c,v 1.37 2017/11/06 15:15:04 christos Exp $ */ 2 /* $KAME: config.c,v 1.93 2005/10/17 14:40:02 suz Exp $ */ 3 4 /* 5 * Copyright (C) 1998 WIDE Project. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the project nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 #include <sys/param.h> 34 #include <sys/ioctl.h> 35 #include <sys/socket.h> 36 #include <sys/time.h> 37 #include <sys/sysctl.h> 38 39 #include <net/if.h> 40 #include <net/route.h> 41 #include <net/if_dl.h> 42 #ifdef __FreeBSD__ 43 #include <net/if_var.h> 44 #endif 45 46 #include <netinet/in.h> 47 #include <netinet/in_var.h> 48 #include <netinet/ip6.h> 49 #include <netinet6/ip6_var.h> 50 #include <netinet/icmp6.h> 51 #include <netinet6/nd6.h> 52 53 #include <arpa/inet.h> 54 55 #include <stdio.h> 56 #include <syslog.h> 57 #include <errno.h> 58 #include <string.h> 59 #include <stdlib.h> 60 #include <search.h> 61 #include <unistd.h> 62 #include <ifaddrs.h> 63 #include <inttypes.h> 64 65 #include "rtadvd.h" 66 #include "advcap.h" 67 #include "timer.h" 68 #include "if.h" 69 #include "config.h" 70 #include "logit.h" 71 #include "prog_ops.h" 72 73 #ifndef __arraycount 74 #define __arraycount(__x) (sizeof(__x) / sizeof(__x[0])) 75 #endif 76 77 static time_t prefix_timo = (60 * 120); /* 2 hours. 78 * XXX: should be configurable. */ 79 static struct rtadvd_timer *prefix_timeout(void *); 80 static void makeentry(char *, size_t, int, const char *); 81 static int getinet6sysctl(int); 82 83 static size_t 84 encode_domain(char *dst, const char *src) 85 { 86 ssize_t len; 87 char *odst, *p; 88 89 odst = dst; 90 while (src && (len = strlen(src)) != 0) { 91 p = strchr(src, '.'); 92 *dst++ = len = MIN(63, p == NULL ? len : p - src); 93 memcpy(dst, src, len); 94 dst += len; 95 if (p == NULL) 96 break; 97 src = p + 1; 98 } 99 *dst++ = '\0'; 100 101 return dst - odst; 102 } 103 104 void 105 free_rainfo(struct rainfo *rai) 106 { 107 struct prefix *pfx; 108 struct rtinfo *rti; 109 struct rdnss *rdnss; 110 struct rdnss_addr *rdnsa; 111 struct dnssl *dnssl; 112 struct dnssl_domain *dnsd; 113 114 rtadvd_remove_timer(&rai->timer); 115 116 while ((pfx = TAILQ_FIRST(&rai->prefix))) { 117 TAILQ_REMOVE(&rai->prefix, pfx, next); 118 free(pfx); 119 } 120 121 while ((rti = TAILQ_FIRST(&rai->route))) { 122 TAILQ_REMOVE(&rai->route, rti, next); 123 free(rti); 124 } 125 126 while ((rdnss = TAILQ_FIRST(&rai->rdnss))) { 127 TAILQ_REMOVE(&rai->rdnss, rdnss, next); 128 while ((rdnsa = TAILQ_FIRST(&rdnss->list))) { 129 TAILQ_REMOVE(&rdnss->list, rdnsa, next); 130 free(rdnsa); 131 } 132 free(rdnss); 133 } 134 135 while ((dnssl = TAILQ_FIRST(&rai->dnssl))) { 136 TAILQ_REMOVE(&rai->dnssl, dnssl, next); 137 while ((dnsd = TAILQ_FIRST(&dnssl->list))) { 138 TAILQ_REMOVE(&dnssl->list, dnsd, next); 139 free(dnsd); 140 } 141 free(dnssl); 142 } 143 144 free(rai->sdl); 145 free(rai->ra_data); 146 free(rai); 147 } 148 149 void 150 getconfig(const char *intface, int exithard) 151 { 152 int stat, c, i; 153 char tbuf[BUFSIZ]; 154 struct rainfo *tmp, *rai; 155 int32_t val; 156 int64_t val64; 157 char buf[BUFSIZ]; 158 char *bp = buf; 159 char *addr, *flagstr, *ap; 160 static int forwarding = -1; 161 char entbuf[256], abuf[256]; 162 struct rdnss *rdnss; 163 struct dnssl *dnssl; 164 165 #define MUSTHAVE(var, cap) \ 166 do { \ 167 int64_t t; \ 168 if ((t = agetnum(cap)) < 0) { \ 169 fprintf(stderr, "rtadvd: need %s for interface %s\n", \ 170 cap, intface); \ 171 goto errexit; \ 172 } \ 173 var = t; \ 174 } while (0) 175 #define MAYHAVE(var, cap, def) \ 176 do { \ 177 if ((var = agetnum(cap)) < 0) \ 178 var = def; \ 179 } while (0) 180 #define ELM_MALLOC(p) \ 181 do { \ 182 p = calloc(1, sizeof(*p)); \ 183 if (p == NULL) { \ 184 logit(LOG_ERR, "<%s> calloc failed: %m", \ 185 __func__); \ 186 goto errexit; \ 187 } \ 188 } while(/*CONSTCOND*/0) 189 190 if (if_nametoindex(intface) == 0) { 191 logit(LOG_INFO, "<%s> interface %s not found, ignoring", 192 __func__, intface); 193 return; 194 } 195 196 logit(LOG_DEBUG, "<%s> loading configuration for interface %s", 197 __func__, intface); 198 199 if ((stat = agetent(tbuf, intface)) <= 0) { 200 memset(tbuf, 0, sizeof(tbuf)); 201 logit(LOG_INFO, 202 "<%s> %s isn't defined in the configuration file" 203 " or the configuration file doesn't exist." 204 " Treat it as default", 205 __func__, intface); 206 } 207 208 ELM_MALLOC(tmp); 209 TAILQ_INIT(&tmp->prefix); 210 TAILQ_INIT(&tmp->route); 211 TAILQ_INIT(&tmp->rdnss); 212 TAILQ_INIT(&tmp->dnssl); 213 214 /* check if we are allowed to forward packets (if not determined) */ 215 if (forwarding < 0) { 216 if ((forwarding = getinet6sysctl(IPV6CTL_FORWARDING)) < 0) 217 exit(1); 218 } 219 220 /* get interface information */ 221 if (agetflag("nolladdr")) 222 tmp->advlinkopt = 0; 223 else 224 tmp->advlinkopt = 1; 225 if (tmp->advlinkopt) { 226 if ((tmp->sdl = if_nametosdl(intface)) == NULL) { 227 logit(LOG_ERR, 228 "<%s> can't get information of %s", 229 __func__, intface); 230 goto errexit; 231 } 232 tmp->ifindex = tmp->sdl->sdl_index; 233 } else { 234 tmp->ifindex = if_nametoindex(intface); 235 if (tmp->ifindex == 0) { 236 logit(LOG_ERR, 237 "<%s> can't get information of %s", 238 __func__, intface); 239 goto errexit; 240 } 241 } 242 tmp->ifflags = if_getflags(tmp->ifindex, 0); 243 strlcpy(tmp->ifname, intface, sizeof(tmp->ifname)); 244 if ((tmp->phymtu = if_getmtu(intface)) == 0) { 245 tmp->phymtu = IPV6_MMTU; 246 logit(LOG_WARNING, 247 "<%s> can't get interface mtu of %s. Treat as %d", 248 __func__, intface, IPV6_MMTU); 249 } 250 251 /* 252 * set router configuration variables. 253 */ 254 MAYHAVE(val, "maxinterval", DEF_MAXRTRADVINTERVAL); 255 if (val < MIN_MAXINTERVAL || val > MAX_MAXINTERVAL) { 256 logit(LOG_ERR, 257 "<%s> maxinterval (%d) on %s is invalid " 258 "(must be between %u and %u)", __func__, val, 259 intface, MIN_MAXINTERVAL, MAX_MAXINTERVAL); 260 goto errexit; 261 } 262 tmp->maxinterval = val; 263 MAYHAVE(val, "mininterval", tmp->maxinterval/3); 264 if (val < MIN_MININTERVAL || val > (tmp->maxinterval * 3) / 4) { 265 logit(LOG_ERR, 266 "<%s> mininterval (%d) on %s is invalid " 267 "(must be between %u and %d)", 268 __func__, val, intface, MIN_MININTERVAL, 269 (tmp->maxinterval * 3) / 4); 270 goto errexit; 271 } 272 tmp->mininterval = val; 273 274 MAYHAVE(val, "chlim", DEF_ADVCURHOPLIMIT); 275 tmp->hoplimit = val & 0xff; 276 277 if ((flagstr = (char *)agetstr("raflags", &bp))) { 278 val = 0; 279 if (strchr(flagstr, 'm')) 280 val |= ND_RA_FLAG_MANAGED; 281 if (strchr(flagstr, 'o')) 282 val |= ND_RA_FLAG_OTHER; 283 if (strchr(flagstr, 'h')) 284 val |= ND_RA_FLAG_RTPREF_HIGH; 285 if (strchr(flagstr, 'l')) { 286 if ((val & ND_RA_FLAG_RTPREF_HIGH)) { 287 logit(LOG_ERR, "<%s> the \'h\' and \'l\'" 288 " router flags are exclusive", __func__); 289 goto errexit; 290 } 291 val |= ND_RA_FLAG_RTPREF_LOW; 292 } 293 } else { 294 MAYHAVE(val, "raflags", 0); 295 } 296 tmp->managedflg = val & ND_RA_FLAG_MANAGED; 297 tmp->otherflg = val & ND_RA_FLAG_OTHER; 298 #ifndef ND_RA_FLAG_RTPREF_MASK 299 #define ND_RA_FLAG_RTPREF_MASK 0x18 /* 00011000 */ 300 #define ND_RA_FLAG_RTPREF_RSV 0x10 /* 00010000 */ 301 #endif 302 tmp->rtpref = val & ND_RA_FLAG_RTPREF_MASK; 303 if (tmp->rtpref == ND_RA_FLAG_RTPREF_RSV) { 304 logit(LOG_ERR, "<%s> invalid router preference (%02x) on %s", 305 __func__, tmp->rtpref, intface); 306 goto errexit; 307 } 308 309 MAYHAVE(val, "rltime", DEF_ADVROUTERLIFETIME); 310 if (val && (val < tmp->maxinterval || val > MAXROUTERLIFETIME)) { 311 logit(LOG_ERR, 312 "<%s> router lifetime (%d) on %s is invalid " 313 "(must be 0 or between %d and %d)", 314 __func__, val, intface, 315 tmp->maxinterval, MAXROUTERLIFETIME); 316 goto errexit; 317 } 318 /* 319 * Basically, hosts MUST NOT send Router Advertisement messages at any 320 * time (RFC 2461, Section 6.2.3). However, it would sometimes be 321 * useful to allow hosts to advertise some parameters such as prefix 322 * information and link MTU. Thus, we allow hosts to invoke rtadvd 323 * only when router lifetime (on every advertising interface) is 324 * explicitly set zero. (see also the above section) 325 */ 326 if (val && forwarding == 0) { 327 logit(LOG_ERR, 328 "<%s> non zero router lifetime is specified for %s, " 329 "which must not be allowed for hosts. you must " 330 "change router lifetime or enable IPv6 forwarding.", 331 __func__, intface); 332 goto errexit; 333 } 334 tmp->lifetime = val & 0xffff; 335 336 MAYHAVE(val, "rtime", DEF_ADVREACHABLETIME); 337 if (val < 0 || val > MAXREACHABLETIME) { 338 logit(LOG_ERR, 339 "<%s> reachable time (%d) on %s is invalid " 340 "(must be no greater than %d)", 341 __func__, val, intface, MAXREACHABLETIME); 342 goto errexit; 343 } 344 tmp->reachabletime = (uint32_t)val; 345 346 MAYHAVE(val64, "retrans", DEF_ADVRETRANSTIMER); 347 if (val64 < 0 || val64 > 0xffffffff) { 348 logit(LOG_ERR, "<%s> retrans time (%lld) on %s out of range", 349 __func__, (long long)val64, intface); 350 goto errexit; 351 } 352 tmp->retranstimer = (uint32_t)val64; 353 354 if (agetnum("hapref") != -1 || agetnum("hatime") != -1) { 355 logit(LOG_ERR, 356 "<%s> mobile-ip6 configuration not supported", 357 __func__); 358 goto errexit; 359 } 360 /* prefix information */ 361 362 /* 363 * This is an implementation specific parameter to consider 364 * link propagation delays and poorly synchronized clocks when 365 * checking consistency of advertised lifetimes. 366 */ 367 MAYHAVE(val, "clockskew", 0); 368 tmp->clockskew = val; 369 370 tmp->pfxs = 0; 371 for (i = -1; i < MAXPREFIX; i++) { 372 struct prefix *pfx; 373 374 makeentry(entbuf, sizeof(entbuf), i, "addr"); 375 addr = (char *)agetstr(entbuf, &bp); 376 if (addr == NULL) 377 continue; 378 379 /* allocate memory to store prefix information */ 380 if ((pfx = calloc(1, sizeof(*pfx))) == NULL) { 381 logit(LOG_ERR, 382 "<%s> can't allocate memory: %m", 383 __func__); 384 goto errexit; 385 } 386 387 TAILQ_INSERT_TAIL(&tmp->prefix, pfx, next); 388 tmp->pfxs++; 389 pfx->rainfo = tmp; 390 391 pfx->origin = PREFIX_FROM_CONFIG; 392 393 if (inet_pton(AF_INET6, addr, &pfx->prefix) != 1) { 394 logit(LOG_ERR, 395 "<%s> inet_pton failed for %s", 396 __func__, addr); 397 goto errexit; 398 } 399 if (IN6_IS_ADDR_MULTICAST(&pfx->prefix)) { 400 logit(LOG_ERR, 401 "<%s> multicast prefix (%s) must " 402 "not be advertised on %s", 403 __func__, addr, intface); 404 goto errexit; 405 } 406 if (IN6_IS_ADDR_LINKLOCAL(&pfx->prefix)) 407 logit(LOG_NOTICE, 408 "<%s> link-local prefix (%s) will be" 409 " advertised on %s", 410 __func__, addr, intface); 411 412 makeentry(entbuf, sizeof(entbuf), i, "prefixlen"); 413 MAYHAVE(val, entbuf, 64); 414 if (val < 0 || val > 128) { 415 logit(LOG_ERR, "<%s> prefixlen (%d) for %s " 416 "on %s out of range", 417 __func__, val, addr, intface); 418 goto errexit; 419 } 420 pfx->prefixlen = (int)val; 421 422 makeentry(entbuf, sizeof(entbuf), i, "pinfoflags"); 423 if ((flagstr = (char *)agetstr(entbuf, &bp))) { 424 val = 0; 425 if (strchr(flagstr, 'l')) 426 val |= ND_OPT_PI_FLAG_ONLINK; 427 if (strchr(flagstr, 'a')) 428 val |= ND_OPT_PI_FLAG_AUTO; 429 } else { 430 MAYHAVE(val, entbuf, 431 (ND_OPT_PI_FLAG_ONLINK|ND_OPT_PI_FLAG_AUTO)); 432 } 433 pfx->onlinkflg = val & ND_OPT_PI_FLAG_ONLINK; 434 pfx->autoconfflg = val & ND_OPT_PI_FLAG_AUTO; 435 436 makeentry(entbuf, sizeof(entbuf), i, "vltime"); 437 MAYHAVE(val64, entbuf, DEF_ADVVALIDLIFETIME); 438 if (val64 < 0 || val64 > 0xffffffff) { 439 logit(LOG_ERR, "<%s> vltime (%lld) for " 440 "%s/%d on %s is out of range", 441 __func__, (long long)val64, 442 addr, pfx->prefixlen, intface); 443 goto errexit; 444 } 445 pfx->validlifetime = (uint32_t)val64; 446 447 makeentry(entbuf, sizeof(entbuf), i, "vltimedecr"); 448 if (agetflag(entbuf)) { 449 struct timespec now; 450 prog_clock_gettime(CLOCK_MONOTONIC, &now); 451 pfx->vltimeexpire = 452 now.tv_sec + pfx->validlifetime; 453 } 454 455 makeentry(entbuf, sizeof(entbuf), i, "pltime"); 456 MAYHAVE(val64, entbuf, DEF_ADVPREFERREDLIFETIME); 457 if (val64 < 0 || val64 > 0xffffffff) { 458 logit(LOG_ERR, 459 "<%s> pltime (%lld) for %s/%d on %s " 460 "is out of range", 461 __func__, (long long)val64, 462 addr, pfx->prefixlen, intface); 463 goto errexit; 464 } 465 pfx->preflifetime = (uint32_t)val64; 466 467 makeentry(entbuf, sizeof(entbuf), i, "pltimedecr"); 468 if (agetflag(entbuf)) { 469 struct timespec now; 470 prog_clock_gettime(CLOCK_MONOTONIC, &now); 471 pfx->pltimeexpire = 472 now.tv_sec + pfx->preflifetime; 473 } 474 } 475 if (TAILQ_FIRST(&tmp->prefix) == NULL && !agetflag("noifprefix")) 476 get_prefix(tmp); 477 478 MAYHAVE(val64, "mtu", 0); 479 if (val64 < 0 || val64 > 0xffffffff) { 480 logit(LOG_ERR, 481 "<%s> mtu (%" PRIi64 ") on %s out of range", 482 __func__, val64, intface); 483 goto errexit; 484 } 485 tmp->linkmtu = (uint32_t)val64; 486 if (tmp->linkmtu == 0) { 487 char *mtustr; 488 489 if ((mtustr = (char *)agetstr("mtu", &bp)) && 490 strcmp(mtustr, "auto") == 0) 491 tmp->linkmtu = tmp->phymtu; 492 } 493 else if (tmp->linkmtu < IPV6_MMTU || tmp->linkmtu > tmp->phymtu) { 494 logit(LOG_ERR, 495 "<%s> advertised link mtu (%d) on %s is invalid (must " 496 "be between least MTU (%d) and physical link MTU (%d)", 497 __func__, tmp->linkmtu, intface, 498 IPV6_MMTU, tmp->phymtu); 499 goto errexit; 500 } 501 502 #ifdef SIOCSIFINFO_IN6 503 { 504 struct in6_ndireq ndi; 505 int s; 506 507 if ((s = prog_socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 508 logit(LOG_ERR, "<%s> socket: %m", __func__); 509 goto errexit; 510 } 511 memset(&ndi, 0, sizeof(ndi)); 512 strncpy(ndi.ifname, intface, IFNAMSIZ); 513 if (prog_ioctl(s, SIOCGIFINFO_IN6, &ndi) < 0) { 514 logit(LOG_INFO, "<%s> ioctl:SIOCGIFINFO_IN6 at %s: %m", 515 __func__, intface); 516 } 517 518 /* reflect the RA info to the host variables in kernel */ 519 ndi.ndi.chlim = tmp->hoplimit; 520 ndi.ndi.retrans = tmp->retranstimer; 521 ndi.ndi.basereachable = tmp->reachabletime; 522 if (prog_ioctl(s, SIOCSIFINFO_IN6, &ndi) < 0) { 523 logit(LOG_INFO, "<%s> ioctl:SIOCSIFINFO_IN6 at %s: %m", 524 __func__, intface); 525 } 526 prog_close(s); 527 } 528 #endif 529 530 /* route information */ 531 for (i = -1; i < MAXROUTE; i++) { 532 struct rtinfo *rti; 533 char oentbuf[256]; 534 535 makeentry(entbuf, sizeof(entbuf), i, "rtprefix"); 536 addr = (char *)agetstr(entbuf, &bp); 537 if (addr == NULL) { 538 makeentry(oentbuf, sizeof(oentbuf), i, "rtrprefix"); 539 addr = (char *)agetstr(oentbuf, &bp); 540 if (addr) { 541 fprintf(stderr, "%s was obsoleted. Use %s.\n", 542 oentbuf, entbuf); 543 } 544 } 545 if (addr == NULL) 546 continue; 547 548 ELM_MALLOC(rti); 549 memset(rti, 0, sizeof(*rti)); 550 551 /* link into chain */ 552 TAILQ_INSERT_TAIL(&tmp->route, rti, next); 553 554 if (inet_pton(AF_INET6, addr, &rti->prefix) != 1) { 555 logit(LOG_ERR, "<%s> inet_pton failed for %s", 556 __func__, addr); 557 goto errexit; 558 } 559 #if 0 560 /* 561 * XXX: currently there's no restriction in route information 562 * prefix according to 563 * draft-ietf-ipngwg-router-selection-00.txt. 564 * However, I think the similar restriction be necessary. 565 */ 566 MAYHAVE(val64, entbuf, DEF_ADVVALIDLIFETIME); 567 if (IN6_IS_ADDR_MULTICAST(&rti->prefix)) { 568 logit(LOG_ERR, 569 "<%s> multicast route (%s) must " 570 "not be advertised on %s", 571 __func__, addr, intface); 572 goto errexit; 573 } 574 if (IN6_IS_ADDR_LINKLOCAL(&rti->prefix)) { 575 logit(LOG_NOTICE, 576 "<%s> link-local route (%s) will " 577 "be advertised on %s", 578 __func__, addr, intface); 579 goto errexit; 580 } 581 #endif 582 583 makeentry(entbuf, sizeof(entbuf), i, "rtplen"); 584 /* XXX: 256 is a magic number for compatibility check. */ 585 MAYHAVE(val, entbuf, 256); 586 if (val == 256) { 587 makeentry(oentbuf, sizeof(oentbuf), i, "rtrplen"); 588 MAYHAVE(val, oentbuf, 256); 589 if (val != 256) { 590 fprintf(stderr, "%s was obsoleted. Use %s.\n", 591 oentbuf, entbuf); 592 } else 593 val = 64; 594 } 595 if (val < 0 || val > 128) { 596 logit(LOG_ERR, "<%s> prefixlen (%d) for %s on %s " 597 "out of range", 598 __func__, val, addr, intface); 599 goto errexit; 600 } 601 rti->prefixlen = (int)val; 602 603 makeentry(entbuf, sizeof(entbuf), i, "rtflags"); 604 if ((flagstr = (char *)agetstr(entbuf, &bp))) { 605 val = 0; 606 if (strchr(flagstr, 'h')) 607 val |= ND_RA_FLAG_RTPREF_HIGH; 608 if (strchr(flagstr, 'l')) { 609 if ((val & ND_RA_FLAG_RTPREF_HIGH)) { 610 logit(LOG_ERR, 611 "<%s> the \'h\' and \'l\' route" 612 " preferences are exclusive", 613 __func__); 614 goto errexit; 615 } 616 val |= ND_RA_FLAG_RTPREF_LOW; 617 } 618 } else 619 MAYHAVE(val, entbuf, 256); /* XXX */ 620 if (val == 256) { 621 makeentry(oentbuf, sizeof(oentbuf), i, "rtrflags"); 622 MAYHAVE(val, oentbuf, 256); 623 if (val != 256) { 624 fprintf(stderr, "%s was obsoleted. Use %s.\n", 625 oentbuf, entbuf); 626 } else 627 val = 0; 628 } 629 rti->rtpref = val & ND_RA_FLAG_RTPREF_MASK; 630 if (rti->rtpref == ND_RA_FLAG_RTPREF_RSV) { 631 logit(LOG_ERR, "<%s> invalid route preference (%02x) " 632 "for %s/%d on %s", 633 __func__, rti->rtpref, addr, 634 rti->prefixlen, intface); 635 goto errexit; 636 } 637 638 /* 639 * Since the spec does not a default value, we should make 640 * this entry mandatory. However, FreeBSD 4.4 has shipped 641 * with this field being optional, we use the router lifetime 642 * as an ad-hoc default value with a warning message. 643 */ 644 makeentry(entbuf, sizeof(entbuf), i, "rtltime"); 645 MAYHAVE(val64, entbuf, -1); 646 if (val64 == -1) { 647 makeentry(oentbuf, sizeof(oentbuf), i, "rtrltime"); 648 MAYHAVE(val64, oentbuf, -1); 649 if (val64 != -1) { 650 fprintf(stderr, "%s was obsoleted. Use %s.\n", 651 oentbuf, entbuf); 652 } else { 653 fprintf(stderr, "%s should be specified " 654 "for interface %s.\n", 655 entbuf, intface); 656 val64 = tmp->lifetime; 657 } 658 } 659 if (val64 < 0 || val64 > 0xffffffff) { 660 logit(LOG_ERR, "<%s> route lifetime (%lld) for " 661 "%s/%d on %s out of range", __func__, 662 (long long)val64, addr, rti->prefixlen, intface); 663 goto errexit; 664 } 665 rti->ltime = (uint32_t)val64; 666 } 667 668 /* RDNSS */ 669 for (i = -1; i < MAXRDNSS; i++) { 670 struct rdnss_addr *rdnsa; 671 672 makeentry(entbuf, sizeof(entbuf), i, "rdnss"); 673 addr = (char *)agetstr(entbuf, &bp); 674 if (addr == NULL) 675 continue; 676 677 ELM_MALLOC(rdnss); 678 TAILQ_INSERT_TAIL(&tmp->rdnss, rdnss, next); 679 TAILQ_INIT(&rdnss->list); 680 681 for (ap = addr; ap - addr < (ssize_t)strlen(addr); ap += c+1) { 682 c = strcspn(ap, ","); 683 strncpy(abuf, ap, c); 684 abuf[c] = '\0'; 685 ELM_MALLOC(rdnsa); 686 TAILQ_INSERT_TAIL(&rdnss->list, rdnsa, next); 687 if (inet_pton(AF_INET6, abuf, &rdnsa->addr) != 1) { 688 logit(LOG_ERR, "<%s> inet_pton failed for %s", 689 __func__, addr); 690 goto errexit; 691 } 692 } 693 694 makeentry(entbuf, sizeof(entbuf), i, "rdnssltime"); 695 MAYHAVE(val64, entbuf, tmp->maxinterval * 3 / 2); 696 if (val64 < tmp->maxinterval || 697 val64 > tmp->maxinterval * 2) 698 { 699 logit(LOG_ERR, "<%s> %s (%lld) on %s is invalid", 700 __func__, entbuf, (long long)val64, intface); 701 goto errexit; 702 } 703 rdnss->lifetime = (uint32_t)val64; 704 705 } 706 707 /* DNSSL */ 708 TAILQ_INIT(&tmp->dnssl); 709 for (i = -1; i < MAXDNSSL; i++) { 710 struct dnssl_domain *dnsd; 711 712 makeentry(entbuf, sizeof(entbuf), i, "dnssl"); 713 addr = (char *)agetstr(entbuf, &bp); 714 if (addr == NULL) 715 continue; 716 717 ELM_MALLOC(dnssl); 718 TAILQ_INSERT_TAIL(&tmp->dnssl, dnssl, next); 719 TAILQ_INIT(&dnssl->list); 720 721 for (ap = addr; ap - addr < (ssize_t)strlen(addr); ap += c+1) { 722 c = strcspn(ap, ","); 723 strncpy(abuf, ap, c); 724 abuf[c] = '\0'; 725 ELM_MALLOC(dnsd); 726 TAILQ_INSERT_TAIL(&dnssl->list, dnsd, next); 727 dnsd->len = encode_domain(dnsd->domain, abuf); 728 } 729 730 makeentry(entbuf, sizeof(entbuf), i, "dnsslltime"); 731 MAYHAVE(val64, entbuf, tmp->maxinterval * 3 / 2); 732 if (val64 < tmp->maxinterval || 733 val64 > tmp->maxinterval * 2) 734 { 735 logit(LOG_ERR, "<%s> %s (%lld) on %s is invalid", 736 __func__, entbuf, (long long)val64, intface); 737 goto errexit; 738 } 739 dnssl->lifetime = (uint32_t)val64; 740 741 } 742 743 TAILQ_FOREACH(rai, &ralist, next) { 744 if (rai->ifindex == tmp->ifindex) { 745 TAILQ_REMOVE(&ralist, rai, next); 746 /* If we already have a leaving RA use that 747 * as this config hasn't been advertised */ 748 if (rai->leaving) { 749 tmp->leaving = rai->leaving; 750 free_rainfo(rai); 751 rai = tmp->leaving; 752 rai->leaving_for = tmp; 753 break; 754 } 755 rai->lifetime = 0; 756 TAILQ_FOREACH(rdnss, &rai->rdnss, next) 757 rdnss->lifetime = 0; 758 TAILQ_FOREACH(dnssl, &rai->dnssl, next) 759 dnssl->lifetime = 0; 760 rai->leaving_for = tmp; 761 tmp->leaving = rai; 762 rai->initcounter = MAX_INITIAL_RTR_ADVERTISEMENTS; 763 rai->mininterval = MIN_DELAY_BETWEEN_RAS; 764 rai->maxinterval = MIN_DELAY_BETWEEN_RAS; 765 rai->leaving_adv = MAX_FINAL_RTR_ADVERTISEMENTS; 766 if (rai->timer == NULL) 767 rai->timer = rtadvd_add_timer(ra_timeout, 768 ra_timer_update, 769 rai, rai); 770 ra_timer_update((void *)rai, &rai->timer->tm); 771 rtadvd_set_timer(&rai->timer->tm, rai->timer); 772 break; 773 } 774 } 775 776 /* okey */ 777 TAILQ_INSERT_TAIL(&ralist, tmp, next); 778 779 /* construct the sending packet */ 780 make_packet(tmp); 781 782 /* set timer */ 783 if (rai) 784 return; 785 tmp->timer = rtadvd_add_timer(ra_timeout, ra_timer_update, 786 tmp, tmp); 787 ra_timer_set_short_delay(tmp); 788 789 return; 790 791 errexit: 792 if (exithard) 793 exit(1); 794 free_rainfo(tmp); 795 } 796 797 void 798 get_prefix(struct rainfo *rai) 799 { 800 struct ifaddrs *ifap, *ifa; 801 struct prefix *pp; 802 struct in6_addr *a; 803 unsigned char *p, *ep, *m, *lim; 804 char ntopbuf[INET6_ADDRSTRLEN]; 805 806 if (getifaddrs(&ifap) < 0) { 807 logit(LOG_ERR, 808 "<%s> can't get interface addresses", 809 __func__); 810 exit(1); 811 } 812 813 for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 814 int plen; 815 816 if (strcmp(ifa->ifa_name, rai->ifname) != 0) 817 continue; 818 if (ifa->ifa_addr->sa_family != AF_INET6) 819 continue; 820 a = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr; 821 if (IN6_IS_ADDR_LINKLOCAL(a)) 822 continue; 823 /* get prefix length */ 824 m = (unsigned char *)&((struct sockaddr_in6 *)ifa->ifa_netmask)->sin6_addr; 825 lim = (unsigned char *)(ifa->ifa_netmask) + ifa->ifa_netmask->sa_len; 826 plen = prefixlen(m, lim); 827 if (plen <= 0 || plen > 128) { 828 logit(LOG_ERR, "<%s> failed to get prefixlen " 829 "or prefix is invalid", 830 __func__); 831 exit(1); 832 } 833 if (plen == 128) /* XXX */ 834 continue; 835 if (find_prefix(rai, a, plen)) { 836 /* ignore a duplicated prefix. */ 837 continue; 838 } 839 840 /* allocate memory to store prefix info. */ 841 if ((pp = calloc(1, sizeof(*pp))) == NULL) { 842 logit(LOG_ERR, 843 "<%s> can't get allocate buffer for prefix", 844 __func__); 845 exit(1); 846 } 847 848 /* set prefix, sweep bits outside of prefixlen */ 849 pp->prefixlen = plen; 850 memcpy(&pp->prefix, a, sizeof(*a)); 851 if (1) 852 { 853 p = (unsigned char *)&pp->prefix; 854 ep = (unsigned char *)(&pp->prefix + 1); 855 while (m < lim && p < ep) 856 *p++ &= *m++; 857 while (p < ep) 858 *p++ = 0x00; 859 } 860 if (!inet_ntop(AF_INET6, &pp->prefix, ntopbuf, 861 sizeof(ntopbuf))) { 862 logit(LOG_ERR, "<%s> inet_ntop failed", __func__); 863 exit(1); 864 } 865 logit(LOG_DEBUG, 866 "<%s> add %s/%d to prefix list on %s", 867 __func__, ntopbuf, pp->prefixlen, rai->ifname); 868 869 /* set other fields with protocol defaults */ 870 pp->validlifetime = DEF_ADVVALIDLIFETIME; 871 pp->preflifetime = DEF_ADVPREFERREDLIFETIME; 872 pp->onlinkflg = 1; 873 pp->autoconfflg = 1; 874 pp->origin = PREFIX_FROM_KERNEL; 875 pp->rainfo = rai; 876 877 /* link into chain */ 878 TAILQ_INSERT_TAIL(&rai->prefix, pp, next); 879 rai->pfxs++; 880 } 881 882 freeifaddrs(ifap); 883 } 884 885 static void 886 makeentry(char *buf, size_t len, int id, const char *string) 887 { 888 889 if (id < 0) 890 strlcpy(buf, string, len); 891 else 892 snprintf(buf, len, "%s%d", string, id); 893 } 894 895 /* 896 * Add a prefix to the list of specified interface and reconstruct 897 * the outgoing packet. 898 * The prefix must not be in the list. 899 * XXX: other parameters of the prefix(e.g. lifetime) should be 900 * able to be specified. 901 */ 902 static void 903 add_prefix(struct rainfo *rai, struct in6_prefixreq *ipr) 904 { 905 struct prefix *prefix; 906 char ntopbuf[INET6_ADDRSTRLEN]; 907 908 if ((prefix = calloc(1, sizeof(*prefix))) == NULL) { 909 logit(LOG_ERR, "<%s> memory allocation failed", 910 __func__); 911 return; /* XXX: error or exit? */ 912 } 913 prefix->prefix = ipr->ipr_prefix.sin6_addr; 914 prefix->prefixlen = ipr->ipr_plen; 915 prefix->validlifetime = ipr->ipr_vltime; 916 prefix->preflifetime = ipr->ipr_pltime; 917 prefix->onlinkflg = ipr->ipr_raf_onlink; 918 prefix->autoconfflg = ipr->ipr_raf_auto; 919 prefix->origin = PREFIX_FROM_DYNAMIC; 920 921 prefix->rainfo = rai; 922 TAILQ_INSERT_TAIL(&rai->prefix, prefix, next); 923 rai->pfxs++; 924 925 logit(LOG_DEBUG, "<%s> new prefix %s/%d was added on %s", 926 __func__, inet_ntop(AF_INET6, &ipr->ipr_prefix.sin6_addr, 927 ntopbuf, INET6_ADDRSTRLEN), 928 ipr->ipr_plen, rai->ifname); 929 930 /* free the previous packet */ 931 free(rai->ra_data); 932 rai->ra_data = NULL; 933 934 /* reconstruct the packet */ 935 make_packet(rai); 936 } 937 938 /* 939 * Delete a prefix to the list of specified interface and reconstruct 940 * the outgoing packet. 941 * The prefix must be in the list. 942 */ 943 void 944 delete_prefix(struct prefix *prefix) 945 { 946 char ntopbuf[INET6_ADDRSTRLEN]; 947 struct rainfo *rai = prefix->rainfo; 948 949 TAILQ_REMOVE(&rai->prefix, prefix, next); 950 rai->pfxs--; 951 logit(LOG_DEBUG, "<%s> prefix %s/%d was deleted on %s", 952 __func__, inet_ntop(AF_INET6, &prefix->prefix, 953 ntopbuf, INET6_ADDRSTRLEN), 954 prefix->prefixlen, rai->ifname); 955 rtadvd_remove_timer(&prefix->timer); 956 free(prefix); 957 } 958 959 void 960 invalidate_prefix(struct prefix *prefix) 961 { 962 char ntopbuf[INET6_ADDRSTRLEN]; 963 struct timespec timo; 964 struct rainfo *rai = prefix->rainfo; 965 966 if (prefix->timer) { /* sanity check */ 967 logit(LOG_ERR, 968 "<%s> assumption failure: timer already exists", 969 __func__); 970 exit(1); 971 } 972 973 logit(LOG_DEBUG, "<%s> prefix %s/%d was invalidated on %s, " 974 "will expire in %ld seconds", __func__, 975 inet_ntop(AF_INET6, &prefix->prefix, ntopbuf, INET6_ADDRSTRLEN), 976 prefix->prefixlen, rai->ifname, (long)prefix_timo); 977 978 /* set the expiration timer */ 979 prefix->timer = rtadvd_add_timer(prefix_timeout, NULL, prefix, NULL); 980 if (prefix->timer == NULL) { 981 logit(LOG_ERR, "<%s> failed to add a timer for a prefix. " 982 "remove the prefix", __func__); 983 delete_prefix(prefix); 984 } 985 timo.tv_sec = prefix_timo; 986 timo.tv_nsec = 0; 987 rtadvd_set_timer(&timo, prefix->timer); 988 } 989 990 static struct rtadvd_timer * 991 prefix_timeout(void *arg) 992 { 993 struct prefix *prefix = (struct prefix *)arg; 994 995 delete_prefix(prefix); 996 997 return(NULL); 998 } 999 1000 void 1001 update_prefix(struct prefix * prefix) 1002 { 1003 char ntopbuf[INET6_ADDRSTRLEN]; 1004 struct rainfo *rai = prefix->rainfo; 1005 1006 if (prefix->timer == NULL) { /* sanity check */ 1007 logit(LOG_ERR, 1008 "<%s> assumption failure: timer does not exist", 1009 __func__); 1010 exit(1); 1011 } 1012 1013 logit(LOG_DEBUG, "<%s> prefix %s/%d was re-enabled on %s", 1014 __func__, inet_ntop(AF_INET6, &prefix->prefix, ntopbuf, 1015 INET6_ADDRSTRLEN), prefix->prefixlen, rai->ifname); 1016 1017 /* stop the expiration timer */ 1018 rtadvd_remove_timer(&prefix->timer); 1019 } 1020 1021 /* 1022 * Try to get an in6_prefixreq contents for a prefix which matches 1023 * ipr->ipr_prefix and ipr->ipr_plen and belongs to 1024 * the interface whose name is ipr->ipr_name[]. 1025 */ 1026 static int 1027 init_prefix(struct in6_prefixreq *ipr) 1028 { 1029 #if 0 1030 int s; 1031 1032 if ((s = prog_socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 1033 logit(LOG_ERR, "<%s> socket: %m", __func__); 1034 exit(1); 1035 } 1036 1037 if (prog_ioctl(s, SIOCGIFPREFIX_IN6, ipr) < 0) { 1038 logit(LOG_INFO, "<%s> ioctl:SIOCGIFPREFIX: %m", __func__); 1039 1040 ipr->ipr_vltime = DEF_ADVVALIDLIFETIME; 1041 ipr->ipr_pltime = DEF_ADVPREFERREDLIFETIME; 1042 ipr->ipr_raf_onlink = 1; 1043 ipr->ipr_raf_auto = 1; 1044 /* omit other field initialization */ 1045 } 1046 else if (ipr->ipr_origin < PR_ORIG_RR) { 1047 char ntopbuf[INET6_ADDRSTRLEN]; 1048 1049 logit(LOG_WARNING, "<%s> Added prefix(%s)'s origin %d is" 1050 "lower than PR_ORIG_RR(router renumbering)." 1051 "This should not happen if I am router", __func__, 1052 inet_ntop(AF_INET6, &ipr->ipr_prefix.sin6_addr, ntopbuf, 1053 sizeof(ntopbuf)), ipr->ipr_origin); 1054 prog_close(s); 1055 return 1; 1056 } 1057 1058 prog_close(s); 1059 return 0; 1060 #else 1061 ipr->ipr_vltime = DEF_ADVVALIDLIFETIME; 1062 ipr->ipr_pltime = DEF_ADVPREFERREDLIFETIME; 1063 ipr->ipr_raf_onlink = 1; 1064 ipr->ipr_raf_auto = 1; 1065 return 0; 1066 #endif 1067 } 1068 1069 void 1070 make_prefix(struct rainfo *rai, int ifindex, struct in6_addr *addr, int plen) 1071 { 1072 struct in6_prefixreq ipr; 1073 1074 memset(&ipr, 0, sizeof(ipr)); 1075 if (if_indextoname(ifindex, ipr.ipr_name) == NULL) { 1076 logit(LOG_ERR, "<%s> Prefix added interface No.%d doesn't" 1077 "exist. This should not happen: %m", __func__, 1078 ifindex); 1079 exit(1); 1080 } 1081 ipr.ipr_prefix.sin6_len = sizeof(ipr.ipr_prefix); 1082 ipr.ipr_prefix.sin6_family = AF_INET6; 1083 ipr.ipr_prefix.sin6_addr = *addr; 1084 ipr.ipr_plen = plen; 1085 1086 if (init_prefix(&ipr)) 1087 return; /* init failed by some error */ 1088 add_prefix(rai, &ipr); 1089 } 1090 1091 void 1092 make_packet(struct rainfo *rainfo) 1093 { 1094 size_t packlen, lladdroptlen = 0; 1095 char *buf; 1096 struct nd_router_advert *ra; 1097 struct nd_opt_prefix_info *ndopt_pi; 1098 struct nd_opt_mtu *ndopt_mtu; 1099 struct prefix *pfx; 1100 struct nd_opt_route_info *ndopt_rti; 1101 struct rtinfo *rti; 1102 struct nd_opt_rdnss *ndopt_rdnss; 1103 struct rdnss *rdns; 1104 struct rdnss_addr *rdnsa; 1105 struct nd_opt_dnssl *ndopt_dnssl; 1106 struct dnssl *dnsl; 1107 struct dnssl_domain *dnsd; 1108 size_t len, plen; 1109 1110 /* calculate total length */ 1111 packlen = sizeof(struct nd_router_advert); 1112 if (rainfo->advlinkopt) { 1113 if ((lladdroptlen = lladdropt_length(rainfo->sdl)) == 0) { 1114 logit(LOG_INFO, 1115 "<%s> link-layer address option has" 1116 " null length on %s. Treat as not included.", 1117 __func__, rainfo->ifname); 1118 rainfo->advlinkopt = 0; 1119 } 1120 packlen += lladdroptlen; 1121 } 1122 if (TAILQ_FIRST(&rainfo->prefix) != NULL) 1123 packlen += sizeof(struct nd_opt_prefix_info) * rainfo->pfxs; 1124 if (rainfo->linkmtu) 1125 packlen += sizeof(struct nd_opt_mtu); 1126 TAILQ_FOREACH(rti, &rainfo->route, next) 1127 packlen += sizeof(struct nd_opt_route_info) + 1128 ((rti->prefixlen + 0x3f) >> 6) * 8; 1129 1130 TAILQ_FOREACH(rdns, &rainfo->rdnss, next) { 1131 packlen += sizeof(struct nd_opt_rdnss); 1132 TAILQ_FOREACH(rdnsa, &rdns->list, next) 1133 packlen += sizeof(rdnsa->addr); 1134 } 1135 TAILQ_FOREACH(dnsl, &rainfo->dnssl, next) { 1136 packlen += sizeof(struct nd_opt_dnssl); 1137 len = 0; 1138 TAILQ_FOREACH(dnsd, &dnsl->list, next) 1139 len += dnsd->len; 1140 len += len % 8 ? 8 - len % 8 : 0; 1141 packlen += len; 1142 } 1143 1144 /* allocate memory for the packet */ 1145 if ((buf = realloc(rainfo->ra_data, packlen)) == NULL) { 1146 logit(LOG_ERR, 1147 "<%s> can't get enough memory for an RA packet %m", 1148 __func__); 1149 exit(1); 1150 } 1151 rainfo->ra_data = buf; 1152 /* XXX: what if packlen > 576? */ 1153 rainfo->ra_datalen = packlen; 1154 #define CHECKLEN(size) \ 1155 do { \ 1156 if (buf + size > rainfo->ra_data + packlen) { \ 1157 logit(LOG_ERR, \ 1158 "<%s, %d> RA packet does not fit in %zu",\ 1159 __func__, __LINE__, packlen); \ 1160 exit(1); \ 1161 } \ 1162 } while (/*CONSTCOND*/0) 1163 /* 1164 * construct the packet 1165 */ 1166 CHECKLEN(sizeof(*ra)); 1167 ra = (struct nd_router_advert *)buf; 1168 ra->nd_ra_type = ND_ROUTER_ADVERT; 1169 ra->nd_ra_code = 0; 1170 ra->nd_ra_cksum = 0; 1171 ra->nd_ra_curhoplimit = (uint8_t)(0xff & rainfo->hoplimit); 1172 ra->nd_ra_flags_reserved = 0; /* just in case */ 1173 /* 1174 * XXX: the router preference field, which is a 2-bit field, should be 1175 * initialized before other fields. 1176 */ 1177 ra->nd_ra_flags_reserved = 0xff & rainfo->rtpref; 1178 ra->nd_ra_flags_reserved |= 1179 rainfo->managedflg ? ND_RA_FLAG_MANAGED : 0; 1180 ra->nd_ra_flags_reserved |= 1181 rainfo->otherflg ? ND_RA_FLAG_OTHER : 0; 1182 ra->nd_ra_router_lifetime = htons(rainfo->lifetime); 1183 ra->nd_ra_reachable = htonl(rainfo->reachabletime); 1184 ra->nd_ra_retransmit = htonl(rainfo->retranstimer); 1185 buf += sizeof(*ra); 1186 1187 if (rainfo->advlinkopt) { 1188 CHECKLEN(sizeof(struct nd_opt_hdr)); 1189 lladdropt_fill(rainfo->sdl, (struct nd_opt_hdr *)buf); 1190 buf += lladdroptlen; 1191 } 1192 1193 if (rainfo->linkmtu) { 1194 CHECKLEN(sizeof(*ndopt_mtu)); 1195 ndopt_mtu = (struct nd_opt_mtu *)buf; 1196 ndopt_mtu->nd_opt_mtu_type = ND_OPT_MTU; 1197 ndopt_mtu->nd_opt_mtu_len = 1; 1198 ndopt_mtu->nd_opt_mtu_reserved = 0; 1199 ndopt_mtu->nd_opt_mtu_mtu = htonl(rainfo->linkmtu); 1200 buf += sizeof(struct nd_opt_mtu); 1201 } 1202 1203 TAILQ_FOREACH(pfx, &rainfo->prefix, next) { 1204 uint32_t vltime, pltime; 1205 struct timespec now; 1206 1207 CHECKLEN(sizeof(*ndopt_pi)); 1208 ndopt_pi = (struct nd_opt_prefix_info *)buf; 1209 ndopt_pi->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION; 1210 ndopt_pi->nd_opt_pi_len = 4; 1211 ndopt_pi->nd_opt_pi_prefix_len = pfx->prefixlen; 1212 ndopt_pi->nd_opt_pi_flags_reserved = 0; 1213 if (pfx->onlinkflg) 1214 ndopt_pi->nd_opt_pi_flags_reserved |= 1215 ND_OPT_PI_FLAG_ONLINK; 1216 if (pfx->autoconfflg) 1217 ndopt_pi->nd_opt_pi_flags_reserved |= 1218 ND_OPT_PI_FLAG_AUTO; 1219 if (pfx->timer) 1220 vltime = 0; 1221 else { 1222 if (pfx->vltimeexpire || pfx->pltimeexpire) 1223 prog_clock_gettime(CLOCK_MONOTONIC, &now); 1224 if (pfx->vltimeexpire == 0) 1225 vltime = pfx->validlifetime; 1226 else 1227 vltime = (pfx->vltimeexpire > now.tv_sec) ? 1228 pfx->vltimeexpire - now.tv_sec : 0; 1229 } 1230 if (pfx->timer) 1231 pltime = 0; 1232 else { 1233 if (pfx->pltimeexpire == 0) 1234 pltime = pfx->preflifetime; 1235 else 1236 pltime = (pfx->pltimeexpire > now.tv_sec) ? 1237 pfx->pltimeexpire - now.tv_sec : 0; 1238 } 1239 if (vltime < pltime) { 1240 /* 1241 * this can happen if vltime is decrement but pltime 1242 * is not. 1243 */ 1244 pltime = vltime; 1245 } 1246 ndopt_pi->nd_opt_pi_valid_time = htonl(vltime); 1247 ndopt_pi->nd_opt_pi_preferred_time = htonl(pltime); 1248 ndopt_pi->nd_opt_pi_reserved2 = 0; 1249 ndopt_pi->nd_opt_pi_prefix = pfx->prefix; 1250 1251 buf += sizeof(struct nd_opt_prefix_info); 1252 } 1253 1254 TAILQ_FOREACH(rti, &rainfo->route, next) { 1255 uint8_t psize = (rti->prefixlen + 0x3f) >> 6; 1256 1257 CHECKLEN(sizeof(*ndopt_rti)); 1258 ndopt_rti = (struct nd_opt_route_info *)buf; 1259 ndopt_rti->nd_opt_rti_type = ND_OPT_ROUTE_INFO; 1260 ndopt_rti->nd_opt_rti_len = 1 + psize; 1261 ndopt_rti->nd_opt_rti_prefixlen = rti->prefixlen; 1262 ndopt_rti->nd_opt_rti_flags = 0xff & rti->rtpref; 1263 ndopt_rti->nd_opt_rti_lifetime = htonl(rti->ltime); 1264 memcpy(ndopt_rti + 1, &rti->prefix, psize * 8); 1265 buf += sizeof(struct nd_opt_route_info) + psize * 8; 1266 } 1267 1268 TAILQ_FOREACH(rdns, &rainfo->rdnss, next) { 1269 CHECKLEN(sizeof(*ndopt_rdnss)); 1270 ndopt_rdnss = (struct nd_opt_rdnss *)buf; 1271 ndopt_rdnss->nd_opt_rdnss_type = ND_OPT_RDNSS; 1272 ndopt_rdnss->nd_opt_rdnss_len = 1; 1273 ndopt_rdnss->nd_opt_rdnss_reserved = 0; 1274 ndopt_rdnss->nd_opt_rdnss_lifetime = htonl(rdns->lifetime); 1275 buf += sizeof(*ndopt_rdnss); 1276 1277 TAILQ_FOREACH(rdnsa, &rdns->list, next) { 1278 CHECKLEN(sizeof(rdnsa->addr)); 1279 memcpy(buf, &rdnsa->addr, sizeof(rdnsa->addr)); 1280 ndopt_rdnss->nd_opt_rdnss_len += 2; 1281 buf += sizeof(rdnsa->addr); 1282 } 1283 } 1284 1285 TAILQ_FOREACH(dnsl, &rainfo->dnssl, next) { 1286 CHECKLEN(sizeof(*ndopt_dnssl)); 1287 ndopt_dnssl = (struct nd_opt_dnssl *)buf; 1288 ndopt_dnssl->nd_opt_dnssl_type = ND_OPT_DNSSL; 1289 ndopt_dnssl->nd_opt_dnssl_len = 0; 1290 ndopt_dnssl->nd_opt_dnssl_reserved = 0; 1291 ndopt_dnssl->nd_opt_dnssl_lifetime = htonl(dnsl->lifetime); 1292 buf += sizeof(*ndopt_dnssl); 1293 1294 TAILQ_FOREACH(dnsd, &dnsl->list, next) { 1295 CHECKLEN(dnsd->len); 1296 memcpy(buf, dnsd->domain, dnsd->len); 1297 buf += dnsd->len; 1298 } 1299 /* Ensure our length is padded correctly */ 1300 len = buf - (char *)ndopt_dnssl; 1301 plen = len % 8 ? 8 - len % 8 : 0; 1302 CHECKLEN(plen); 1303 memset(buf, 0, plen); 1304 buf += plen; 1305 ndopt_dnssl->nd_opt_dnssl_len = (len + plen) / 8; 1306 } 1307 memset(buf, 0, packlen - (buf - rainfo->ra_data)); 1308 } 1309 1310 static int 1311 getinet6sysctl(int code) 1312 { 1313 const int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, code }; 1314 int value; 1315 size_t size; 1316 1317 size = sizeof(value); 1318 if (prog_sysctl(mib, __arraycount(mib), &value, &size, NULL, 0) 1319 < 0) { 1320 logit(LOG_ERR, "<%s>: failed to get ip6 sysctl(%d): %m", 1321 __func__, code); 1322 return -1; 1323 } 1324 else 1325 return value; 1326 } 1327