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