summaryrefslogtreecommitdiffstats
path: root/usr.sbin
diff options
context:
space:
mode:
authorhrs <hrs@FreeBSD.org>2011-05-31 12:03:34 +0000
committerhrs <hrs@FreeBSD.org>2011-05-31 12:03:34 +0000
commit44b307b34139603f9baa4ad13e4eae27fe63922c (patch)
tree18d951d169905aadb88b8d998982a90c19a68f42 /usr.sbin
parent2372ea4b0ee69274bf13e43935835f106be6238a (diff)
downloadFreeBSD-src-44b307b34139603f9baa4ad13e4eae27fe63922c.zip
FreeBSD-src-44b307b34139603f9baa4ad13e4eae27fe63922c.tar.gz
- Implement RA option expiration based on the lifetime field.
- Add option length check described in RFC 6106 Section 5.3.1.
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/rtsold/rtsol.c42
-rw-r--r--usr.sbin/rtsold/rtsold.c36
-rw-r--r--usr.sbin/rtsold/rtsold.h1
3 files changed, 67 insertions, 12 deletions
diff --git a/usr.sbin/rtsold/rtsol.c b/usr.sbin/rtsold/rtsol.c
index 02659c8..79582c8 100644
--- a/usr.sbin/rtsold/rtsol.c
+++ b/usr.sbin/rtsold/rtsol.c
@@ -83,7 +83,6 @@ static const struct sockaddr_in6 sin6_allrouters = {
static void call_script(const int, const char *const *, void *);
static size_t dname_labeldec(char *, const char *);
static int safefile(const char *);
-static int ra_opt_handler(struct ifinfo *);
#define _ARGS_OTHER otherconf_script, ifi->ifname
#define _ARGS_RESADD resolvconf_script, "-a", ifi->ifname
@@ -244,10 +243,7 @@ rtsol_input(int s)
struct nd_opt_rdnss *rdnss;
struct nd_opt_dnssl *dnssl;
size_t len;
- char nsbuf[11 + INET6_ADDRSTRLEN + 1 + IFNAMSIZ + 1 + 1];
- /* 11 = sizeof("nameserver "), 1+1 = \n\0 termination */
- char slbuf[7 + NI_MAXHOST + 1 + 1];
- /* 7 = sizeof("search "), 1+1 = \n\0 termination */
+ char nsbuf[INET6_ADDRSTRLEN + 1 + IFNAMSIZ + 1 + 1];
char dname[NI_MAXHOST + 1];
struct timeval now;
struct timeval lifetime;
@@ -400,6 +396,16 @@ rtsol_input(int s)
case ND_OPT_RDNSS:
rdnss = (struct nd_opt_rdnss *)raoptp;
+ /* Optlen sanity check (Section 5.3.1 in RFC 6106) */
+ if (rdnss->nd_opt_rdnss_len < 3) {
+ warnmsg(LOG_INFO, __func__,
+ "too short RDNSS option"
+ "in RA from %s was ignored.",
+ inet_ntop(AF_INET6, &from.sin6_addr,
+ ntopbuf, INET6_ADDRSTRLEN));
+ break;
+ }
+
addr = (struct in6_addr *)(raoptp + sizeof(*rdnss));
while ((char *)addr < (char *)RA_OPT_NEXT_HDR(raoptp)) {
if (inet_ntop(AF_INET6, addr, ntopbuf,
@@ -447,16 +453,25 @@ rtsol_input(int s)
case ND_OPT_DNSSL:
dnssl = (struct nd_opt_dnssl *)raoptp;
+ /* Optlen sanity check (Section 5.3.1 in RFC 6106) */
+ if (dnssl->nd_opt_dnssl_len < 2) {
+ warnmsg(LOG_INFO, __func__,
+ "too short DNSSL option"
+ "in RA from %s was ignored.",
+ inet_ntop(AF_INET6, &from.sin6_addr,
+ ntopbuf, INET6_ADDRSTRLEN));
+ break;
+ }
+
p = raoptp + sizeof(*dnssl);
while (0 < (len = dname_labeldec(dname, p))) {
- sprintf(slbuf, "%s ", dname);
- warnmsg(LOG_DEBUG, __func__, "slbuf = %s",
- slbuf);
+ warnmsg(LOG_DEBUG, __func__, "dname = %s",
+ dname);
ELM_MALLOC(rao, break);
rao->rao_type = ndo->nd_opt_type;
- rao->rao_len = strlen(nsbuf);
- rao->rao_msg = strdup(slbuf);
+ rao->rao_len = strlen(dname);
+ rao->rao_msg = strdup(dname);
if (rao->rao_msg == NULL) {
warnmsg(LOG_ERR, __func__,
"strdup failed: %s",
@@ -498,8 +513,9 @@ rtsol_input(int s)
static char resstr_ns_prefix[] = "nameserver ";
static char resstr_sh_prefix[] = "search ";
static char resstr_nl[] = "\n";
+static char resstr_sp[] = " ";
-static int
+int
ra_opt_handler(struct ifinfo *ifi)
{
struct ra_opt *rao;
@@ -548,6 +564,10 @@ ra_opt_handler(struct ifinfo *ifi)
ELM_MALLOC(smp, continue);
smp->sm_msg = rao->rao_msg;
TAILQ_INSERT_TAIL(&sm_dnssl_head, smp, sm_next);
+
+ ELM_MALLOC(smp, continue);
+ smp->sm_msg = resstr_sp;
+ TAILQ_INSERT_TAIL(&sm_dnssl_head, smp, sm_next);
break;
default:
break;
diff --git a/usr.sbin/rtsold/rtsold.c b/usr.sbin/rtsold/rtsold.c
index 42768b5..883b5f0 100644
--- a/usr.sbin/rtsold/rtsold.c
+++ b/usr.sbin/rtsold/rtsold.c
@@ -570,6 +570,19 @@ rtsol_check_timer(void)
"state = %d", ifi->ifname,
ifi->state);
+ /* Remove all RA options. */
+ if (!TAILQ_EMPTY(&ifi->ifi_ra_opt)) {
+ struct ra_opt *rao;
+ struct ra_opt *rao_tmp;
+
+ rao = TAILQ_FIRST(&ifi->ifi_ra_opt);
+ while (rao != NULL) {
+ rao_tmp = TAILQ_NEXT(rao, rao_next);
+ free(rao_tmp->rao_msg);
+ free(rao_tmp);
+ rao = rao_tmp;
+ }
+ }
switch (ifi->state) {
case IFS_DOWN:
case IFS_TENTATIVE:
@@ -635,8 +648,29 @@ rtsol_check_timer(void)
break;
}
rtsol_timer_update(ifi);
- }
+ } else {
+ /* Expiration check for RA options. */
+ struct ra_opt *rao;
+ struct ra_opt *rao_tmp;
+ int expire = 0;
+ TAILQ_FOREACH_SAFE(rao, &ifi->ifi_ra_opt, rao_next, rao_tmp) {
+ warnmsg(LOG_DEBUG, __func__,
+ "RA expiration timer: "
+ "type=%d, msg=%s, timer=%ld:%08ld",
+ rao->rao_type, (char *)rao->rao_msg,
+ (long)rao->rao_expire.tv_sec,
+ (long)rao->rao_expire.tv_usec);
+ if (timercmp(&now, &rao->rao_expire, >=)) {
+ warnmsg(LOG_DEBUG, __func__,
+ "RA expiration timer: expired.");
+ TAILQ_REMOVE(&ifi->ifi_ra_opt, rao, rao_next);
+ expire = 1;
+ }
+ }
+ if (expire)
+ ra_opt_handler(ifi);
+ }
if (timercmp(&ifi->expire, &rtsol_timer, <))
rtsol_timer = ifi->expire;
}
diff --git a/usr.sbin/rtsold/rtsold.h b/usr.sbin/rtsold/rtsold.h
index 8964c42..b8a0509 100644
--- a/usr.sbin/rtsold/rtsold.h
+++ b/usr.sbin/rtsold/rtsold.h
@@ -118,6 +118,7 @@ void rtsol_timer_update(struct ifinfo *);
extern void warnmsg(int, const char *, const char *, ...)
__attribute__((__format__(__printf__, 3, 4)));
extern char **autoifprobe(void);
+extern int ra_opt_handler(struct ifinfo *);
/* if.c */
extern int ifinit(void);
OpenPOWER on IntegriCloud