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