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