diff options
Diffstat (limited to 'usr.sbin/rtadvd/config.c')
-rw-r--r-- | usr.sbin/rtadvd/config.c | 396 |
1 files changed, 317 insertions, 79 deletions
diff --git a/usr.sbin/rtadvd/config.c b/usr.sbin/rtadvd/config.c index ec294f1..01cfb4c 100644 --- a/usr.sbin/rtadvd/config.c +++ b/usr.sbin/rtadvd/config.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: config.c,v 1.11 2000/05/16 13:34:13 itojun Exp $ */ +/* $KAME: config.c,v 1.37 2001/05/25 07:34:00 itojun Exp $ */ /* * Copyright (C) 1998 WIDE Project. @@ -34,6 +34,7 @@ #include <sys/ioctl.h> #include <sys/socket.h> #include <sys/time.h> +#include <sys/sysctl.h> #include <net/if.h> #if defined(__FreeBSD__) && __FreeBSD__ >= 3 @@ -62,6 +63,7 @@ #include <search.h> #endif #include <unistd.h> +#include <ifaddrs.h> #include "rtadvd.h" #include "advcap.h" @@ -71,6 +73,7 @@ static void makeentry __P((char *, int, char *, int)); static void get_prefix __P((struct rainfo *)); +static int getinet6sysctl __P((int)); extern struct rainfo *ralist; @@ -82,9 +85,11 @@ getconfig(intface) char tbuf[BUFSIZ]; struct rainfo *tmp; long val; + long long val64; char buf[BUFSIZ]; char *bp = buf; char *addr; + static int forwarding = -1; #define MUSTHAVE(var, cap) \ do { \ @@ -114,6 +119,13 @@ getconfig(intface) tmp = (struct rainfo *)malloc(sizeof(*ralist)); memset(tmp, 0, sizeof(*tmp)); tmp->prefix.next = tmp->prefix.prev = &tmp->prefix; + tmp->route.next = tmp->route.prev = &tmp->route; + + /* check if we are allowed to forward packets (if not determined) */ + if (forwarding < 0) { + if ((forwarding = getinet6sysctl(IPV6CTL_FORWARDING)) < 0) + exit(1); + } /* get interface information */ if (agetflag("nolladdr")) @@ -164,12 +176,22 @@ getconfig(intface) tmp->hoplimit = val & 0xff; MAYHAVE(val, "raflags", 0); - tmp->managedflg= val & ND_RA_FLAG_MANAGED; + tmp->managedflg = val & ND_RA_FLAG_MANAGED; tmp->otherflg = val & ND_RA_FLAG_OTHER; #ifdef MIP6 if (mobileip6) tmp->haflg = val & ND_RA_FLAG_HA; #endif +#ifndef ND_RA_FLAG_RTPREF_MASK +#define ND_RA_FLAG_RTPREF_MASK 0x18 /* 00011000 */ +#define ND_RA_FLAG_RTPREF_RSV 0x10 /* 00010000 */ +#endif + tmp->rtpref = val & ND_RA_FLAG_RTPREF_MASK; + if (tmp->rtpref == ND_RA_FLAG_RTPREF_RSV) { + syslog(LOG_ERR, "<%s> invalid router preference on %s", + __FUNCTION__, intface); + exit(1); + } MAYHAVE(val, "rltime", tmp->maxinterval * 3); if (val && (val < tmp->maxinterval || val > MAXROUTERLIFETIME)) { @@ -180,6 +202,21 @@ getconfig(intface) tmp->maxinterval, MAXROUTERLIFETIME); exit(1); } + /* + * Basically, hosts MUST NOT send Router Advertisement messages at any + * time (RFC 2461, Section 6.2.3). However, it would sometimes be + * useful to allow hosts to advertise some parameters such as prefix + * information and link MTU. Thus, we allow hosts to invoke rtadvd + * only when router lifetime (on every advertising interface) is + * explicitly set zero. (see also the above section) + */ + if (val && forwarding == 0) { + syslog(LOG_WARNING, + "<%s> non zero router lifetime is specified for %s, " + "which must not be allowed for hosts.", + __FUNCTION__, intface); + exit(1); + } tmp->lifetime = val & 0xffff; MAYHAVE(val, "rtime", DEF_ADVREACHABLETIME); @@ -191,20 +228,23 @@ getconfig(intface) } tmp->reachabletime = (u_int32_t)val; - MAYHAVE(val, "retrans", DEF_ADVRETRANSTIMER); - if (val < 0 || val > 0xffffffff) { + MAYHAVE(val64, "retrans", DEF_ADVRETRANSTIMER); + if (val64 < 0 || val64 > 0xffffffff) { syslog(LOG_ERR, "<%s> retrans time out of range", __FUNCTION__); exit(1); } - tmp->retranstimer = (u_int32_t)val; + tmp->retranstimer = (u_int32_t)val64; -#ifdef MIP6 - if (!mobileip6) +#ifndef MIP6 + if (agetstr("hapref", &bp) || agetstr("hatime", &bp)) { + syslog(LOG_ERR, + "<%s> mobile-ip6 configuration not supported", + __FUNCTION__); + exit(1); + } #else - if (1) -#endif - { + if (!mobileip6) { if (agetstr("hapref", &bp) || agetstr("hatime", &bp)) { syslog(LOG_ERR, "<%s> mobile-ip6 configuration without " @@ -212,9 +252,7 @@ getconfig(intface) __FUNCTION__); exit(1); } - } -#ifdef MIP6 - else { + } else { tmp->hapref = 0; if ((val = agetnum("hapref")) >= 0) tmp->hapref = (int16_t)val; @@ -233,6 +271,15 @@ getconfig(intface) #endif /* prefix information */ + + /* + * This is an implementation specific parameter to consinder + * link propagation delays and poorly synchronized clocks when + * checking consistency of advertised lifetimes. + */ + MAYHAVE(val, "clockskew", 0); + tmp->clockskew = val; + if ((pfxs = agetnum("addrs")) < 0) { /* auto configure prefix information */ if (agetstr("addr", &bp) || agetstr("addr1", &bp)) { @@ -281,7 +328,7 @@ getconfig(intface) { MAYHAVE(val, entbuf, (ND_OPT_PI_FLAG_ONLINK|ND_OPT_PI_FLAG_AUTO| - ND_OPT_PI_FLAG_RTADDR)); + ND_OPT_PI_FLAG_ROUTER)); } else #endif { @@ -291,29 +338,44 @@ getconfig(intface) pfx->onlinkflg = val & ND_OPT_PI_FLAG_ONLINK; pfx->autoconfflg = val & ND_OPT_PI_FLAG_AUTO; #ifdef MIP6 - if (mobileip6) - pfx->routeraddr = val & ND_OPT_PI_FLAG_RTADDR; + pfx->routeraddr = val & ND_OPT_PI_FLAG_ROUTER; #endif makeentry(entbuf, i, "vltime", added); - MAYHAVE(val, entbuf, DEF_ADVVALIDLIFETIME); - if (val < 0 || val > 0xffffffff) { + MAYHAVE(val64, entbuf, DEF_ADVVALIDLIFETIME); + if (val64 < 0 || val64 > 0xffffffff) { syslog(LOG_ERR, "<%s> vltime out of range", __FUNCTION__); exit(1); } - pfx->validlifetime = (u_int32_t)val; + pfx->validlifetime = (u_int32_t)val64; + + makeentry(entbuf, i, "vltimedecr", added); + if (agetflag(entbuf)) { + struct timeval now; + gettimeofday(&now, 0); + pfx->vltimeexpire = + now.tv_sec + pfx->validlifetime; + } makeentry(entbuf, i, "pltime", added); - MAYHAVE(val, entbuf, DEF_ADVPREFERREDLIFETIME); - if (val < 0 || val > 0xffffffff) { + MAYHAVE(val64, entbuf, DEF_ADVPREFERREDLIFETIME); + if (val64 < 0 || val64 > 0xffffffff) { syslog(LOG_ERR, "<%s> pltime out of range", __FUNCTION__); exit(1); } - pfx->preflifetime = (u_int32_t)val; + pfx->preflifetime = (u_int32_t)val64; + + makeentry(entbuf, i, "pltimedecr", added); + if (agetflag(entbuf)) { + struct timeval now; + gettimeofday(&now, 0); + pfx->pltimeexpire = + now.tv_sec + pfx->preflifetime; + } makeentry(entbuf, i, "addr", added); addr = (char *)agetstr(entbuf, &bp); @@ -368,6 +430,106 @@ getconfig(intface) exit(1); } + /* route information */ + + MAYHAVE(val, "routes", 0); + if (val < 0 || val > 0xffffffff) { + syslog(LOG_ERR, + "<%s> number of route information improper", __FUNCTION__); + exit(1); + } + tmp->routes = val; + for (i = 0; i < tmp->routes; i++) { + struct rtinfo *rti; + char entbuf[256]; + int added = (tmp->routes > 1) ? 1 : 0; + + /* allocate memory to store prefix information */ + if ((rti = malloc(sizeof(struct rtinfo))) == NULL) { + syslog(LOG_ERR, + "<%s> can't allocate enough memory", + __FUNCTION__); + exit(1); + } + memset(rti, 0, sizeof(*rti)); + + /* link into chain */ + insque(rti, &tmp->route); + + makeentry(entbuf, i, "rtrplen", added); + MAYHAVE(val, entbuf, 64); + if (val < 0 || val > 128) { + syslog(LOG_ERR, + "<%s> prefixlen out of range", + __FUNCTION__); + exit(1); + } + rti->prefixlen = (int)val; + + makeentry(entbuf, i, "rtrflags", added); + MAYHAVE(val, entbuf, 0); + rti->rtpref = val & ND_RA_FLAG_RTPREF_MASK; + if (rti->rtpref == ND_RA_FLAG_RTPREF_RSV) { + syslog(LOG_ERR, "<%s> invalid router preference", + __FUNCTION__); + exit(1); + } + + makeentry(entbuf, i, "rtrltime", added); + /* + * XXX: since default value of route lifetime is not defined in + * draft-draves-route-selection-01.txt, I took the default + * value of valid lifetime of prefix as its default. + * It need be much considered. + */ + MAYHAVE(val64, entbuf, DEF_ADVVALIDLIFETIME); + if (val64 < 0 || val64 > 0xffffffff) { + syslog(LOG_ERR, + "<%s> rtrltime out of range", + __FUNCTION__); + exit(1); + } + rti->ltime = (u_int32_t)val64; + + makeentry(entbuf, i, "rtrprefix", added); + addr = (char *)agetstr(entbuf, &bp); + if (addr == NULL) { + syslog(LOG_ERR, + "<%s> need %s as an route for " + "interface %s", + __FUNCTION__, entbuf, intface); + exit(1); + } + if (inet_pton(AF_INET6, addr, &rti->prefix) != 1) { + syslog(LOG_ERR, + "<%s> inet_pton failed for %s", + __FUNCTION__, addr); + exit(1); + } +#if 0 + /* + * XXX: currently there's no restriction in route information + * prefix according to draft-draves-route-selection-01.txt, + * however I think the similar restriction be necessary. + */ + MAYHAVE(val64, entbuf, DEF_ADVVALIDLIFETIME); + if (IN6_IS_ADDR_MULTICAST(&rti->prefix)) { + syslog(LOG_ERR, + "<%s> multicast route (%s) must " + "not be advertised (IF=%s)", + __FUNCTION__, addr, intface); + exit(1); + } + if (IN6_IS_ADDR_LINKLOCAL(&rti->prefix)) { + syslog(LOG_NOTICE, + "<%s> link-local route (%s) must " + "not be advertised on %s", + __FUNCTION__, addr, intface); + exit(1); + } +#endif + } + /* okey */ tmp->next = ralist; ralist = tmp; @@ -385,33 +547,26 @@ getconfig(intface) static void get_prefix(struct rainfo *rai) { - size_t len; - u_char *buf, *lim, *next; + struct ifaddrs *ifap, *ifa; + struct prefix *pp; + struct in6_addr *a; + u_char *p, *ep, *m, *lim; u_char ntopbuf[INET6_ADDRSTRLEN]; - if ((len = rtbuf_len()) < 0) { + if (getifaddrs(&ifap) < 0) { syslog(LOG_ERR, - "<%s> can't get buffer length for routing info", + "<%s> can't get interface addresses", __FUNCTION__); exit(1); } - if ((buf = malloc(len)) == NULL) { - syslog(LOG_ERR, - "<%s> can't allocate buffer", __FUNCTION__); - exit(1); - } - if (get_rtinfo(buf, &len) < 0) { - syslog(LOG_ERR, - "<%s> can't get routing inforamtion", __FUNCTION__); - exit(1); - } - - lim = buf + len; - next = get_next_msg(buf, lim, rai->ifindex, &len, - RTADV_TYPE2BITMASK(RTM_GET)); - while (next < lim) { - struct prefix *pp; - struct in6_addr *a; + for (ifa = ifap; ifa; ifa = ifa->ifa_next) { + if (strcmp(ifa->ifa_name, rai->ifname) != 0) + continue; + if (ifa->ifa_addr->sa_family != AF_INET6) + continue; + a = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr; + if (IN6_IS_ADDR_LINKLOCAL(a)) + continue; /* allocate memory to store prefix info. */ if ((pp = malloc(sizeof(*pp))) == NULL) { @@ -422,21 +577,35 @@ get_prefix(struct rainfo *rai) } memset(pp, 0, sizeof(*pp)); - /* set prefix and its length */ - a = get_addr(next); - memcpy(&pp->prefix, a, sizeof(*a)); - if ((pp->prefixlen = get_prefixlen(next)) < 0) { + /* set prefix length */ + m = (u_char *)&((struct sockaddr_in6 *)ifa->ifa_netmask)->sin6_addr; + lim = (u_char *)(ifa->ifa_netmask) + ifa->ifa_netmask->sa_len; + pp->prefixlen = prefixlen(m, lim); + if (pp->prefixlen < 0 || pp->prefixlen > 128) { syslog(LOG_ERR, "<%s> failed to get prefixlen " - "or prefixl is invalid", + "or prefix is invalid", __FUNCTION__); exit(1); } + + /* set prefix, sweep bits outside of prefixlen */ + memcpy(&pp->prefix, a, sizeof(*a)); + p = (u_char *)&pp->prefix; + ep = (u_char *)(&pp->prefix + 1); + while (m < lim) + *p++ &= *m++; + while (p < ep) + *p++ = 0x00; + + if (!inet_ntop(AF_INET6, &pp->prefix, ntopbuf, + sizeof(ntopbuf))) { + syslog(LOG_ERR, "<%s> inet_ntop failed", __FUNCTION__); + exit(1); + } syslog(LOG_DEBUG, "<%s> add %s/%d to prefix list on %s", - __FUNCTION__, - inet_ntop(AF_INET6, a, ntopbuf, INET6_ADDRSTRLEN), - pp->prefixlen, rai->ifname); + __FUNCTION__, ntopbuf, pp->prefixlen, rai->ifname); /* set other fields with protocol defaults */ pp->validlifetime = DEF_ADVVALIDLIFETIME; @@ -450,14 +619,9 @@ get_prefix(struct rainfo *rai) /* counter increment */ rai->pfxs++; - - /* forward pointer and get next prefix(if any) */ - next += len; - next = get_next_msg(next, lim, rai->ifindex, - &len, RTADV_TYPE2BITMASK(RTM_GET)); } - free(buf); + freeifaddrs(ifap); } static void @@ -493,6 +657,7 @@ add_prefix(struct rainfo *rai, struct in6_prefixreq *ipr) __FUNCTION__); return; /* XXX: error or exit? */ } + memset(prefix, 0, sizeof(*prefix)); prefix->prefix = ipr->ipr_prefix.sin6_addr; prefix->prefixlen = ipr->ipr_plen; prefix->validlifetime = ipr->ipr_vltime; @@ -510,7 +675,7 @@ add_prefix(struct rainfo *rai, struct in6_prefixreq *ipr) /* free the previous packet */ free(rai->ra_data); - rai->ra_data = 0; + rai->ra_data = NULL; /* reconstruct the packet */ rai->pfxs++; @@ -617,10 +782,12 @@ make_packet(struct rainfo *rainfo) struct nd_opt_prefix_info *ndopt_pi; struct nd_opt_mtu *ndopt_mtu; #ifdef MIP6 - struct nd_opt_advint *ndopt_advint; - struct nd_opt_hai *ndopt_hai; + struct nd_opt_advinterval *ndopt_advint; + struct nd_opt_homeagent_info *ndopt_hai; #endif + struct nd_opt_route_info *ndopt_rti; struct prefix *pfx; + struct rtinfo *rti; /* calculate total length */ packlen = sizeof(struct nd_router_advert); @@ -641,9 +808,14 @@ make_packet(struct rainfo *rainfo) packlen += sizeof(struct nd_opt_mtu); #ifdef MIP6 if (mobileip6 && rainfo->maxinterval) - packlen += sizeof(struct nd_opt_advint); + packlen += sizeof(struct nd_opt_advinterval); if (mobileip6 && rainfo->hatime) - packlen += sizeof(struct nd_opt_hai); + packlen += sizeof(struct nd_opt_homeagent_info); +#endif +#ifdef ND_OPT_ROUTE_INFO + for (rti = rainfo->route.next; rti != &rainfo->route; rti = rti->next) + packlen += sizeof(struct nd_opt_route_info) + + ((rti->prefixlen + 0x3f) >> 6) * 8; #endif /* allocate memory for the packet */ @@ -653,6 +825,11 @@ make_packet(struct rainfo *rainfo) __FUNCTION__); exit(1); } + if (rainfo->ra_data) { + /* free the previous packet */ + free(rainfo->ra_data); + rainfo->ra_data = NULL; + } rainfo->ra_data = buf; /* XXX: what if packlen > 576? */ rainfo->ra_datalen = packlen; @@ -665,7 +842,12 @@ make_packet(struct rainfo *rainfo) ra->nd_ra_code = 0; ra->nd_ra_cksum = 0; ra->nd_ra_curhoplimit = (u_int8_t)(0xff & rainfo->hoplimit); - ra->nd_ra_flags_reserved = 0; + ra->nd_ra_flags_reserved = 0; /* just in case */ + /* + * XXX: the router preference field, which is a 2-bit field, should be + * initialized before other fields. + */ + ra->nd_ra_flags_reserved = 0xff & rainfo->rtpref; ra->nd_ra_flags_reserved |= rainfo->managedflg ? ND_RA_FLAG_MANAGED : 0; ra->nd_ra_flags_reserved |= @@ -689,36 +871,39 @@ make_packet(struct rainfo *rainfo) ndopt_mtu->nd_opt_mtu_type = ND_OPT_MTU; ndopt_mtu->nd_opt_mtu_len = 1; ndopt_mtu->nd_opt_mtu_reserved = 0; - ndopt_mtu->nd_opt_mtu_mtu = ntohl(rainfo->linkmtu); + ndopt_mtu->nd_opt_mtu_mtu = htonl(rainfo->linkmtu); buf += sizeof(struct nd_opt_mtu); } #ifdef MIP6 if (mobileip6 && rainfo->maxinterval) { - ndopt_advint = (struct nd_opt_advint *)buf; - ndopt_advint->nd_opt_int_type = ND_OPT_ADV_INTERVAL; - ndopt_advint->nd_opt_int_len = 1; - ndopt_advint->nd_opt_int_reserved = 0; - ndopt_advint->nd_opt_int_interval = ntohl(rainfo->maxinterval * + ndopt_advint = (struct nd_opt_advinterval *)buf; + ndopt_advint->nd_opt_adv_type = ND_OPT_ADVINTERVAL; + ndopt_advint->nd_opt_adv_len = 1; + ndopt_advint->nd_opt_adv_reserved = 0; + ndopt_advint->nd_opt_adv_interval = htonl(rainfo->maxinterval * 1000); - buf += sizeof(struct nd_opt_advint); + buf += sizeof(struct nd_opt_advinterval); } #endif #ifdef MIP6 if (rainfo->hatime) { - ndopt_hai = (struct nd_opt_hai *)buf; - ndopt_hai->nd_opt_hai_type = ND_OPT_HA_INFORMATION; + ndopt_hai = (struct nd_opt_homeagent_info *)buf; + ndopt_hai->nd_opt_hai_type = ND_OPT_HOMEAGENT_INFO; ndopt_hai->nd_opt_hai_len = 1; ndopt_hai->nd_opt_hai_reserved = 0; - ndopt_hai->nd_opt_hai_pref = ntohs(rainfo->hapref); - ndopt_hai->nd_opt_hai_lifetime = ntohs(rainfo->hatime); - buf += sizeof(struct nd_opt_hai); + ndopt_hai->nd_opt_hai_preference = htons(rainfo->hapref); + ndopt_hai->nd_opt_hai_lifetime = htons(rainfo->hatime); + buf += sizeof(struct nd_opt_homeagent_info); } #endif for (pfx = rainfo->prefix.next; pfx != &rainfo->prefix; pfx = pfx->next) { + u_int32_t vltime, pltime; + struct timeval now; + ndopt_pi = (struct nd_opt_prefix_info *)buf; ndopt_pi->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION; ndopt_pi->nd_opt_pi_len = 4; @@ -733,16 +918,69 @@ make_packet(struct rainfo *rainfo) #ifdef MIP6 if (pfx->routeraddr) ndopt_pi->nd_opt_pi_flags_reserved |= - ND_OPT_PI_FLAG_RTADDR; + ND_OPT_PI_FLAG_ROUTER; #endif - ndopt_pi->nd_opt_pi_valid_time = ntohl(pfx->validlifetime); - ndopt_pi->nd_opt_pi_preferred_time = - ntohl(pfx->preflifetime); + if (pfx->vltimeexpire || pfx->pltimeexpire) + gettimeofday(&now, NULL); + if (pfx->vltimeexpire == 0) + vltime = pfx->validlifetime; + else + vltime = (pfx->vltimeexpire > now.tv_sec) ? + pfx->vltimeexpire - now.tv_sec : 0; + if (pfx->pltimeexpire == 0) + pltime = pfx->preflifetime; + else + pltime = (pfx->pltimeexpire > now.tv_sec) ? + pfx->pltimeexpire - now.tv_sec : 0; + if (vltime < pltime) { + /* + * this can happen if vltime is decrement but pltime + * is not. + */ + pltime = vltime; + } + ndopt_pi->nd_opt_pi_valid_time = htonl(vltime); + ndopt_pi->nd_opt_pi_preferred_time = htonl(pltime); ndopt_pi->nd_opt_pi_reserved2 = 0; ndopt_pi->nd_opt_pi_prefix = pfx->prefix; buf += sizeof(struct nd_opt_prefix_info); } +#ifdef ND_OPT_ROUTE_INFO + for (rti = rainfo->route.next; rti != &rainfo->route; rti = rti->next) { + u_int8_t psize = (rti->prefixlen + 0x3f) >> 6; + + ndopt_rti = (struct nd_opt_route_info *)buf; + ndopt_rti->nd_opt_rti_type = ND_OPT_ROUTE_INFO; + ndopt_rti->nd_opt_rti_len = 1 + psize; + ndopt_rti->nd_opt_rti_prefixlen = rti->prefixlen; + ndopt_rti->nd_opt_rti_flags = 0xff & rti->rtpref; + ndopt_rti->nd_opt_rti_lifetime = rti->ltime; + memcpy(ndopt_rti + 1, &rti->prefix, psize * 8); + buf += sizeof(struct nd_opt_route_info) + psize * 8; + } +#endif + return; } + +static int +getinet6sysctl(int code) +{ + int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, 0 }; + int value; + size_t size; + + mib[3] = code; + size = sizeof(value); + if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), &value, &size, NULL, 0) + < 0) { + syslog(LOG_ERR, "<%s>: failed to get ip6 sysctl(%d): %s", + __FUNCTION__, code, + strerror(errno)); + return(-1); + } + else + return(value); +} |