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