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