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