config.c revision 97709
176612Stshiozak/* $FreeBSD: head/usr.sbin/rtadvd/config.c 97709 2002-06-01 16:50:21Z ume $ */ 276612Stshiozak/* $KAME: config.c,v 1.37 2001/05/25 07:34:00 itojun Exp $ */ 376612Stshiozak 476612Stshiozak/* 576612Stshiozak * Copyright (C) 1998 WIDE Project. 676612Stshiozak * All rights reserved. 776612Stshiozak * 876612Stshiozak * Redistribution and use in source and binary forms, with or without 976612Stshiozak * modification, are permitted provided that the following conditions 1076612Stshiozak * are met: 1176612Stshiozak * 1. Redistributions of source code must retain the above copyright 1276612Stshiozak * notice, this list of conditions and the following disclaimer. 1376612Stshiozak * 2. Redistributions in binary form must reproduce the above copyright 1476612Stshiozak * notice, this list of conditions and the following disclaimer in the 1576612Stshiozak * documentation and/or other materials provided with the distribution. 1676612Stshiozak * 3. Neither the name of the project nor the names of its contributors 1776612Stshiozak * may be used to endorse or promote products derived from this software 1876612Stshiozak * without specific prior written permission. 1976612Stshiozak * 2076612Stshiozak * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 2176612Stshiozak * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2276612Stshiozak * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2376612Stshiozak * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2476612Stshiozak * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2576612Stshiozak * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2676612Stshiozak * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2776612Stshiozak * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2876612Stshiozak * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2976612Stshiozak * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3076612Stshiozak * SUCH DAMAGE. 3176612Stshiozak */ 3276612Stshiozak 3386170Sobrien#include <sys/param.h> 3476612Stshiozak#include <sys/ioctl.h> 3576612Stshiozak#include <sys/socket.h> 3676612Stshiozak#include <sys/time.h> 3776612Stshiozak#include <sys/sysctl.h> 3876612Stshiozak 3976612Stshiozak#include <net/if.h> 4076612Stshiozak#if defined(__FreeBSD__) && __FreeBSD__ >= 3 4176612Stshiozak#include <net/if_var.h> 4276612Stshiozak#endif /* __FreeBSD__ >= 3 */ 4376612Stshiozak#include <net/route.h> 4476612Stshiozak#include <net/if_dl.h> 4576612Stshiozak 4676612Stshiozak#include <netinet/in.h> 4776612Stshiozak#include <netinet/in_var.h> 4876612Stshiozak#include <netinet/ip6.h> 4976612Stshiozak#include <netinet6/ip6_var.h> 5076612Stshiozak#include <netinet/icmp6.h> 5176612Stshiozak#ifdef MIP6 5276612Stshiozak#include <netinet6/mip6.h> 5376612Stshiozak#endif 5476612Stshiozak 5576612Stshiozak#include <arpa/inet.h> 5676612Stshiozak 57#include <stdio.h> 58#include <syslog.h> 59#include <errno.h> 60#include <string.h> 61#include <stdlib.h> 62#if defined(__NetBSD__) || defined(__OpenBSD__) 63#include <search.h> 64#endif 65#include <unistd.h> 66#include <ifaddrs.h> 67 68#include "rtadvd.h" 69#include "advcap.h" 70#include "timer.h" 71#include "if.h" 72#include "config.h" 73 74static void makeentry __P((char *, size_t, int, char *, int)); 75static void get_prefix __P((struct rainfo *)); 76static int getinet6sysctl __P((int)); 77 78extern struct rainfo *ralist; 79 80void 81getconfig(intface) 82 char *intface; 83{ 84 int stat, pfxs, i; 85 char tbuf[BUFSIZ]; 86 struct rainfo *tmp; 87 long val; 88 long long val64; 89 char buf[BUFSIZ]; 90 char *bp = buf; 91 char *addr; 92 static int forwarding = -1; 93 94#define MUSTHAVE(var, cap) \ 95 do { \ 96 int t; \ 97 if ((t = agetnum(cap)) < 0) { \ 98 fprintf(stderr, "rtadvd: need %s for interface %s\n", \ 99 cap, intface); \ 100 exit(1); \ 101 } \ 102 var = t; \ 103 } while (0) 104#define MAYHAVE(var, cap, def) \ 105 do { \ 106 if ((var = agetnum(cap)) < 0) \ 107 var = def; \ 108 } while (0) 109 110 if ((stat = agetent(tbuf, intface)) <= 0) { 111 memset(tbuf, 0, sizeof(tbuf)); 112 syslog(LOG_INFO, 113 "<%s> %s isn't defined in the configuration file" 114 " or the configuration file doesn't exist." 115 " Treat it as default", 116 __FUNCTION__, intface); 117 } 118 119 tmp = (struct rainfo *)malloc(sizeof(*ralist)); 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 __FUNCTION__, 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 __FUNCTION__, 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 __FUNCTION__, 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 __FUNCTION__, 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#ifdef MIP6 182 if (mobileip6) 183 tmp->haflg = val & ND_RA_FLAG_HA; 184#endif 185#ifndef ND_RA_FLAG_RTPREF_MASK 186#define ND_RA_FLAG_RTPREF_MASK 0x18 /* 00011000 */ 187#define ND_RA_FLAG_RTPREF_RSV 0x10 /* 00010000 */ 188#endif 189 tmp->rtpref = val & ND_RA_FLAG_RTPREF_MASK; 190 if (tmp->rtpref == ND_RA_FLAG_RTPREF_RSV) { 191 syslog(LOG_ERR, "<%s> invalid router preference on %s", 192 __FUNCTION__, intface); 193 exit(1); 194 } 195 196 MAYHAVE(val, "rltime", tmp->maxinterval * 3); 197 if (val && (val < tmp->maxinterval || val > MAXROUTERLIFETIME)) { 198 syslog(LOG_ERR, 199 "<%s> router lifetime on %s must be 0 or" 200 " between %d and %d", 201 __FUNCTION__, intface, 202 tmp->maxinterval, MAXROUTERLIFETIME); 203 exit(1); 204 } 205 /* 206 * Basically, hosts MUST NOT send Router Advertisement messages at any 207 * time (RFC 2461, Section 6.2.3). However, it would sometimes be 208 * useful to allow hosts to advertise some parameters such as prefix 209 * information and link MTU. Thus, we allow hosts to invoke rtadvd 210 * only when router lifetime (on every advertising interface) is 211 * explicitly set zero. (see also the above section) 212 */ 213 if (val && forwarding == 0) { 214 syslog(LOG_WARNING, 215 "<%s> non zero router lifetime is specified for %s, " 216 "which must not be allowed for hosts.", 217 __FUNCTION__, intface); 218 exit(1); 219 } 220 tmp->lifetime = val & 0xffff; 221 222 MAYHAVE(val, "rtime", DEF_ADVREACHABLETIME); 223 if (val > MAXREACHABLETIME) { 224 syslog(LOG_ERR, 225 "<%s> reachable time must be no greater than %d", 226 __FUNCTION__, MAXREACHABLETIME); 227 exit(1); 228 } 229 tmp->reachabletime = (u_int32_t)val; 230 231 MAYHAVE(val64, "retrans", DEF_ADVRETRANSTIMER); 232 if (val64 < 0 || val64 > 0xffffffff) { 233 syslog(LOG_ERR, 234 "<%s> retrans time out of range", __FUNCTION__); 235 exit(1); 236 } 237 tmp->retranstimer = (u_int32_t)val64; 238 239#ifndef MIP6 240 if (agetstr("hapref", &bp) || agetstr("hatime", &bp)) { 241 syslog(LOG_ERR, 242 "<%s> mobile-ip6 configuration not supported", 243 __FUNCTION__); 244 exit(1); 245 } 246#else 247 if (!mobileip6) { 248 if (agetstr("hapref", &bp) || agetstr("hatime", &bp)) { 249 syslog(LOG_ERR, 250 "<%s> mobile-ip6 configuration without " 251 "proper command line option", 252 __FUNCTION__); 253 exit(1); 254 } 255 } else { 256 tmp->hapref = 0; 257 if ((val = agetnum("hapref")) >= 0) 258 tmp->hapref = (int16_t)val; 259 if (tmp->hapref != 0) { 260 tmp->hatime = 0; 261 MUSTHAVE(val, "hatime"); 262 tmp->hatime = (u_int16_t)val; 263 if (tmp->hatime <= 0) { 264 syslog(LOG_ERR, 265 "<%s> home agent lifetime must be greater than 0", 266 __FUNCTION__); 267 exit(1); 268 } 269 } 270 } 271#endif 272 273 /* prefix information */ 274 275 /* 276 * This is an implementation specific parameter to consinder 277 * link propagation delays and poorly synchronized clocks when 278 * checking consistency of advertised lifetimes. 279 */ 280 MAYHAVE(val, "clockskew", 0); 281 tmp->clockskew = val; 282 283 if ((pfxs = agetnum("addrs")) < 0) { 284 /* auto configure prefix information */ 285 if (agetstr("addr", &bp) || agetstr("addr1", &bp)) { 286 syslog(LOG_ERR, 287 "<%s> conflicting prefix configuration for %s: " 288 "automatic and manual config at the same time", 289 __FUNCTION__, intface); 290 exit(1); 291 } 292 get_prefix(tmp); 293 } 294 else { 295 tmp->pfxs = pfxs; 296 for (i = 0; i < pfxs; i++) { 297 struct prefix *pfx; 298 char entbuf[256]; 299 int added = (pfxs > 1) ? 1 : 0; 300 301 /* allocate memory to store prefix information */ 302 if ((pfx = malloc(sizeof(struct prefix))) == NULL) { 303 syslog(LOG_ERR, 304 "<%s> can't allocate enough memory", 305 __FUNCTION__); 306 exit(1); 307 } 308 memset(pfx, 0, sizeof(*pfx)); 309 310 /* link into chain */ 311 insque(pfx, &tmp->prefix); 312 313 pfx->origin = PREFIX_FROM_CONFIG; 314 315 makeentry(entbuf, sizeof(entbuf), i, "prefixlen", 316 added); 317 MAYHAVE(val, entbuf, 64); 318 if (val < 0 || val > 128) { 319 syslog(LOG_ERR, 320 "<%s> prefixlen out of range", 321 __FUNCTION__); 322 exit(1); 323 } 324 pfx->prefixlen = (int)val; 325 326 makeentry(entbuf, sizeof(entbuf), i, "pinfoflags", 327 added); 328#ifdef MIP6 329 if (mobileip6) 330 { 331 MAYHAVE(val, entbuf, 332 (ND_OPT_PI_FLAG_ONLINK|ND_OPT_PI_FLAG_AUTO| 333 ND_OPT_PI_FLAG_ROUTER)); 334 } else 335#endif 336 { 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#ifdef MIP6 343 pfx->routeraddr = val & ND_OPT_PI_FLAG_ROUTER; 344#endif 345 346 makeentry(entbuf, sizeof(entbuf), i, "vltime", added); 347 MAYHAVE(val64, entbuf, DEF_ADVVALIDLIFETIME); 348 if (val64 < 0 || val64 > 0xffffffff) { 349 syslog(LOG_ERR, 350 "<%s> vltime out of range", 351 __FUNCTION__); 352 exit(1); 353 } 354 pfx->validlifetime = (u_int32_t)val64; 355 356 makeentry(entbuf, sizeof(entbuf), i, "vltimedecr", 357 added); 358 if (agetflag(entbuf)) { 359 struct timeval now; 360 gettimeofday(&now, 0); 361 pfx->vltimeexpire = 362 now.tv_sec + pfx->validlifetime; 363 } 364 365 makeentry(entbuf, sizeof(entbuf), i, "pltime", added); 366 MAYHAVE(val64, entbuf, DEF_ADVPREFERREDLIFETIME); 367 if (val64 < 0 || val64 > 0xffffffff) { 368 syslog(LOG_ERR, 369 "<%s> pltime out of range", 370 __FUNCTION__); 371 exit(1); 372 } 373 pfx->preflifetime = (u_int32_t)val64; 374 375 makeentry(entbuf, sizeof(entbuf), i, "pltimedecr", 376 added); 377 if (agetflag(entbuf)) { 378 struct timeval now; 379 gettimeofday(&now, 0); 380 pfx->pltimeexpire = 381 now.tv_sec + pfx->preflifetime; 382 } 383 384 makeentry(entbuf, sizeof(entbuf), i, "addr", added); 385 addr = (char *)agetstr(entbuf, &bp); 386 if (addr == NULL) { 387 syslog(LOG_ERR, 388 "<%s> need %s as an prefix for " 389 "interface %s", 390 __FUNCTION__, entbuf, intface); 391 exit(1); 392 } 393 if (inet_pton(AF_INET6, addr, 394 &pfx->prefix) != 1) { 395 syslog(LOG_ERR, 396 "<%s> inet_pton failed for %s", 397 __FUNCTION__, addr); 398 exit(1); 399 } 400 if (IN6_IS_ADDR_MULTICAST(&pfx->prefix)) { 401 syslog(LOG_ERR, 402 "<%s> multicast prefix(%s) must " 403 "not be advertised (IF=%s)", 404 __FUNCTION__, addr, intface); 405 exit(1); 406 } 407 if (IN6_IS_ADDR_LINKLOCAL(&pfx->prefix)) 408 syslog(LOG_NOTICE, 409 "<%s> link-local prefix(%s) will be" 410 " advertised on %s", 411 __FUNCTION__, addr, intface); 412 } 413 } 414 415 MAYHAVE(val, "mtu", 0); 416 if (val < 0 || val > 0xffffffff) { 417 syslog(LOG_ERR, 418 "<%s> mtu out of range", __FUNCTION__); 419 exit(1); 420 } 421 tmp->linkmtu = (u_int32_t)val; 422 if (tmp->linkmtu == 0) { 423 char *mtustr; 424 425 if ((mtustr = (char *)agetstr("mtu", &bp)) && 426 strcmp(mtustr, "auto") == 0) 427 tmp->linkmtu = tmp->phymtu; 428 } 429 else if (tmp->linkmtu < IPV6_MMTU || tmp->linkmtu > tmp->phymtu) { 430 syslog(LOG_ERR, 431 "<%s> advertised link mtu must be between" 432 " least MTU and physical link MTU", 433 __FUNCTION__); 434 exit(1); 435 } 436 437 /* route information */ 438 439 MAYHAVE(val, "routes", 0); 440 if (val < 0 || val > 0xffffffff) { 441 syslog(LOG_ERR, 442 "<%s> number of route information improper", __FUNCTION__); 443 exit(1); 444 } 445 tmp->routes = val; 446 for (i = 0; i < tmp->routes; i++) { 447 struct rtinfo *rti; 448 char entbuf[256]; 449 int added = (tmp->routes > 1) ? 1 : 0; 450 451 /* allocate memory to store prefix information */ 452 if ((rti = malloc(sizeof(struct rtinfo))) == NULL) { 453 syslog(LOG_ERR, 454 "<%s> can't allocate enough memory", 455 __FUNCTION__); 456 exit(1); 457 } 458 memset(rti, 0, sizeof(*rti)); 459 460 /* link into chain */ 461 insque(rti, &tmp->route); 462 463 makeentry(entbuf, sizeof(entbuf), i, "rtrplen", added); 464 MAYHAVE(val, entbuf, 64); 465 if (val < 0 || val > 128) { 466 syslog(LOG_ERR, 467 "<%s> prefixlen out of range", 468 __FUNCTION__); 469 exit(1); 470 } 471 rti->prefixlen = (int)val; 472 473 makeentry(entbuf, sizeof(entbuf), i, "rtrflags", added); 474 MAYHAVE(val, entbuf, 0); 475 rti->rtpref = val & ND_RA_FLAG_RTPREF_MASK; 476 if (rti->rtpref == ND_RA_FLAG_RTPREF_RSV) { 477 syslog(LOG_ERR, "<%s> invalid router preference", 478 __FUNCTION__); 479 exit(1); 480 } 481 482 makeentry(entbuf, sizeof(entbuf), i, "rtrltime", added); 483 /* 484 * XXX: since default value of route lifetime is not defined in 485 * draft-draves-route-selection-01.txt, I took the default 486 * value of valid lifetime of prefix as its default. 487 * It need be much considered. 488 */ 489 MAYHAVE(val64, entbuf, DEF_ADVVALIDLIFETIME); 490 if (val64 < 0 || val64 > 0xffffffff) { 491 syslog(LOG_ERR, 492 "<%s> rtrltime out of range", 493 __FUNCTION__); 494 exit(1); 495 } 496 rti->ltime = (u_int32_t)val64; 497 498 makeentry(entbuf, sizeof(entbuf), i, "rtrprefix", added); 499 addr = (char *)agetstr(entbuf, &bp); 500 if (addr == NULL) { 501 syslog(LOG_ERR, 502 "<%s> need %s as an route for " 503 "interface %s", 504 __FUNCTION__, entbuf, intface); 505 exit(1); 506 } 507 if (inet_pton(AF_INET6, addr, &rti->prefix) != 1) { 508 syslog(LOG_ERR, 509 "<%s> inet_pton failed for %s", 510 __FUNCTION__, addr); 511 exit(1); 512 } 513#if 0 514 /* 515 * XXX: currently there's no restriction in route information 516 * prefix according to draft-draves-route-selection-01.txt, 517 * however I think the similar restriction be necessary. 518 */ 519 MAYHAVE(val64, entbuf, DEF_ADVVALIDLIFETIME); 520 if (IN6_IS_ADDR_MULTICAST(&rti->prefix)) { 521 syslog(LOG_ERR, 522 "<%s> multicast route (%s) must " 523 "not be advertised (IF=%s)", 524 __FUNCTION__, addr, intface); 525 exit(1); 526 } 527 if (IN6_IS_ADDR_LINKLOCAL(&rti->prefix)) { 528 syslog(LOG_NOTICE, 529 "<%s> link-local route (%s) must " 530 "not be advertised on %s", 531 __FUNCTION__, addr, intface); 532 exit(1); 533 } 534#endif 535 } 536 537 /* okey */ 538 tmp->next = ralist; 539 ralist = tmp; 540 541 /* construct the sending packet */ 542 make_packet(tmp); 543 544 /* set timer */ 545 tmp->timer = rtadvd_add_timer(ra_timeout, ra_timer_update, 546 tmp, tmp); 547 ra_timer_update((void *)tmp, &tmp->timer->tm); 548 rtadvd_set_timer(&tmp->timer->tm, tmp->timer); 549} 550 551static void 552get_prefix(struct rainfo *rai) 553{ 554 struct ifaddrs *ifap, *ifa; 555 struct prefix *pp; 556 struct in6_addr *a; 557 u_char *p, *ep, *m, *lim; 558 u_char ntopbuf[INET6_ADDRSTRLEN]; 559 560 if (getifaddrs(&ifap) < 0) { 561 syslog(LOG_ERR, 562 "<%s> can't get interface addresses", 563 __FUNCTION__); 564 exit(1); 565 } 566 for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 567 if (strcmp(ifa->ifa_name, rai->ifname) != 0) 568 continue; 569 if (ifa->ifa_addr->sa_family != AF_INET6) 570 continue; 571 a = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr; 572 if (IN6_IS_ADDR_LINKLOCAL(a)) 573 continue; 574 575 /* allocate memory to store prefix info. */ 576 if ((pp = malloc(sizeof(*pp))) == NULL) { 577 syslog(LOG_ERR, 578 "<%s> can't get allocate buffer for prefix", 579 __FUNCTION__); 580 exit(1); 581 } 582 memset(pp, 0, sizeof(*pp)); 583 584 /* set prefix length */ 585 m = (u_char *)&((struct sockaddr_in6 *)ifa->ifa_netmask)->sin6_addr; 586 lim = (u_char *)(ifa->ifa_netmask) + ifa->ifa_netmask->sa_len; 587 pp->prefixlen = prefixlen(m, lim); 588 if (pp->prefixlen < 0 || pp->prefixlen > 128) { 589 syslog(LOG_ERR, 590 "<%s> failed to get prefixlen " 591 "or prefix is invalid", 592 __FUNCTION__); 593 exit(1); 594 } 595 596 /* set prefix, sweep bits outside of prefixlen */ 597 memcpy(&pp->prefix, a, sizeof(*a)); 598 p = (u_char *)&pp->prefix; 599 ep = (u_char *)(&pp->prefix + 1); 600 while (m < lim) 601 *p++ &= *m++; 602 while (p < ep) 603 *p++ = 0x00; 604 605 if (!inet_ntop(AF_INET6, &pp->prefix, ntopbuf, 606 sizeof(ntopbuf))) { 607 syslog(LOG_ERR, "<%s> inet_ntop failed", __FUNCTION__); 608 exit(1); 609 } 610 syslog(LOG_DEBUG, 611 "<%s> add %s/%d to prefix list on %s", 612 __FUNCTION__, ntopbuf, pp->prefixlen, rai->ifname); 613 614 /* set other fields with protocol defaults */ 615 pp->validlifetime = DEF_ADVVALIDLIFETIME; 616 pp->preflifetime = DEF_ADVPREFERREDLIFETIME; 617 pp->onlinkflg = 1; 618 pp->autoconfflg = 1; 619 pp->origin = PREFIX_FROM_KERNEL; 620 621 /* link into chain */ 622 insque(pp, &rai->prefix); 623 624 /* counter increment */ 625 rai->pfxs++; 626 } 627 628 freeifaddrs(ifap); 629} 630 631static void 632makeentry(buf, len, id, string, add) 633 char *buf; 634 size_t len; 635 int id; 636 char *string; 637 int add; 638{ 639 char *ep = buf + len; 640 641 strcpy(buf, string); 642 if (add) { 643 char *cp; 644 645 cp = (char *)index(buf, '\0'); 646 snprintf(cp, ep - cp, "%d", id); 647 } 648} 649 650/* 651 * Add a prefix to the list of specified interface and reconstruct 652 * the outgoing packet. 653 * The prefix must not be in the list. 654 * XXX: other parameter of the prefix(e.g. lifetime) shoule be 655 * able to be specified. 656 */ 657static void 658add_prefix(struct rainfo *rai, struct in6_prefixreq *ipr) 659{ 660 struct prefix *prefix; 661 u_char ntopbuf[INET6_ADDRSTRLEN]; 662 663 if ((prefix = malloc(sizeof(*prefix))) == NULL) { 664 syslog(LOG_ERR, "<%s> memory allocation failed", 665 __FUNCTION__); 666 return; /* XXX: error or exit? */ 667 } 668 memset(prefix, 0, sizeof(*prefix)); 669 prefix->prefix = ipr->ipr_prefix.sin6_addr; 670 prefix->prefixlen = ipr->ipr_plen; 671 prefix->validlifetime = ipr->ipr_vltime; 672 prefix->preflifetime = ipr->ipr_pltime; 673 prefix->onlinkflg = ipr->ipr_raf_onlink; 674 prefix->autoconfflg = ipr->ipr_raf_auto; 675 prefix->origin = PREFIX_FROM_DYNAMIC; 676 677 insque(prefix, &rai->prefix); 678 679 syslog(LOG_DEBUG, "<%s> new prefix %s/%d was added on %s", 680 __FUNCTION__, inet_ntop(AF_INET6, &ipr->ipr_prefix.sin6_addr, 681 ntopbuf, INET6_ADDRSTRLEN), 682 ipr->ipr_plen, rai->ifname); 683 684 /* free the previous packet */ 685 free(rai->ra_data); 686 rai->ra_data = NULL; 687 688 /* reconstruct the packet */ 689 rai->pfxs++; 690 make_packet(rai); 691 692 /* 693 * reset the timer so that the new prefix will be advertised quickly. 694 */ 695 rai->initcounter = 0; 696 ra_timer_update((void *)rai, &rai->timer->tm); 697 rtadvd_set_timer(&rai->timer->tm, rai->timer); 698} 699 700/* 701 * Delete a prefix to the list of specified interface and reconstruct 702 * the outgoing packet. 703 * The prefix must be in the list. 704 */ 705void 706delete_prefix(struct rainfo *rai, struct prefix *prefix) 707{ 708 u_char ntopbuf[INET6_ADDRSTRLEN]; 709 710 remque(prefix); 711 syslog(LOG_DEBUG, "<%s> prefix %s/%d was deleted on %s", 712 __FUNCTION__, inet_ntop(AF_INET6, &prefix->prefix, 713 ntopbuf, INET6_ADDRSTRLEN), 714 prefix->prefixlen, rai->ifname); 715 free(prefix); 716 rai->pfxs--; 717 make_packet(rai); 718} 719 720/* 721 * Try to get an in6_prefixreq contents for a prefix which matches 722 * ipr->ipr_prefix and ipr->ipr_plen and belongs to 723 * the interface whose name is ipr->ipr_name[]. 724 */ 725static int 726init_prefix(struct in6_prefixreq *ipr) 727{ 728 int s; 729 730 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 731 syslog(LOG_ERR, "<%s> socket: %s", __FUNCTION__, 732 strerror(errno)); 733 exit(1); 734 } 735 736 if (ioctl(s, SIOCGIFPREFIX_IN6, (caddr_t)ipr) < 0) { 737 syslog(LOG_INFO, "<%s> ioctl:SIOCGIFPREFIX %s", __FUNCTION__, 738 strerror(errno)); 739 740 ipr->ipr_vltime = DEF_ADVVALIDLIFETIME; 741 ipr->ipr_pltime = DEF_ADVPREFERREDLIFETIME; 742 ipr->ipr_raf_onlink = 1; 743 ipr->ipr_raf_auto = 1; 744 /* omit other field initialization */ 745 } 746 else if (ipr->ipr_origin < PR_ORIG_RR) { 747 u_char ntopbuf[INET6_ADDRSTRLEN]; 748 749 syslog(LOG_WARNING, "<%s> Added prefix(%s)'s origin %d is" 750 "lower than PR_ORIG_RR(router renumbering)." 751 "This should not happen if I am router", __FUNCTION__, 752 inet_ntop(AF_INET6, &ipr->ipr_prefix.sin6_addr, ntopbuf, 753 sizeof(ntopbuf)), ipr->ipr_origin); 754 close(s); 755 return 1; 756 } 757 758 close(s); 759 return 0; 760} 761 762void 763make_prefix(struct rainfo *rai, int ifindex, struct in6_addr *addr, int plen) 764{ 765 struct in6_prefixreq ipr; 766 767 memset(&ipr, 0, sizeof(ipr)); 768 if (if_indextoname(ifindex, ipr.ipr_name) == NULL) { 769 syslog(LOG_ERR, "<%s> Prefix added interface No.%d doesn't" 770 "exist. This should not happen! %s", __FUNCTION__, 771 ifindex, strerror(errno)); 772 exit(1); 773 } 774 ipr.ipr_prefix.sin6_len = sizeof(ipr.ipr_prefix); 775 ipr.ipr_prefix.sin6_family = AF_INET6; 776 ipr.ipr_prefix.sin6_addr = *addr; 777 ipr.ipr_plen = plen; 778 779 if (init_prefix(&ipr)) 780 return; /* init failed by some error */ 781 add_prefix(rai, &ipr); 782} 783 784void 785make_packet(struct rainfo *rainfo) 786{ 787 size_t packlen, lladdroptlen = 0; 788 char *buf; 789 struct nd_router_advert *ra; 790 struct nd_opt_prefix_info *ndopt_pi; 791 struct nd_opt_mtu *ndopt_mtu; 792#ifdef MIP6 793 struct nd_opt_advinterval *ndopt_advint; 794 struct nd_opt_homeagent_info *ndopt_hai; 795#endif 796 struct nd_opt_route_info *ndopt_rti; 797 struct prefix *pfx; 798 struct rtinfo *rti; 799 800 /* calculate total length */ 801 packlen = sizeof(struct nd_router_advert); 802 if (rainfo->advlinkopt) { 803 if ((lladdroptlen = lladdropt_length(rainfo->sdl)) == 0) { 804 syslog(LOG_INFO, 805 "<%s> link-layer address option has" 806 " null length on %s." 807 " Treat as not included.", 808 __FUNCTION__, rainfo->ifname); 809 rainfo->advlinkopt = 0; 810 } 811 packlen += lladdroptlen; 812 } 813 if (rainfo->pfxs) 814 packlen += sizeof(struct nd_opt_prefix_info) * rainfo->pfxs; 815 if (rainfo->linkmtu) 816 packlen += sizeof(struct nd_opt_mtu); 817#ifdef MIP6 818 if (mobileip6 && rainfo->maxinterval) 819 packlen += sizeof(struct nd_opt_advinterval); 820 if (mobileip6 && rainfo->hatime) 821 packlen += sizeof(struct nd_opt_homeagent_info); 822#endif 823#ifdef ND_OPT_ROUTE_INFO 824 for (rti = rainfo->route.next; rti != &rainfo->route; rti = rti->next) 825 packlen += sizeof(struct nd_opt_route_info) + 826 ((rti->prefixlen + 0x3f) >> 6) * 8; 827#endif 828 829 /* allocate memory for the packet */ 830 if ((buf = malloc(packlen)) == NULL) { 831 syslog(LOG_ERR, 832 "<%s> can't get enough memory for an RA packet", 833 __FUNCTION__); 834 exit(1); 835 } 836 if (rainfo->ra_data) { 837 /* free the previous packet */ 838 free(rainfo->ra_data); 839 rainfo->ra_data = NULL; 840 } 841 rainfo->ra_data = buf; 842 /* XXX: what if packlen > 576? */ 843 rainfo->ra_datalen = packlen; 844 845 /* 846 * construct the packet 847 */ 848 ra = (struct nd_router_advert *)buf; 849 ra->nd_ra_type = ND_ROUTER_ADVERT; 850 ra->nd_ra_code = 0; 851 ra->nd_ra_cksum = 0; 852 ra->nd_ra_curhoplimit = (u_int8_t)(0xff & rainfo->hoplimit); 853 ra->nd_ra_flags_reserved = 0; /* just in case */ 854 /* 855 * XXX: the router preference field, which is a 2-bit field, should be 856 * initialized before other fields. 857 */ 858 ra->nd_ra_flags_reserved = 0xff & rainfo->rtpref; 859 ra->nd_ra_flags_reserved |= 860 rainfo->managedflg ? ND_RA_FLAG_MANAGED : 0; 861 ra->nd_ra_flags_reserved |= 862 rainfo->otherflg ? ND_RA_FLAG_OTHER : 0; 863#ifdef MIP6 864 ra->nd_ra_flags_reserved |= 865 rainfo->haflg ? ND_RA_FLAG_HA : 0; 866#endif 867 ra->nd_ra_router_lifetime = htons(rainfo->lifetime); 868 ra->nd_ra_reachable = htonl(rainfo->reachabletime); 869 ra->nd_ra_retransmit = htonl(rainfo->retranstimer); 870 buf += sizeof(*ra); 871 872 if (rainfo->advlinkopt) { 873 lladdropt_fill(rainfo->sdl, (struct nd_opt_hdr *)buf); 874 buf += lladdroptlen; 875 } 876 877 if (rainfo->linkmtu) { 878 ndopt_mtu = (struct nd_opt_mtu *)buf; 879 ndopt_mtu->nd_opt_mtu_type = ND_OPT_MTU; 880 ndopt_mtu->nd_opt_mtu_len = 1; 881 ndopt_mtu->nd_opt_mtu_reserved = 0; 882 ndopt_mtu->nd_opt_mtu_mtu = htonl(rainfo->linkmtu); 883 buf += sizeof(struct nd_opt_mtu); 884 } 885 886#ifdef MIP6 887 if (mobileip6 && rainfo->maxinterval) { 888 ndopt_advint = (struct nd_opt_advinterval *)buf; 889 ndopt_advint->nd_opt_adv_type = ND_OPT_ADVINTERVAL; 890 ndopt_advint->nd_opt_adv_len = 1; 891 ndopt_advint->nd_opt_adv_reserved = 0; 892 ndopt_advint->nd_opt_adv_interval = htonl(rainfo->maxinterval * 893 1000); 894 buf += sizeof(struct nd_opt_advinterval); 895 } 896#endif 897 898#ifdef MIP6 899 if (rainfo->hatime) { 900 ndopt_hai = (struct nd_opt_homeagent_info *)buf; 901 ndopt_hai->nd_opt_hai_type = ND_OPT_HOMEAGENT_INFO; 902 ndopt_hai->nd_opt_hai_len = 1; 903 ndopt_hai->nd_opt_hai_reserved = 0; 904 ndopt_hai->nd_opt_hai_preference = htons(rainfo->hapref); 905 ndopt_hai->nd_opt_hai_lifetime = htons(rainfo->hatime); 906 buf += sizeof(struct nd_opt_homeagent_info); 907 } 908#endif 909 910 for (pfx = rainfo->prefix.next; 911 pfx != &rainfo->prefix; pfx = pfx->next) { 912 u_int32_t vltime, pltime; 913 struct timeval now; 914 915 ndopt_pi = (struct nd_opt_prefix_info *)buf; 916 ndopt_pi->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION; 917 ndopt_pi->nd_opt_pi_len = 4; 918 ndopt_pi->nd_opt_pi_prefix_len = pfx->prefixlen; 919 ndopt_pi->nd_opt_pi_flags_reserved = 0; 920 if (pfx->onlinkflg) 921 ndopt_pi->nd_opt_pi_flags_reserved |= 922 ND_OPT_PI_FLAG_ONLINK; 923 if (pfx->autoconfflg) 924 ndopt_pi->nd_opt_pi_flags_reserved |= 925 ND_OPT_PI_FLAG_AUTO; 926#ifdef MIP6 927 if (pfx->routeraddr) 928 ndopt_pi->nd_opt_pi_flags_reserved |= 929 ND_OPT_PI_FLAG_ROUTER; 930#endif 931 if (pfx->vltimeexpire || pfx->pltimeexpire) 932 gettimeofday(&now, NULL); 933 if (pfx->vltimeexpire == 0) 934 vltime = pfx->validlifetime; 935 else 936 vltime = (pfx->vltimeexpire > now.tv_sec) ? 937 pfx->vltimeexpire - now.tv_sec : 0; 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 if (vltime < pltime) { 944 /* 945 * this can happen if vltime is decrement but pltime 946 * is not. 947 */ 948 pltime = vltime; 949 } 950 ndopt_pi->nd_opt_pi_valid_time = htonl(vltime); 951 ndopt_pi->nd_opt_pi_preferred_time = htonl(pltime); 952 ndopt_pi->nd_opt_pi_reserved2 = 0; 953 ndopt_pi->nd_opt_pi_prefix = pfx->prefix; 954 955 buf += sizeof(struct nd_opt_prefix_info); 956 } 957 958#ifdef ND_OPT_ROUTE_INFO 959 for (rti = rainfo->route.next; rti != &rainfo->route; rti = rti->next) { 960 u_int8_t psize = (rti->prefixlen + 0x3f) >> 6; 961 962 ndopt_rti = (struct nd_opt_route_info *)buf; 963 ndopt_rti->nd_opt_rti_type = ND_OPT_ROUTE_INFO; 964 ndopt_rti->nd_opt_rti_len = 1 + psize; 965 ndopt_rti->nd_opt_rti_prefixlen = rti->prefixlen; 966 ndopt_rti->nd_opt_rti_flags = 0xff & rti->rtpref; 967 ndopt_rti->nd_opt_rti_lifetime = rti->ltime; 968 memcpy(ndopt_rti + 1, &rti->prefix, psize * 8); 969 buf += sizeof(struct nd_opt_route_info) + psize * 8; 970 } 971#endif 972 973 return; 974} 975 976static int 977getinet6sysctl(int code) 978{ 979 int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, 0 }; 980 int value; 981 size_t size; 982 983 mib[3] = code; 984 size = sizeof(value); 985 if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), &value, &size, NULL, 0) 986 < 0) { 987 syslog(LOG_ERR, "<%s>: failed to get ip6 sysctl(%d): %s", 988 __FUNCTION__, code, 989 strerror(errno)); 990 return(-1); 991 } 992 else 993 return(value); 994} 995