1 /* $NetBSD: config.c,v 1.25 2006/05/11 08:35:47 mrg Exp $ */ 2 /* $KAME: config.c,v 1.93 2005/10/17 14:40:02 suz Exp $ */ 3 4 /* 5 * Copyright (C) 1998 WIDE Project. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the project nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 #include <sys/param.h> 34 #include <sys/ioctl.h> 35 #include <sys/socket.h> 36 #include <sys/time.h> 37 #include <sys/sysctl.h> 38 39 #include <net/if.h> 40 #include <net/route.h> 41 #include <net/if_dl.h> 42 43 #include <netinet/in.h> 44 #include <netinet/in_var.h> 45 #include <netinet/ip6.h> 46 #include <netinet6/ip6_var.h> 47 #include <netinet/icmp6.h> 48 #include <netinet6/nd6.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 <search.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 strlcpy(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 %u 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, 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 pfx->rainfo = tmp; 296 tmp->pfxs++; 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 #ifdef SIOCSIFINFO_IN6 410 { 411 struct in6_ndireq ndi; 412 int s; 413 414 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 415 syslog(LOG_ERR, "<%s> socket: %s", __func__, 416 strerror(errno)); 417 exit(1); 418 } 419 memset(&ndi, 0, sizeof(ndi)); 420 strncpy(ndi.ifname, intface, IFNAMSIZ); 421 if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&ndi) < 0) { 422 syslog(LOG_INFO, "<%s> ioctl:SIOCGIFINFO_IN6 at %s: %s", 423 __func__, intface, strerror(errno)); 424 } 425 426 /* reflect the RA info to the host variables in kernel */ 427 ndi.ndi.chlim = tmp->hoplimit; 428 ndi.ndi.retrans = tmp->retranstimer; 429 ndi.ndi.basereachable = tmp->reachabletime; 430 if (ioctl(s, SIOCSIFINFO_IN6, (caddr_t)&ndi) < 0) { 431 syslog(LOG_INFO, "<%s> ioctl:SIOCSIFINFO_IN6 at %s: %s", 432 __func__, intface, strerror(errno)); 433 } 434 close(s); 435 } 436 #endif 437 438 /* route information */ 439 #ifdef ROUTEINFO 440 tmp->routes = 0; 441 for (i = -1; i < MAXROUTE; i++) { 442 struct rtinfo *rti; 443 char entbuf[256], oentbuf[256]; 444 445 makeentry(entbuf, sizeof(entbuf), i, "rtprefix"); 446 addr = (char *)agetstr(entbuf, &bp); 447 if (addr == NULL) { 448 makeentry(oentbuf, sizeof(oentbuf), i, "rtrprefix"); 449 addr = (char *)agetstr(oentbuf, &bp); 450 if (addr) { 451 fprintf(stderr, "%s was obsoleted. Use %s.\n", 452 oentbuf, entbuf); 453 } 454 } 455 if (addr == NULL) 456 continue; 457 458 /* allocate memory to store prefix information */ 459 if ((rti = malloc(sizeof(struct rtinfo))) == NULL) { 460 syslog(LOG_ERR, 461 "<%s> can't allocate enough memory", 462 __func__); 463 exit(1); 464 } 465 memset(rti, 0, sizeof(*rti)); 466 467 /* link into chain */ 468 insque(rti, &tmp->route); 469 tmp->routes++; 470 471 if (inet_pton(AF_INET6, addr, &rti->prefix) != 1) { 472 syslog(LOG_ERR, "<%s> inet_pton failed for %s", 473 __func__, addr); 474 exit(1); 475 } 476 #if 0 477 /* 478 * XXX: currently there's no restriction in route information 479 * prefix according to 480 * draft-ietf-ipngwg-router-selection-00.txt. 481 * However, I think the similar restriction be necessary. 482 */ 483 MAYHAVE(val64, entbuf, DEF_ADVVALIDLIFETIME); 484 if (IN6_IS_ADDR_MULTICAST(&rti->prefix)) { 485 syslog(LOG_ERR, 486 "<%s> multicast route (%s) must " 487 "not be advertised on %s", 488 __func__, addr, intface); 489 exit(1); 490 } 491 if (IN6_IS_ADDR_LINKLOCAL(&rti->prefix)) { 492 syslog(LOG_NOTICE, 493 "<%s> link-local route (%s) will " 494 "be advertised on %s", 495 __func__, addr, intface); 496 exit(1); 497 } 498 #endif 499 500 makeentry(entbuf, sizeof(entbuf), i, "rtplen"); 501 /* XXX: 256 is a magic number for compatibility check. */ 502 MAYHAVE(val, entbuf, 256); 503 if (val == 256) { 504 makeentry(oentbuf, sizeof(oentbuf), i, "rtrplen"); 505 MAYHAVE(val, oentbuf, 256); 506 if (val != 256) { 507 fprintf(stderr, "%s was obsoleted. Use %s.\n", 508 oentbuf, entbuf); 509 } else 510 val = 64; 511 } 512 if (val < 0 || val > 128) { 513 syslog(LOG_ERR, "<%s> prefixlen (%ld) for %s on %s " 514 "out of range", 515 __func__, val, addr, intface); 516 exit(1); 517 } 518 rti->prefixlen = (int)val; 519 520 makeentry(entbuf, sizeof(entbuf), i, "rtflags"); 521 if ((flagstr = (char *)agetstr(entbuf, &bp))) { 522 val = 0; 523 if (strchr(flagstr, 'h')) 524 val |= ND_RA_FLAG_RTPREF_HIGH; 525 if (strchr(flagstr, 'l')) { 526 if ((val & ND_RA_FLAG_RTPREF_HIGH)) { 527 syslog(LOG_ERR, 528 "<%s> the \'h\' and \'l\' route" 529 " preferences are exclusive", 530 __func__); 531 exit(1); 532 } 533 val |= ND_RA_FLAG_RTPREF_LOW; 534 } 535 } else 536 MAYHAVE(val, entbuf, 256); /* XXX */ 537 if (val == 256) { 538 makeentry(oentbuf, sizeof(oentbuf), i, "rtrflags"); 539 MAYHAVE(val, oentbuf, 256); 540 if (val != 256) { 541 fprintf(stderr, "%s was obsoleted. Use %s.\n", 542 oentbuf, entbuf); 543 } else 544 val = 0; 545 } 546 rti->rtpref = val & ND_RA_FLAG_RTPREF_MASK; 547 if (rti->rtpref == ND_RA_FLAG_RTPREF_RSV) { 548 syslog(LOG_ERR, "<%s> invalid route preference (%02x) " 549 "for %s/%d on %s", 550 __func__, rti->rtpref, addr, 551 rti->prefixlen, intface); 552 exit(1); 553 } 554 555 /* 556 * Since the spec does not a default value, we should make 557 * this entry mandatory. However, FreeBSD 4.4 has shipped 558 * with this field being optional, we use the router lifetime 559 * as an ad-hoc default value with a warning message. 560 */ 561 makeentry(entbuf, sizeof(entbuf), i, "rtltime"); 562 MAYHAVE(val64, entbuf, -1); 563 if (val64 == -1) { 564 makeentry(oentbuf, sizeof(oentbuf), i, "rtrltime"); 565 MAYHAVE(val64, oentbuf, -1); 566 if (val64 != -1) { 567 fprintf(stderr, "%s was obsoleted. Use %s.\n", 568 oentbuf, entbuf); 569 } else { 570 fprintf(stderr, "%s should be specified " 571 "for interface %s.\n", 572 entbuf, intface); 573 val64 = tmp->lifetime; 574 } 575 } 576 if (val64 < 0 || val64 > 0xffffffff) { 577 syslog(LOG_ERR, "<%s> route lifetime (%lld) for " 578 "%s/%d on %s out of range", __func__, 579 (long long)val64, addr, rti->prefixlen, intface); 580 exit(1); 581 } 582 rti->ltime = (u_int32_t)val64; 583 } 584 #endif 585 586 /* okey */ 587 tmp->next = ralist; 588 ralist = tmp; 589 590 /* construct the sending packet */ 591 make_packet(tmp); 592 593 /* set timer */ 594 tmp->timer = rtadvd_add_timer(ra_timeout, ra_timer_update, 595 tmp, tmp); 596 ra_timer_update((void *)tmp, &tmp->timer->tm); 597 rtadvd_set_timer(&tmp->timer->tm, tmp->timer); 598 } 599 600 void 601 get_prefix(struct rainfo *rai) 602 { 603 struct ifaddrs *ifap, *ifa; 604 struct prefix *pp; 605 struct in6_addr *a; 606 u_char *p, *ep, *m, *lim; 607 char ntopbuf[INET6_ADDRSTRLEN]; 608 609 if (getifaddrs(&ifap) < 0) { 610 syslog(LOG_ERR, 611 "<%s> can't get interface addresses", 612 __func__); 613 exit(1); 614 } 615 616 for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 617 int plen; 618 619 if (strcmp(ifa->ifa_name, rai->ifname) != 0) 620 continue; 621 if (ifa->ifa_addr->sa_family != AF_INET6) 622 continue; 623 a = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr; 624 if (IN6_IS_ADDR_LINKLOCAL(a)) 625 continue; 626 /* get prefix length */ 627 m = (u_char *)&((struct sockaddr_in6 *)ifa->ifa_netmask)->sin6_addr; 628 lim = (u_char *)(ifa->ifa_netmask) + ifa->ifa_netmask->sa_len; 629 plen = prefixlen(m, lim); 630 if (plen <= 0 || plen > 128) { 631 syslog(LOG_ERR, "<%s> failed to get prefixlen " 632 "or prefix is invalid", 633 __func__); 634 exit(1); 635 } 636 if (plen == 128) /* XXX */ 637 continue; 638 if (find_prefix(rai, a, plen)) { 639 /* ignore a duplicated prefix. */ 640 continue; 641 } 642 643 /* allocate memory to store prefix info. */ 644 if ((pp = malloc(sizeof(*pp))) == NULL) { 645 syslog(LOG_ERR, 646 "<%s> can't get allocate buffer for prefix", 647 __func__); 648 exit(1); 649 } 650 memset(pp, 0, sizeof(*pp)); 651 652 /* set prefix, sweep bits outside of prefixlen */ 653 pp->prefixlen = plen; 654 memcpy(&pp->prefix, a, sizeof(*a)); 655 if (1) 656 { 657 p = (u_char *)&pp->prefix; 658 ep = (u_char *)(&pp->prefix + 1); 659 while (m < lim && p < ep) 660 *p++ &= *m++; 661 while (p < ep) 662 *p++ = 0x00; 663 } 664 if (!inet_ntop(AF_INET6, &pp->prefix, ntopbuf, 665 sizeof(ntopbuf))) { 666 syslog(LOG_ERR, "<%s> inet_ntop failed", __func__); 667 exit(1); 668 } 669 syslog(LOG_DEBUG, 670 "<%s> add %s/%d to prefix list on %s", 671 __func__, ntopbuf, pp->prefixlen, rai->ifname); 672 673 /* set other fields with protocol defaults */ 674 pp->validlifetime = DEF_ADVVALIDLIFETIME; 675 pp->preflifetime = DEF_ADVPREFERREDLIFETIME; 676 pp->onlinkflg = 1; 677 pp->autoconfflg = 1; 678 pp->origin = PREFIX_FROM_KERNEL; 679 pp->rainfo = rai; 680 681 /* link into chain */ 682 insque(pp, &rai->prefix); 683 684 /* counter increment */ 685 rai->pfxs++; 686 } 687 688 freeifaddrs(ifap); 689 } 690 691 static void 692 makeentry(buf, len, id, string) 693 char *buf; 694 size_t len; 695 int id; 696 char *string; 697 { 698 699 if (id < 0) 700 strlcpy(buf, string, len); 701 else 702 snprintf(buf, len, "%s%d", string, id); 703 } 704 705 /* 706 * Add a prefix to the list of specified interface and reconstruct 707 * the outgoing packet. 708 * The prefix must not be in the list. 709 * XXX: other parameters of the prefix(e.g. lifetime) should be 710 * able to be specified. 711 */ 712 static void 713 add_prefix(struct rainfo *rai, struct in6_prefixreq *ipr) 714 { 715 struct prefix *prefix; 716 char ntopbuf[INET6_ADDRSTRLEN]; 717 718 if ((prefix = malloc(sizeof(*prefix))) == NULL) { 719 syslog(LOG_ERR, "<%s> memory allocation failed", 720 __func__); 721 return; /* XXX: error or exit? */ 722 } 723 memset(prefix, 0, sizeof(*prefix)); 724 prefix->prefix = ipr->ipr_prefix.sin6_addr; 725 prefix->prefixlen = ipr->ipr_plen; 726 prefix->validlifetime = ipr->ipr_vltime; 727 prefix->preflifetime = ipr->ipr_pltime; 728 prefix->onlinkflg = ipr->ipr_raf_onlink; 729 prefix->autoconfflg = ipr->ipr_raf_auto; 730 prefix->origin = PREFIX_FROM_DYNAMIC; 731 732 insque(prefix, &rai->prefix); 733 prefix->rainfo = rai; 734 735 syslog(LOG_DEBUG, "<%s> new prefix %s/%d was added on %s", 736 __func__, inet_ntop(AF_INET6, &ipr->ipr_prefix.sin6_addr, 737 ntopbuf, INET6_ADDRSTRLEN), 738 ipr->ipr_plen, rai->ifname); 739 740 /* free the previous packet */ 741 free(rai->ra_data); 742 rai->ra_data = NULL; 743 744 /* reconstruct the packet */ 745 rai->pfxs++; 746 make_packet(rai); 747 } 748 749 /* 750 * Delete a prefix to the list of specified interface and reconstruct 751 * the outgoing packet. 752 * The prefix must be in the list. 753 */ 754 void 755 delete_prefix(struct prefix *prefix) 756 { 757 char ntopbuf[INET6_ADDRSTRLEN]; 758 struct rainfo *rai = prefix->rainfo; 759 760 remque(prefix); 761 syslog(LOG_DEBUG, "<%s> prefix %s/%d was deleted on %s", 762 __func__, inet_ntop(AF_INET6, &prefix->prefix, 763 ntopbuf, INET6_ADDRSTRLEN), 764 prefix->prefixlen, rai->ifname); 765 if (prefix->timer) 766 rtadvd_remove_timer(&prefix->timer); 767 free(prefix); 768 rai->pfxs--; 769 } 770 771 void 772 invalidate_prefix(struct prefix *prefix) 773 { 774 char ntopbuf[INET6_ADDRSTRLEN]; 775 struct timeval timo; 776 struct rainfo *rai = prefix->rainfo; 777 778 if (prefix->timer) { /* sanity check */ 779 syslog(LOG_ERR, 780 "<%s> assumption failure: timer already exists", 781 __func__); 782 exit(1); 783 } 784 785 syslog(LOG_DEBUG, "<%s> prefix %s/%d was invalidated on %s, " 786 "will expire in %ld seconds", __func__, 787 inet_ntop(AF_INET6, &prefix->prefix, ntopbuf, INET6_ADDRSTRLEN), 788 prefix->prefixlen, rai->ifname, (long)prefix_timo); 789 790 /* set the expiration timer */ 791 prefix->timer = rtadvd_add_timer(prefix_timeout, NULL, prefix, NULL); 792 if (prefix->timer == NULL) { 793 syslog(LOG_ERR, "<%s> failed to add a timer for a prefix. " 794 "remove the prefix", __func__); 795 delete_prefix(prefix); 796 } 797 timo.tv_sec = prefix_timo; 798 timo.tv_usec = 0; 799 rtadvd_set_timer(&timo, prefix->timer); 800 } 801 802 static struct rtadvd_timer * 803 prefix_timeout(void *arg) 804 { 805 struct prefix *prefix = (struct prefix *)arg; 806 807 delete_prefix(prefix); 808 809 return(NULL); 810 } 811 812 void 813 update_prefix(struct prefix * prefix) 814 { 815 char ntopbuf[INET6_ADDRSTRLEN]; 816 struct rainfo *rai = prefix->rainfo; 817 818 if (prefix->timer == NULL) { /* sanity check */ 819 syslog(LOG_ERR, 820 "<%s> assumption failure: timer does not exist", 821 __func__); 822 exit(1); 823 } 824 825 syslog(LOG_DEBUG, "<%s> prefix %s/%d was re-enabled on %s", 826 __func__, inet_ntop(AF_INET6, &prefix->prefix, ntopbuf, 827 INET6_ADDRSTRLEN), prefix->prefixlen, rai->ifname); 828 829 /* stop the expiration timer */ 830 rtadvd_remove_timer(&prefix->timer); 831 } 832 833 /* 834 * Try to get an in6_prefixreq contents for a prefix which matches 835 * ipr->ipr_prefix and ipr->ipr_plen and belongs to 836 * the interface whose name is ipr->ipr_name[]. 837 */ 838 static int 839 init_prefix(struct in6_prefixreq *ipr) 840 { 841 #if 0 842 int s; 843 844 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 845 syslog(LOG_ERR, "<%s> socket: %s", __func__, 846 strerror(errno)); 847 exit(1); 848 } 849 850 if (ioctl(s, SIOCGIFPREFIX_IN6, (caddr_t)ipr) < 0) { 851 syslog(LOG_INFO, "<%s> ioctl:SIOCGIFPREFIX %s", __func__, 852 strerror(errno)); 853 854 ipr->ipr_vltime = DEF_ADVVALIDLIFETIME; 855 ipr->ipr_pltime = DEF_ADVPREFERREDLIFETIME; 856 ipr->ipr_raf_onlink = 1; 857 ipr->ipr_raf_auto = 1; 858 /* omit other field initialization */ 859 } 860 else if (ipr->ipr_origin < PR_ORIG_RR) { 861 char ntopbuf[INET6_ADDRSTRLEN]; 862 863 syslog(LOG_WARNING, "<%s> Added prefix(%s)'s origin %d is" 864 "lower than PR_ORIG_RR(router renumbering)." 865 "This should not happen if I am router", __func__, 866 inet_ntop(AF_INET6, &ipr->ipr_prefix.sin6_addr, ntopbuf, 867 sizeof(ntopbuf)), ipr->ipr_origin); 868 close(s); 869 return 1; 870 } 871 872 close(s); 873 return 0; 874 #else 875 ipr->ipr_vltime = DEF_ADVVALIDLIFETIME; 876 ipr->ipr_pltime = DEF_ADVPREFERREDLIFETIME; 877 ipr->ipr_raf_onlink = 1; 878 ipr->ipr_raf_auto = 1; 879 return 0; 880 #endif 881 } 882 883 void 884 make_prefix(struct rainfo *rai, int ifindex, struct in6_addr *addr, int plen) 885 { 886 struct in6_prefixreq ipr; 887 888 memset(&ipr, 0, sizeof(ipr)); 889 if (if_indextoname(ifindex, ipr.ipr_name) == NULL) { 890 syslog(LOG_ERR, "<%s> Prefix added interface No.%d doesn't" 891 "exist. This should not happen! %s", __func__, 892 ifindex, strerror(errno)); 893 exit(1); 894 } 895 ipr.ipr_prefix.sin6_len = sizeof(ipr.ipr_prefix); 896 ipr.ipr_prefix.sin6_family = AF_INET6; 897 ipr.ipr_prefix.sin6_addr = *addr; 898 ipr.ipr_plen = plen; 899 900 if (init_prefix(&ipr)) 901 return; /* init failed by some error */ 902 add_prefix(rai, &ipr); 903 } 904 905 void 906 make_packet(struct rainfo *rainfo) 907 { 908 size_t packlen, lladdroptlen = 0; 909 u_char *buf; 910 struct nd_router_advert *ra; 911 struct nd_opt_prefix_info *ndopt_pi; 912 struct nd_opt_mtu *ndopt_mtu; 913 struct prefix *pfx; 914 #ifdef ROUTEINFO 915 struct nd_opt_route_info *ndopt_rti; 916 struct rtinfo *rti; 917 #endif 918 919 /* calculate total length */ 920 packlen = sizeof(struct nd_router_advert); 921 if (rainfo->advlinkopt) { 922 if ((lladdroptlen = lladdropt_length(rainfo->sdl)) == 0) { 923 syslog(LOG_INFO, 924 "<%s> link-layer address option has" 925 " null length on %s. Treat as not included.", 926 __func__, rainfo->ifname); 927 rainfo->advlinkopt = 0; 928 } 929 packlen += lladdroptlen; 930 } 931 if (rainfo->pfxs) 932 packlen += sizeof(struct nd_opt_prefix_info) * rainfo->pfxs; 933 if (rainfo->linkmtu) 934 packlen += sizeof(struct nd_opt_mtu); 935 #ifdef ROUTEINFO 936 for (rti = rainfo->route.next; rti != &rainfo->route; rti = rti->next) 937 packlen += sizeof(struct nd_opt_route_info) + 938 ((rti->prefixlen + 0x3f) >> 6) * 8; 939 #endif 940 941 /* allocate memory for the packet */ 942 if ((buf = malloc(packlen)) == NULL) { 943 syslog(LOG_ERR, 944 "<%s> can't get enough memory for an RA packet", 945 __func__); 946 exit(1); 947 } 948 if (rainfo->ra_data) { 949 /* free the previous packet */ 950 free(rainfo->ra_data); 951 rainfo->ra_data = NULL; 952 } 953 rainfo->ra_data = buf; 954 /* XXX: what if packlen > 576? */ 955 rainfo->ra_datalen = packlen; 956 957 /* 958 * construct the packet 959 */ 960 ra = (struct nd_router_advert *)buf; 961 ra->nd_ra_type = ND_ROUTER_ADVERT; 962 ra->nd_ra_code = 0; 963 ra->nd_ra_cksum = 0; 964 ra->nd_ra_curhoplimit = (u_int8_t)(0xff & rainfo->hoplimit); 965 ra->nd_ra_flags_reserved = 0; /* just in case */ 966 /* 967 * XXX: the router preference field, which is a 2-bit field, should be 968 * initialized before other fields. 969 */ 970 ra->nd_ra_flags_reserved = 0xff & rainfo->rtpref; 971 ra->nd_ra_flags_reserved |= 972 rainfo->managedflg ? ND_RA_FLAG_MANAGED : 0; 973 ra->nd_ra_flags_reserved |= 974 rainfo->otherflg ? ND_RA_FLAG_OTHER : 0; 975 ra->nd_ra_router_lifetime = htons(rainfo->lifetime); 976 ra->nd_ra_reachable = htonl(rainfo->reachabletime); 977 ra->nd_ra_retransmit = htonl(rainfo->retranstimer); 978 buf += sizeof(*ra); 979 980 if (rainfo->advlinkopt) { 981 lladdropt_fill(rainfo->sdl, (struct nd_opt_hdr *)buf); 982 buf += lladdroptlen; 983 } 984 985 if (rainfo->linkmtu) { 986 ndopt_mtu = (struct nd_opt_mtu *)buf; 987 ndopt_mtu->nd_opt_mtu_type = ND_OPT_MTU; 988 ndopt_mtu->nd_opt_mtu_len = 1; 989 ndopt_mtu->nd_opt_mtu_reserved = 0; 990 ndopt_mtu->nd_opt_mtu_mtu = htonl(rainfo->linkmtu); 991 buf += sizeof(struct nd_opt_mtu); 992 } 993 994 995 996 for (pfx = rainfo->prefix.next; 997 pfx != &rainfo->prefix; pfx = pfx->next) { 998 u_int32_t vltime, pltime; 999 struct timeval now; 1000 1001 ndopt_pi = (struct nd_opt_prefix_info *)buf; 1002 ndopt_pi->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION; 1003 ndopt_pi->nd_opt_pi_len = 4; 1004 ndopt_pi->nd_opt_pi_prefix_len = pfx->prefixlen; 1005 ndopt_pi->nd_opt_pi_flags_reserved = 0; 1006 if (pfx->onlinkflg) 1007 ndopt_pi->nd_opt_pi_flags_reserved |= 1008 ND_OPT_PI_FLAG_ONLINK; 1009 if (pfx->autoconfflg) 1010 ndopt_pi->nd_opt_pi_flags_reserved |= 1011 ND_OPT_PI_FLAG_AUTO; 1012 if (pfx->timer) 1013 vltime = 0; 1014 else { 1015 if (pfx->vltimeexpire || pfx->pltimeexpire) 1016 gettimeofday(&now, NULL); 1017 if (pfx->vltimeexpire == 0) 1018 vltime = pfx->validlifetime; 1019 else 1020 vltime = (pfx->vltimeexpire > now.tv_sec) ? 1021 pfx->vltimeexpire - now.tv_sec : 0; 1022 } 1023 if (pfx->timer) 1024 pltime = 0; 1025 else { 1026 if (pfx->pltimeexpire == 0) 1027 pltime = pfx->preflifetime; 1028 else 1029 pltime = (pfx->pltimeexpire > now.tv_sec) ? 1030 pfx->pltimeexpire - now.tv_sec : 0; 1031 } 1032 if (vltime < pltime) { 1033 /* 1034 * this can happen if vltime is decrement but pltime 1035 * is not. 1036 */ 1037 pltime = vltime; 1038 } 1039 ndopt_pi->nd_opt_pi_valid_time = htonl(vltime); 1040 ndopt_pi->nd_opt_pi_preferred_time = htonl(pltime); 1041 ndopt_pi->nd_opt_pi_reserved2 = 0; 1042 ndopt_pi->nd_opt_pi_prefix = pfx->prefix; 1043 1044 buf += sizeof(struct nd_opt_prefix_info); 1045 } 1046 1047 #ifdef ROUTEINFO 1048 for (rti = rainfo->route.next; rti != &rainfo->route; rti = rti->next) { 1049 u_int8_t psize = (rti->prefixlen + 0x3f) >> 6; 1050 1051 ndopt_rti = (struct nd_opt_route_info *)buf; 1052 ndopt_rti->nd_opt_rti_type = ND_OPT_ROUTE_INFO; 1053 ndopt_rti->nd_opt_rti_len = 1 + psize; 1054 ndopt_rti->nd_opt_rti_prefixlen = rti->prefixlen; 1055 ndopt_rti->nd_opt_rti_flags = 0xff & rti->rtpref; 1056 ndopt_rti->nd_opt_rti_lifetime = htonl(rti->ltime); 1057 memcpy(ndopt_rti + 1, &rti->prefix, psize * 8); 1058 buf += sizeof(struct nd_opt_route_info) + psize * 8; 1059 } 1060 #endif 1061 1062 return; 1063 } 1064 1065 static int 1066 getinet6sysctl(int code) 1067 { 1068 int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, 0 }; 1069 int value; 1070 size_t size; 1071 1072 mib[3] = code; 1073 size = sizeof(value); 1074 if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), &value, &size, NULL, 0) 1075 < 0) { 1076 syslog(LOG_ERR, "<%s>: failed to get ip6 sysctl(%d): %s", 1077 __func__, code, 1078 strerror(errno)); 1079 return(-1); 1080 } 1081 else 1082 return(value); 1083 } 1084