summaryrefslogtreecommitdiff
path: root/usr.sbin/rtadvd/config.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/rtadvd/config.c')
-rw-r--r--usr.sbin/rtadvd/config.c184
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);
+}