1 /* $NetBSD: config.c,v 1.21 2003/06/17 08:08:48 itojun Exp $ */ 2 /* $KAME: config.c,v 1.62 2002/05/29 10:13:10 itojun 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 49 #include <arpa/inet.h> 50 51 #include <stdio.h> 52 #include <syslog.h> 53 #include <errno.h> 54 #include <string.h> 55 #include <stdlib.h> 56 #include <search.h> 57 #include <unistd.h> 58 #include <ifaddrs.h> 59 60 #include "rtadvd.h" 61 #include "advcap.h" 62 #include "timer.h" 63 #include "if.h" 64 #include "config.h" 65 66 static void makeentry __P((char *, size_t, int, char *)); 67 static int getinet6sysctl __P((int)); 68 69 extern struct rainfo *ralist; 70 71 void 72 getconfig(intface) 73 char *intface; 74 { 75 int stat, i; 76 char tbuf[BUFSIZ]; 77 struct rainfo *tmp; 78 long val; 79 int64_t val64; 80 char buf[BUFSIZ]; 81 char *bp = buf; 82 char *addr; 83 static int forwarding = -1; 84 85 #define MUSTHAVE(var, cap) \ 86 do { \ 87 int64_t t; \ 88 if ((t = agetnum(cap)) < 0) { \ 89 fprintf(stderr, "rtadvd: need %s for interface %s\n", \ 90 cap, intface); \ 91 exit(1); \ 92 } \ 93 var = t; \ 94 } while (0) 95 #define MAYHAVE(var, cap, def) \ 96 do { \ 97 if ((var = agetnum(cap)) < 0) \ 98 var = def; \ 99 } while (0) 100 101 if ((stat = agetent(tbuf, intface)) <= 0) { 102 memset(tbuf, 0, sizeof(tbuf)); 103 syslog(LOG_INFO, 104 "<%s> %s isn't defined in the configuration file" 105 " or the configuration file doesn't exist." 106 " Treat it as default", 107 __func__, intface); 108 } 109 110 tmp = (struct rainfo *)malloc(sizeof(*ralist)); 111 if (tmp == NULL) { 112 syslog(LOG_INFO, "<%s> %s: can't allocate enough memory", 113 __func__, intface); 114 exit(1); 115 } 116 memset(tmp, 0, sizeof(*tmp)); 117 tmp->prefix.next = tmp->prefix.prev = &tmp->prefix; 118 119 /* check if we are allowed to forward packets (if not determined) */ 120 if (forwarding < 0) { 121 if ((forwarding = getinet6sysctl(IPV6CTL_FORWARDING)) < 0) 122 exit(1); 123 } 124 125 /* get interface information */ 126 if (agetflag("nolladdr")) 127 tmp->advlinkopt = 0; 128 else 129 tmp->advlinkopt = 1; 130 if (tmp->advlinkopt) { 131 if ((tmp->sdl = if_nametosdl(intface)) == NULL) { 132 syslog(LOG_ERR, 133 "<%s> can't get information of %s", 134 __func__, intface); 135 exit(1); 136 } 137 tmp->ifindex = tmp->sdl->sdl_index; 138 } else 139 tmp->ifindex = if_nametoindex(intface); 140 strlcpy(tmp->ifname, intface, sizeof(tmp->ifname)); 141 if ((tmp->phymtu = if_getmtu(intface)) == 0) { 142 tmp->phymtu = IPV6_MMTU; 143 syslog(LOG_WARNING, 144 "<%s> can't get interface mtu of %s. Treat as %d", 145 __func__, intface, IPV6_MMTU); 146 } 147 148 /* 149 * set router configuration variables. 150 */ 151 MAYHAVE(val, "maxinterval", DEF_MAXRTRADVINTERVAL); 152 if (val < MIN_MAXINTERVAL || val > MAX_MAXINTERVAL) { 153 syslog(LOG_ERR, 154 "<%s> maxinterval (%ld) on %s is invalid " 155 "(must be between %e and %u)", __func__, val, 156 intface, MIN_MAXINTERVAL, MAX_MAXINTERVAL); 157 exit(1); 158 } 159 tmp->maxinterval = (u_int)val; 160 MAYHAVE(val, "mininterval", tmp->maxinterval/3); 161 if (val < MIN_MININTERVAL || val > (tmp->maxinterval * 3) / 4) { 162 syslog(LOG_ERR, 163 "<%s> mininterval (%ld) on %s is invalid " 164 "(must be between %e and %d)", 165 __func__, val, intface, MIN_MININTERVAL, 166 (tmp->maxinterval * 3) / 4); 167 exit(1); 168 } 169 tmp->mininterval = (u_int)val; 170 171 MAYHAVE(val, "chlim", DEF_ADVCURHOPLIMIT); 172 tmp->hoplimit = val & 0xff; 173 174 MAYHAVE(val, "raflags", 0); 175 tmp->managedflg = val & ND_RA_FLAG_MANAGED; 176 tmp->otherflg = val & ND_RA_FLAG_OTHER; 177 #ifndef ND_RA_FLAG_RTPREF_MASK 178 #define ND_RA_FLAG_RTPREF_MASK 0x18 /* 00011000 */ 179 #define ND_RA_FLAG_RTPREF_RSV 0x10 /* 00010000 */ 180 #endif 181 tmp->rtpref = val & ND_RA_FLAG_RTPREF_MASK; 182 if (tmp->rtpref == ND_RA_FLAG_RTPREF_RSV) { 183 syslog(LOG_ERR, "<%s> invalid router preference (%02x) on %s", 184 __func__, tmp->rtpref, intface); 185 exit(1); 186 } 187 188 MAYHAVE(val, "rltime", tmp->maxinterval * 3); 189 if (val && (val < tmp->maxinterval || val > MAXROUTERLIFETIME)) { 190 syslog(LOG_ERR, 191 "<%s> router lifetime (%ld) on %s is invalid " 192 "(must be 0 or between %d and %d)", 193 __func__, val, intface, 194 tmp->maxinterval, MAXROUTERLIFETIME); 195 exit(1); 196 } 197 /* 198 * Basically, hosts MUST NOT send Router Advertisement messages at any 199 * time (RFC 2461, Section 6.2.3). However, it would sometimes be 200 * useful to allow hosts to advertise some parameters such as prefix 201 * information and link MTU. Thus, we allow hosts to invoke rtadvd 202 * only when router lifetime (on every advertising interface) is 203 * explicitly set zero. (see also the above section) 204 */ 205 if (val && forwarding == 0) { 206 syslog(LOG_ERR, 207 "<%s> non zero router lifetime is specified for %s, " 208 "which must not be allowed for hosts. you must " 209 "change router lifetime or enable IPv6 forwarding.", 210 __func__, intface); 211 exit(1); 212 } 213 tmp->lifetime = val & 0xffff; 214 215 MAYHAVE(val, "rtime", DEF_ADVREACHABLETIME); 216 if (val < 0 || val > MAXREACHABLETIME) { 217 syslog(LOG_ERR, 218 "<%s> reachable time (%ld) on %s is invalid " 219 "(must be no greater than %d)", 220 __func__, val, intface, MAXREACHABLETIME); 221 exit(1); 222 } 223 tmp->reachabletime = (u_int32_t)val; 224 225 MAYHAVE(val64, "retrans", DEF_ADVRETRANSTIMER); 226 if (val64 < 0 || val64 > 0xffffffff) { 227 syslog(LOG_ERR, "<%s> retrans time (%lld) on %s out of range", 228 __func__, (long long)val64, intface); 229 exit(1); 230 } 231 tmp->retranstimer = (u_int32_t)val64; 232 233 if (agetnum("hapref") != -1 || agetnum("hatime") != -1) { 234 syslog(LOG_ERR, 235 "<%s> mobile-ip6 configuration not supported", 236 __func__); 237 exit(1); 238 } 239 /* prefix information */ 240 241 /* 242 * This is an implementation specific parameter to consider 243 * link propagation delays and poorly synchronized clocks when 244 * checking consistency of advertised lifetimes. 245 */ 246 MAYHAVE(val, "clockskew", 0); 247 tmp->clockskew = val; 248 249 tmp->pfxs = 0; 250 for (i = -1; i < MAXPREFIX; i++) { 251 struct prefix *pfx; 252 char entbuf[256]; 253 254 makeentry(entbuf, sizeof(entbuf), i, "addr"); 255 addr = (char *)agetstr(entbuf, &bp); 256 if (addr == NULL) 257 continue; 258 259 /* allocate memory to store prefix information */ 260 if ((pfx = malloc(sizeof(struct prefix))) == NULL) { 261 syslog(LOG_ERR, 262 "<%s> can't allocate enough memory", 263 __func__); 264 exit(1); 265 } 266 memset(pfx, 0, sizeof(*pfx)); 267 268 /* link into chain */ 269 insque(pfx, &tmp->prefix); 270 tmp->pfxs++; 271 272 pfx->origin = PREFIX_FROM_CONFIG; 273 274 if (inet_pton(AF_INET6, addr, &pfx->prefix) != 1) { 275 syslog(LOG_ERR, 276 "<%s> inet_pton failed for %s", 277 __func__, addr); 278 exit(1); 279 } 280 if (IN6_IS_ADDR_MULTICAST(&pfx->prefix)) { 281 syslog(LOG_ERR, 282 "<%s> multicast prefix (%s) must " 283 "not be advertised on %s", 284 __func__, addr, intface); 285 exit(1); 286 } 287 if (IN6_IS_ADDR_LINKLOCAL(&pfx->prefix)) 288 syslog(LOG_NOTICE, 289 "<%s> link-local prefix (%s) will be" 290 " advertised on %s", 291 __func__, addr, intface); 292 293 makeentry(entbuf, sizeof(entbuf), i, "prefixlen"); 294 MAYHAVE(val, entbuf, 64); 295 if (val < 0 || val > 128) { 296 syslog(LOG_ERR, "<%s> prefixlen (%ld) for %s " 297 "on %s out of range", 298 __func__, val, addr, intface); 299 exit(1); 300 } 301 pfx->prefixlen = (int)val; 302 303 makeentry(entbuf, sizeof(entbuf), i, "pinfoflags"); 304 MAYHAVE(val, entbuf, 305 (ND_OPT_PI_FLAG_ONLINK|ND_OPT_PI_FLAG_AUTO)); 306 pfx->onlinkflg = val & ND_OPT_PI_FLAG_ONLINK; 307 pfx->autoconfflg = val & ND_OPT_PI_FLAG_AUTO; 308 309 makeentry(entbuf, sizeof(entbuf), i, "vltime"); 310 MAYHAVE(val64, entbuf, DEF_ADVVALIDLIFETIME); 311 if (val64 < 0 || val64 > 0xffffffff) { 312 syslog(LOG_ERR, "<%s> vltime (%lld) for " 313 "%s/%d on %s is out of range", 314 __func__, (long long)val64, 315 addr, pfx->prefixlen, intface); 316 exit(1); 317 } 318 pfx->validlifetime = (u_int32_t)val64; 319 320 makeentry(entbuf, sizeof(entbuf), i, "vltimedecr"); 321 if (agetflag(entbuf)) { 322 struct timeval now; 323 gettimeofday(&now, 0); 324 pfx->vltimeexpire = 325 now.tv_sec + pfx->validlifetime; 326 } 327 328 makeentry(entbuf, sizeof(entbuf), i, "pltime"); 329 MAYHAVE(val64, entbuf, DEF_ADVPREFERREDLIFETIME); 330 if (val64 < 0 || val64 > 0xffffffff) { 331 syslog(LOG_ERR, 332 "<%s> pltime (%lld) for %s/%d on %s " 333 "is out of range", 334 __func__, (long long)val64, 335 addr, pfx->prefixlen, intface); 336 exit(1); 337 } 338 pfx->preflifetime = (u_int32_t)val64; 339 340 makeentry(entbuf, sizeof(entbuf), i, "pltimedecr"); 341 if (agetflag(entbuf)) { 342 struct timeval now; 343 gettimeofday(&now, 0); 344 pfx->pltimeexpire = 345 now.tv_sec + pfx->preflifetime; 346 } 347 } 348 if (tmp->pfxs == 0) 349 get_prefix(tmp); 350 351 MAYHAVE(val, "mtu", 0); 352 if (val < 0 || val > 0xffffffff) { 353 syslog(LOG_ERR, 354 "<%s> mtu (%ld) on %s out of range", 355 __func__, val, intface); 356 exit(1); 357 } 358 tmp->linkmtu = (u_int32_t)val; 359 if (tmp->linkmtu == 0) { 360 char *mtustr; 361 362 if ((mtustr = (char *)agetstr("mtu", &bp)) && 363 strcmp(mtustr, "auto") == 0) 364 tmp->linkmtu = tmp->phymtu; 365 } 366 else if (tmp->linkmtu < IPV6_MMTU || tmp->linkmtu > tmp->phymtu) { 367 syslog(LOG_ERR, 368 "<%s> advertised link mtu (%lu) on %s is invalid (must " 369 "be between least MTU (%d) and physical link MTU (%d)", 370 __func__, (unsigned long)tmp->linkmtu, intface, 371 IPV6_MMTU, tmp->phymtu); 372 exit(1); 373 } 374 375 /* route information */ 376 MAYHAVE(val, "routes", -1); 377 if (val != -1) 378 syslog(LOG_INFO, "route information option is not available"); 379 380 /* okey */ 381 tmp->next = ralist; 382 ralist = tmp; 383 384 /* construct the sending packet */ 385 make_packet(tmp); 386 387 /* set timer */ 388 tmp->timer = rtadvd_add_timer(ra_timeout, ra_timer_update, 389 tmp, tmp); 390 ra_timer_update((void *)tmp, &tmp->timer->tm); 391 rtadvd_set_timer(&tmp->timer->tm, tmp->timer); 392 } 393 394 void 395 get_prefix(struct rainfo *rai) 396 { 397 struct ifaddrs *ifap, *ifa; 398 struct prefix *pp; 399 struct in6_addr *a; 400 u_char *p, *ep, *m, *lim; 401 u_char ntopbuf[INET6_ADDRSTRLEN]; 402 403 if (getifaddrs(&ifap) < 0) { 404 syslog(LOG_ERR, 405 "<%s> can't get interface addresses", 406 __func__); 407 exit(1); 408 } 409 410 for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 411 int plen; 412 413 if (strcmp(ifa->ifa_name, rai->ifname) != 0) 414 continue; 415 if (ifa->ifa_addr->sa_family != AF_INET6) 416 continue; 417 a = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr; 418 if (IN6_IS_ADDR_LINKLOCAL(a)) 419 continue; 420 /* get prefix length */ 421 m = (u_char *)&((struct sockaddr_in6 *)ifa->ifa_netmask)->sin6_addr; 422 lim = (u_char *)(ifa->ifa_netmask) + ifa->ifa_netmask->sa_len; 423 plen = prefixlen(m, lim); 424 if (plen <= 0 || plen > 128) { 425 syslog(LOG_ERR, "<%s> failed to get prefixlen " 426 "or prefix is invalid", 427 __func__); 428 exit(1); 429 } 430 if (plen == 128) /* XXX */ 431 continue; 432 if (find_prefix(rai, a, plen)) { 433 /* ignore a duplicated prefix. */ 434 continue; 435 } 436 437 /* allocate memory to store prefix info. */ 438 if ((pp = malloc(sizeof(*pp))) == NULL) { 439 syslog(LOG_ERR, 440 "<%s> can't get allocate buffer for prefix", 441 __func__); 442 exit(1); 443 } 444 memset(pp, 0, sizeof(*pp)); 445 446 /* set prefix, sweep bits outside of prefixlen */ 447 pp->prefixlen = plen; 448 memcpy(&pp->prefix, a, sizeof(*a)); 449 if (1) 450 { 451 p = (u_char *)&pp->prefix; 452 ep = (u_char *)(&pp->prefix + 1); 453 while (m < lim) 454 *p++ &= *m++; 455 while (p < ep) 456 *p++ = 0x00; 457 } 458 if (!inet_ntop(AF_INET6, &pp->prefix, ntopbuf, 459 sizeof(ntopbuf))) { 460 syslog(LOG_ERR, "<%s> inet_ntop failed", __func__); 461 exit(1); 462 } 463 syslog(LOG_DEBUG, 464 "<%s> add %s/%d to prefix list on %s", 465 __func__, ntopbuf, pp->prefixlen, rai->ifname); 466 467 /* set other fields with protocol defaults */ 468 pp->validlifetime = DEF_ADVVALIDLIFETIME; 469 pp->preflifetime = DEF_ADVPREFERREDLIFETIME; 470 pp->onlinkflg = 1; 471 pp->autoconfflg = 1; 472 pp->origin = PREFIX_FROM_KERNEL; 473 474 /* link into chain */ 475 insque(pp, &rai->prefix); 476 477 /* counter increment */ 478 rai->pfxs++; 479 } 480 481 freeifaddrs(ifap); 482 } 483 484 static void 485 makeentry(buf, len, id, string) 486 char *buf; 487 size_t len; 488 int id; 489 char *string; 490 { 491 492 if (id < 0) 493 strlcpy(buf, string, len); 494 else 495 snprintf(buf, len, "%s%d", string, id); 496 } 497 498 /* 499 * Add a prefix to the list of specified interface and reconstruct 500 * the outgoing packet. 501 * The prefix must not be in the list. 502 * XXX: other parameter of the prefix(e.g. lifetime) shoule be 503 * able to be specified. 504 */ 505 static void 506 add_prefix(struct rainfo *rai, struct in6_prefixreq *ipr) 507 { 508 struct prefix *prefix; 509 u_char ntopbuf[INET6_ADDRSTRLEN]; 510 511 if ((prefix = malloc(sizeof(*prefix))) == NULL) { 512 syslog(LOG_ERR, "<%s> memory allocation failed", 513 __func__); 514 return; /* XXX: error or exit? */ 515 } 516 memset(prefix, 0, sizeof(*prefix)); 517 prefix->prefix = ipr->ipr_prefix.sin6_addr; 518 prefix->prefixlen = ipr->ipr_plen; 519 prefix->validlifetime = ipr->ipr_vltime; 520 prefix->preflifetime = ipr->ipr_pltime; 521 prefix->onlinkflg = ipr->ipr_raf_onlink; 522 prefix->autoconfflg = ipr->ipr_raf_auto; 523 prefix->origin = PREFIX_FROM_DYNAMIC; 524 525 insque(prefix, &rai->prefix); 526 527 syslog(LOG_DEBUG, "<%s> new prefix %s/%d was added on %s", 528 __func__, inet_ntop(AF_INET6, &ipr->ipr_prefix.sin6_addr, 529 ntopbuf, INET6_ADDRSTRLEN), 530 ipr->ipr_plen, rai->ifname); 531 532 /* free the previous packet */ 533 free(rai->ra_data); 534 rai->ra_data = NULL; 535 536 /* reconstruct the packet */ 537 rai->pfxs++; 538 make_packet(rai); 539 540 /* 541 * reset the timer so that the new prefix will be advertised quickly. 542 */ 543 rai->initcounter = 0; 544 ra_timer_update((void *)rai, &rai->timer->tm); 545 rtadvd_set_timer(&rai->timer->tm, rai->timer); 546 } 547 548 /* 549 * Delete a prefix to the list of specified interface and reconstruct 550 * the outgoing packet. 551 * The prefix must be in the list. 552 */ 553 void 554 delete_prefix(struct rainfo *rai, struct prefix *prefix) 555 { 556 u_char ntopbuf[INET6_ADDRSTRLEN]; 557 558 remque(prefix); 559 syslog(LOG_DEBUG, "<%s> prefix %s/%d was deleted on %s", 560 __func__, inet_ntop(AF_INET6, &prefix->prefix, 561 ntopbuf, INET6_ADDRSTRLEN), 562 prefix->prefixlen, rai->ifname); 563 free(prefix); 564 rai->pfxs--; 565 make_packet(rai); 566 } 567 568 /* 569 * Try to get an in6_prefixreq contents for a prefix which matches 570 * ipr->ipr_prefix and ipr->ipr_plen and belongs to 571 * the interface whose name is ipr->ipr_name[]. 572 */ 573 static int 574 init_prefix(struct in6_prefixreq *ipr) 575 { 576 #if 0 577 int s; 578 579 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 580 syslog(LOG_ERR, "<%s> socket: %s", __func__, 581 strerror(errno)); 582 exit(1); 583 } 584 585 if (ioctl(s, SIOCGIFPREFIX_IN6, (caddr_t)ipr) < 0) { 586 syslog(LOG_INFO, "<%s> ioctl:SIOCGIFPREFIX %s", __func__, 587 strerror(errno)); 588 589 ipr->ipr_vltime = DEF_ADVVALIDLIFETIME; 590 ipr->ipr_pltime = DEF_ADVPREFERREDLIFETIME; 591 ipr->ipr_raf_onlink = 1; 592 ipr->ipr_raf_auto = 1; 593 /* omit other field initialization */ 594 } 595 else if (ipr->ipr_origin < PR_ORIG_RR) { 596 u_char ntopbuf[INET6_ADDRSTRLEN]; 597 598 syslog(LOG_WARNING, "<%s> Added prefix(%s)'s origin %d is" 599 "lower than PR_ORIG_RR(router renumbering)." 600 "This should not happen if I am router", __func__, 601 inet_ntop(AF_INET6, &ipr->ipr_prefix.sin6_addr, ntopbuf, 602 sizeof(ntopbuf)), ipr->ipr_origin); 603 close(s); 604 return 1; 605 } 606 607 close(s); 608 return 0; 609 #else 610 ipr->ipr_vltime = DEF_ADVVALIDLIFETIME; 611 ipr->ipr_pltime = DEF_ADVPREFERREDLIFETIME; 612 ipr->ipr_raf_onlink = 1; 613 ipr->ipr_raf_auto = 1; 614 return 0; 615 #endif 616 } 617 618 void 619 make_prefix(struct rainfo *rai, int ifindex, struct in6_addr *addr, int plen) 620 { 621 struct in6_prefixreq ipr; 622 623 memset(&ipr, 0, sizeof(ipr)); 624 if (if_indextoname(ifindex, ipr.ipr_name) == NULL) { 625 syslog(LOG_ERR, "<%s> Prefix added interface No.%d doesn't" 626 "exist. This should not happen! %s", __func__, 627 ifindex, strerror(errno)); 628 exit(1); 629 } 630 ipr.ipr_prefix.sin6_len = sizeof(ipr.ipr_prefix); 631 ipr.ipr_prefix.sin6_family = AF_INET6; 632 ipr.ipr_prefix.sin6_addr = *addr; 633 ipr.ipr_plen = plen; 634 635 if (init_prefix(&ipr)) 636 return; /* init failed by some error */ 637 add_prefix(rai, &ipr); 638 } 639 640 void 641 make_packet(struct rainfo *rainfo) 642 { 643 size_t packlen, lladdroptlen = 0; 644 char *buf; 645 struct nd_router_advert *ra; 646 struct nd_opt_prefix_info *ndopt_pi; 647 struct nd_opt_mtu *ndopt_mtu; 648 struct prefix *pfx; 649 650 /* calculate total length */ 651 packlen = sizeof(struct nd_router_advert); 652 if (rainfo->advlinkopt) { 653 if ((lladdroptlen = lladdropt_length(rainfo->sdl)) == 0) { 654 syslog(LOG_INFO, 655 "<%s> link-layer address option has" 656 " null length on %s. Treat as not included.", 657 __func__, rainfo->ifname); 658 rainfo->advlinkopt = 0; 659 } 660 packlen += lladdroptlen; 661 } 662 if (rainfo->pfxs) 663 packlen += sizeof(struct nd_opt_prefix_info) * rainfo->pfxs; 664 if (rainfo->linkmtu) 665 packlen += sizeof(struct nd_opt_mtu); 666 667 /* allocate memory for the packet */ 668 if ((buf = malloc(packlen)) == NULL) { 669 syslog(LOG_ERR, 670 "<%s> can't get enough memory for an RA packet", 671 __func__); 672 exit(1); 673 } 674 if (rainfo->ra_data) { 675 /* free the previous packet */ 676 free(rainfo->ra_data); 677 rainfo->ra_data = NULL; 678 } 679 rainfo->ra_data = buf; 680 /* XXX: what if packlen > 576? */ 681 rainfo->ra_datalen = packlen; 682 683 /* 684 * construct the packet 685 */ 686 ra = (struct nd_router_advert *)buf; 687 ra->nd_ra_type = ND_ROUTER_ADVERT; 688 ra->nd_ra_code = 0; 689 ra->nd_ra_cksum = 0; 690 ra->nd_ra_curhoplimit = (u_int8_t)(0xff & rainfo->hoplimit); 691 ra->nd_ra_flags_reserved = 0; /* just in case */ 692 /* 693 * XXX: the router preference field, which is a 2-bit field, should be 694 * initialized before other fields. 695 */ 696 ra->nd_ra_flags_reserved = 0xff & rainfo->rtpref; 697 ra->nd_ra_flags_reserved |= 698 rainfo->managedflg ? ND_RA_FLAG_MANAGED : 0; 699 ra->nd_ra_flags_reserved |= 700 rainfo->otherflg ? ND_RA_FLAG_OTHER : 0; 701 ra->nd_ra_router_lifetime = htons(rainfo->lifetime); 702 ra->nd_ra_reachable = htonl(rainfo->reachabletime); 703 ra->nd_ra_retransmit = htonl(rainfo->retranstimer); 704 buf += sizeof(*ra); 705 706 if (rainfo->advlinkopt) { 707 lladdropt_fill(rainfo->sdl, (struct nd_opt_hdr *)buf); 708 buf += lladdroptlen; 709 } 710 711 if (rainfo->linkmtu) { 712 ndopt_mtu = (struct nd_opt_mtu *)buf; 713 ndopt_mtu->nd_opt_mtu_type = ND_OPT_MTU; 714 ndopt_mtu->nd_opt_mtu_len = 1; 715 ndopt_mtu->nd_opt_mtu_reserved = 0; 716 ndopt_mtu->nd_opt_mtu_mtu = htonl(rainfo->linkmtu); 717 buf += sizeof(struct nd_opt_mtu); 718 } 719 720 721 722 for (pfx = rainfo->prefix.next; 723 pfx != &rainfo->prefix; pfx = pfx->next) { 724 u_int32_t vltime, pltime; 725 struct timeval now; 726 727 ndopt_pi = (struct nd_opt_prefix_info *)buf; 728 ndopt_pi->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION; 729 ndopt_pi->nd_opt_pi_len = 4; 730 ndopt_pi->nd_opt_pi_prefix_len = pfx->prefixlen; 731 ndopt_pi->nd_opt_pi_flags_reserved = 0; 732 if (pfx->onlinkflg) 733 ndopt_pi->nd_opt_pi_flags_reserved |= 734 ND_OPT_PI_FLAG_ONLINK; 735 if (pfx->autoconfflg) 736 ndopt_pi->nd_opt_pi_flags_reserved |= 737 ND_OPT_PI_FLAG_AUTO; 738 if (pfx->vltimeexpire || pfx->pltimeexpire) 739 gettimeofday(&now, NULL); 740 if (pfx->vltimeexpire == 0) 741 vltime = pfx->validlifetime; 742 else 743 vltime = (pfx->vltimeexpire > now.tv_sec) ? 744 pfx->vltimeexpire - now.tv_sec : 0; 745 if (pfx->pltimeexpire == 0) 746 pltime = pfx->preflifetime; 747 else 748 pltime = (pfx->pltimeexpire > now.tv_sec) ? 749 pfx->pltimeexpire - now.tv_sec : 0; 750 if (vltime < pltime) { 751 /* 752 * this can happen if vltime is decrement but pltime 753 * is not. 754 */ 755 pltime = vltime; 756 } 757 ndopt_pi->nd_opt_pi_valid_time = htonl(vltime); 758 ndopt_pi->nd_opt_pi_preferred_time = htonl(pltime); 759 ndopt_pi->nd_opt_pi_reserved2 = 0; 760 ndopt_pi->nd_opt_pi_prefix = pfx->prefix; 761 762 buf += sizeof(struct nd_opt_prefix_info); 763 } 764 765 return; 766 } 767 768 static int 769 getinet6sysctl(int code) 770 { 771 int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, 0 }; 772 int value; 773 size_t size; 774 775 mib[3] = code; 776 size = sizeof(value); 777 if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), &value, &size, NULL, 0) 778 < 0) { 779 syslog(LOG_ERR, "<%s>: failed to get ip6 sysctl(%d): %s", 780 __func__, code, 781 strerror(errno)); 782 return(-1); 783 } 784 else 785 return(value); 786 } 787