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