diff options
Diffstat (limited to 'usr.sbin/rtadvd/config.c')
-rw-r--r-- | usr.sbin/rtadvd/config.c | 184 |
1 files changed, 177 insertions, 7 deletions
diff --git a/usr.sbin/rtadvd/config.c b/usr.sbin/rtadvd/config.c index 6e34165f64b..51c69fb2dd3 100644 --- a/usr.sbin/rtadvd/config.c +++ b/usr.sbin/rtadvd/config.c @@ -1,5 +1,5 @@ -/* $OpenBSD: config.c,v 1.7 2000/07/06 10:14:46 itojun Exp $ */ -/* $KAME: config.c,v 1.12 2000/05/22 22:23:07 itojun Exp $ */ +/* $OpenBSD: config.c,v 1.8 2001/01/15 11:06:24 itojun Exp $ */ +/* $KAME: config.c,v 1.26 2000/12/25 12:19:27 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; @@ -85,6 +88,7 @@ getconfig(intface) char buf[BUFSIZ]; char *bp = buf; char *addr; + static int forwarding = -1; #define MUSTHAVE(var, cap) \ do { \ @@ -115,6 +119,12 @@ getconfig(intface) memset(tmp, 0, sizeof(*tmp)); tmp->prefix.next = tmp->prefix.prev = &tmp->prefix; + /* 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")) tmp->advlinkopt = 0; @@ -180,6 +190,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); @@ -233,6 +258,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)) { @@ -303,6 +337,14 @@ getconfig(intface) } pfx->validlifetime = (u_int32_t)val; + 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) { @@ -313,6 +355,14 @@ getconfig(intface) } pfx->preflifetime = (u_int32_t)val; + 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); if (addr == NULL) { @@ -383,6 +433,7 @@ getconfig(intface) static void get_prefix(struct rainfo *rai) { +#if 0 size_t len; u_char *buf, *lim, *next; u_char ntopbuf[INET6_ADDRSTRLEN]; @@ -426,14 +477,14 @@ get_prefix(struct rainfo *rai) if ((pp->prefixlen = get_prefixlen(next)) < 0) { syslog(LOG_ERR, "<%s> failed to get prefixlen " - "or prefixl is invalid", + "or prefix is invalid", __FUNCTION__); exit(1); } syslog(LOG_DEBUG, "<%s> add %s/%d to prefix list on %s", __FUNCTION__, - inet_ntop(AF_INET6, a, ntopbuf, INET6_ADDRSTRLEN), + inet_ntop(AF_INET6, a, ntopbuf, sizeof(ntopbuf)), pp->prefixlen, rai->ifname); /* set other fields with protocol defaults */ @@ -456,6 +507,83 @@ get_prefix(struct rainfo *rai) } free(buf); +#else + struct ifaddrs *ifap, *ifa; + struct prefix *pp; + struct in6_addr *a; + u_char *p, *ep, *m, *lim; + u_char ntopbuf[INET6_ADDRSTRLEN]; + + if (getifaddrs(&ifap) < 0) { + syslog(LOG_ERR, + "<%s> can't get interface addresses", + __FUNCTION__); + exit(1); + } + 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) { + syslog(LOG_ERR, + "<%s> can't get allocate buffer for prefix", + __FUNCTION__); + exit(1); + } + memset(pp, 0, sizeof(*pp)); + + /* 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 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__, ntopbuf, pp->prefixlen, rai->ifname); + + /* set other fields with protocol defaults */ + pp->validlifetime = DEF_ADVVALIDLIFETIME; + pp->preflifetime = DEF_ADVPREFERREDLIFETIME; + pp->onlinkflg = 1; + pp->autoconfflg = 1; + pp->origin = PREFIX_FROM_KERNEL; + + /* link into chain */ + insque(pp, &rai->prefix); + + /* counter increment */ + rai->pfxs++; + } + + freeifaddrs(ifap); +#endif } static void @@ -491,6 +619,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; @@ -717,6 +846,9 @@ make_packet(struct rainfo *rainfo) 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,9 +865,27 @@ make_packet(struct rainfo *rainfo) ndopt_pi->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_RTADDR; #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 = ntohl(vltime); + ndopt_pi->nd_opt_pi_preferred_time = ntohl(pltime); ndopt_pi->nd_opt_pi_reserved2 = 0; ndopt_pi->nd_opt_pi_prefix = pfx->prefix; @@ -744,3 +894,23 @@ make_packet(struct rainfo *rainfo) 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); +} |