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