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