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