diff options
author | hrs <hrs@FreeBSD.org> | 2011-06-06 03:06:43 +0000 |
---|---|---|
committer | hrs <hrs@FreeBSD.org> | 2011-06-06 03:06:43 +0000 |
commit | 10df0af5a54c03a258caf94e9931b16eec080d79 (patch) | |
tree | 7fcbcd5609e82351ec883059d7bfb466d7cb8ef6 /usr.sbin/rtadvd | |
parent | acbda2ccc11fcdfe5fa5175c97ac29b4bb729bb5 (diff) | |
download | FreeBSD-src-10df0af5a54c03a258caf94e9931b16eec080d79.zip FreeBSD-src-10df0af5a54c03a258caf94e9931b16eec080d79.tar.gz |
- Implement RDNSS and DNSSL options (RFC 6106, IPv6 Router Advertisement
Options for DNS Configuration) into rtadvd(8) and rtsold(8). DNS
information received by rtsold(8) will go to resolv.conf(5) by
resolvconf(8) script. This is based on work by J.R. Oldroyd (kern/156259)
but revised extensively[1].
- rtadvd(8) now supports "noifprefix" to disable gathering on-link prefixes
from interfaces when no "addr" is specified[2]. An entry in rtadvd.conf
with "noifprefix" + no "addr" generates an RA message with no prefix
information option.
- rtadvd(8) now supports RTM_IFANNOUNCE message to fix crashes when an
interface is added or removed.
- Correct bogus ND_OPT_ROUTE_INFO value to one in RFC 4191.
Reviewed by: bz[1]
PR: kern/156259 [1]
PR: bin/152458 [2]
Diffstat (limited to 'usr.sbin/rtadvd')
-rw-r--r-- | usr.sbin/rtadvd/Makefile | 2 | ||||
-rw-r--r-- | usr.sbin/rtadvd/advcap.c | 50 | ||||
-rw-r--r-- | usr.sbin/rtadvd/config.c | 1020 | ||||
-rw-r--r-- | usr.sbin/rtadvd/config.h | 9 | ||||
-rw-r--r-- | usr.sbin/rtadvd/dump.c | 217 | ||||
-rw-r--r-- | usr.sbin/rtadvd/dump.h | 6 | ||||
-rw-r--r-- | usr.sbin/rtadvd/if.c | 113 | ||||
-rw-r--r-- | usr.sbin/rtadvd/if.h | 4 | ||||
-rw-r--r-- | usr.sbin/rtadvd/pathnames.h | 5 | ||||
-rw-r--r-- | usr.sbin/rtadvd/rrenum.c | 192 | ||||
-rw-r--r-- | usr.sbin/rtadvd/rrenum.h | 4 | ||||
-rw-r--r-- | usr.sbin/rtadvd/rtadvd.8 | 35 | ||||
-rw-r--r-- | usr.sbin/rtadvd/rtadvd.c | 1284 | ||||
-rw-r--r-- | usr.sbin/rtadvd/rtadvd.conf | 3 | ||||
-rw-r--r-- | usr.sbin/rtadvd/rtadvd.conf.5 | 111 | ||||
-rw-r--r-- | usr.sbin/rtadvd/rtadvd.h | 226 | ||||
-rw-r--r-- | usr.sbin/rtadvd/timer.c | 120 | ||||
-rw-r--r-- | usr.sbin/rtadvd/timer.h | 61 |
18 files changed, 2067 insertions, 1395 deletions
diff --git a/usr.sbin/rtadvd/Makefile b/usr.sbin/rtadvd/Makefile index 9dbfc99..e34aa3c 100644 --- a/usr.sbin/rtadvd/Makefile +++ b/usr.sbin/rtadvd/Makefile @@ -23,6 +23,6 @@ LDADD= -lutil CFLAGS+= -DHAVE_ARC4RANDOM -DHAVE_POLL_H -DROUTEINFO -WARNS?= 1 +WARNS?= 6 .include <bsd.prog.mk> diff --git a/usr.sbin/rtadvd/advcap.c b/usr.sbin/rtadvd/advcap.c index 792ea27..b0f5ee0 100644 --- a/usr.sbin/rtadvd/advcap.c +++ b/usr.sbin/rtadvd/advcap.c @@ -64,8 +64,6 @@ #define V_TERM "HOST" #endif -char *RM; - /* * termcap - routines for dealing with the terminal capability data base * @@ -83,12 +81,11 @@ char *RM; static char *tbuf; static int hopcount; /* detect infinite loops in termcap, init 0 */ -static char *remotefile; - -extern char *conffile; +static const char *remotefile; +extern const char *conffile; int tgetent(char *, char *); -int getent(char *, char *, char *); +int getent(char *, char *, const char *); int tnchktc(void); int tnamatch(char *); static char *tskip(char *); @@ -103,22 +100,18 @@ static char *tdecode(char *, char **); * we just notice escaped newlines. */ int -tgetent(bp, name) - char *bp, *name; +tgetent(char *bp, char *name) { - char *cp; - - remotefile = cp = conffile ? conffile : _PATH_RTADVDCONF; - return (getent(bp, name, cp)); + return (getent(bp, name, conffile)); } int -getent(bp, name, cp) - char *bp, *name, *cp; +getent(char *bp, char *name, const char *cfile) { int c; int i = 0, cnt = 0; char ibuf[BUFSIZ]; + char *cp; int tf; tbuf = bp; @@ -130,9 +123,9 @@ getent(bp, name, cp) * use so we don't have to read the file. In this case it * has to already have the newlines crunched out. */ - if (cp && *cp) { - tf = open(RM = cp, O_RDONLY); - } + if (cfile && *cfile) + tf = open(cfile, O_RDONLY); + if (tf < 0) { syslog(LOG_INFO, "<%s> open: %s", __func__, strerror(errno)); @@ -184,7 +177,7 @@ getent(bp, name, cp) * Note that this works because of the left to right scan. */ int -tnchktc() +tnchktc(void) { char *p, *q; char tcname[16]; /* name of similar terminal */ @@ -233,8 +226,7 @@ tnchktc() * name (before the first field) stops us. */ int -tnamatch(np) - char *np; +tnamatch(char *np) { char *Np, *Bp; @@ -260,8 +252,7 @@ tnamatch(np) * into the termcap file in octal. */ static char * -tskip(bp) - char *bp; +tskip(char *bp) { int dquote; @@ -305,8 +296,7 @@ breakbreak: * Note that we handle octal numbers beginning with 0. */ int64_t -tgetnum(id) - char *id; +tgetnum(char *id) { int64_t i; int base; @@ -341,8 +331,7 @@ tgetnum(id) * not given. */ int -tgetflag(id) - char *id; +tgetflag(char *id) { char *bp = tbuf; @@ -369,8 +358,7 @@ tgetflag(id) * No checking on area overflow. */ char * -tgetstr(id, area) - char *id, **area; +tgetstr(char *id, char **area) { char *bp = tbuf; @@ -395,13 +383,11 @@ tgetstr(id, area) * string capability escapes. */ static char * -tdecode(str, area) - char *str; - char **area; +tdecode(char *str, char **area) { char *cp; int c; - char *dp; + const char *dp; int i; char term; diff --git a/usr.sbin/rtadvd/config.c b/usr.sbin/rtadvd/config.c index 5eadcc5..4c870b9 100644 --- a/usr.sbin/rtadvd/config.c +++ b/usr.sbin/rtadvd/config.c @@ -4,7 +4,7 @@ /* * Copyright (C) 1998 WIDE Project. * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -16,7 +16,7 @@ * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -34,7 +34,6 @@ #include <sys/ioctl.h> #include <sys/socket.h> #include <sys/time.h> -#include <sys/sysctl.h> #include <net/if.h> #include <net/if_var.h> @@ -53,6 +52,7 @@ #include <stdio.h> #include <syslog.h> #include <errno.h> +#include <netdb.h> #include <string.h> #include <search.h> #include <stdlib.h> @@ -65,29 +65,55 @@ #include "if.h" #include "config.h" +/* label of tcapcode + number + domain name + zero octet */ +static char entbuf[10 + 3 + NI_MAXHOST + 1]; +static char oentbuf[10 + 3 + NI_MAXHOST + 1]; +static char abuf[DNAME_LABELENC_MAXLEN]; + static time_t prefix_timo = (60 * 120); /* 2 hours. * XXX: should be configurable. */ -extern struct rainfo *ralist; static struct rtadvd_timer *prefix_timeout(void *); -static void makeentry(char *, size_t, int, char *); -static int getinet6sysctl(int); +static void makeentry(char *, size_t, int, const char *); +static size_t dname_labelenc(char *, const char *); -void -getconfig(intface) - char *intface; +/* Encode domain name label encoding in RFC 1035 Section 3.1 */ +static size_t +dname_labelenc(char *dst, const char *src) { - int stat, i; - char tbuf[BUFSIZ]; - struct rainfo *tmp; - long val; - int64_t val64; - char buf[BUFSIZ]; - char *bp = buf; - char *addr, *flagstr; - static int forwarding = -1; + char *dst_origin; + char *p; + size_t len; -#define MUSTHAVE(var, cap) \ + dst_origin = dst; + len = strlen(src); + + /* Length fields per 63 octets + '\0' (<= DNAME_LABELENC_MAXLEN) */ + memset(dst, 0, len + len / 64 + 1 + 1); + + syslog(LOG_DEBUG, "<%s> labelenc = %s", __func__, src); + while (src && (len = strlen(src)) != 0) { + /* Put a length field with 63 octet limitation first. */ + p = strchr(src, '.'); + if (p == NULL) + *dst++ = len = MIN(63, len); + else + *dst++ = len = MIN(63, p - src); + /* Copy 63 octets at most. */ + memcpy(dst, src, len); + dst += len; + if (p == NULL) /* the last label */ + break; + src = p + 1; + } + /* Always need a 0-length label at the tail. */ + *dst++ = '\0'; + + syslog(LOG_DEBUG, "<%s> labellen = %d", __func__, dst - dst_origin); + return (dst - dst_origin); +} + +#define MUSTHAVE(var, cap) \ do { \ int64_t t; \ if ((t = agetnum(cap)) < 0) { \ @@ -97,60 +123,158 @@ getconfig(intface) } \ var = t; \ } while (0) -#define MAYHAVE(var, cap, def) \ + +#define MAYHAVE(var, cap, def) \ do { \ if ((var = agetnum(cap)) < 0) \ var = def; \ } while (0) +#define ELM_MALLOC(p,error_action) \ + do { \ + p = malloc(sizeof(*p)); \ + if (p == NULL) { \ + syslog(LOG_ERR, "<%s> malloc failed: %s", \ + __func__, strerror(errno)); \ + error_action; \ + } \ + memset(p, 0, sizeof(*p)); \ + } while(0) + +int +rmconfig(int idx) +{ + struct rainfo *rai; + struct prefix *pfx; + struct soliciter *sol; + struct rdnss *rdn; + struct rdnss_addr *rdna; + struct dnssl *dns; + struct rtinfo *rti; + + rai = if_indextorainfo(idx); + if (rai == NULL) { + syslog(LOG_ERR, "<%s>: rainfo not found (idx=%d)", + __func__, idx); + return (-1); + } + + TAILQ_REMOVE(&railist, rai, rai_next); + syslog(LOG_DEBUG, "<%s>: rainfo (idx=%d) removed.", + __func__, idx); + + /* Free all of allocated memories for this entry. */ + rtadvd_remove_timer(rai->rai_timer); + + if (rai->rai_ra_data != NULL) + free(rai->rai_ra_data); + + if (rai->rai_sdl != NULL) + free(rai->rai_sdl); + + while ((pfx = TAILQ_FIRST(&rai->rai_prefix)) != NULL) { + TAILQ_REMOVE(&rai->rai_prefix, pfx, pfx_next); + free(pfx); + } + while ((sol = TAILQ_FIRST(&rai->rai_soliciter)) != NULL) { + TAILQ_REMOVE(&rai->rai_soliciter, sol, sol_next); + free(sol); + } + while ((rdn = TAILQ_FIRST(&rai->rai_rdnss)) != NULL) { + TAILQ_REMOVE(&rai->rai_rdnss, rdn, rd_next); + while ((rdna = TAILQ_FIRST(&rdn->rd_list)) != NULL) { + TAILQ_REMOVE(&rdn->rd_list, rdna, ra_next); + free(rdna); + } + free(rdn); + } + while ((dns = TAILQ_FIRST(&rai->rai_dnssl)) != NULL) { + TAILQ_REMOVE(&rai->rai_dnssl, dns, dn_next); + free(dns); + } + while ((rti = TAILQ_FIRST(&rai->rai_route)) != NULL) { + TAILQ_REMOVE(&rai->rai_route, rti, rti_next); + free(rti); + } + free(rai); + + return (0); +} + +int +getconfig(int idx) +{ + int stat, i; + char tbuf[BUFSIZ]; + struct rainfo *rai; + long val; + int64_t val64; + char buf[BUFSIZ]; + char *bp = buf; + char *addr, *flagstr; + char intface[IFNAMSIZ]; + + if (if_indextoname(idx, intface) == NULL) { + syslog(LOG_ERR, "<%s> invalid index number (%d)", + __func__, idx); + return (-1); + } + if ((stat = agetent(tbuf, intface)) <= 0) { memset(tbuf, 0, sizeof(tbuf)); syslog(LOG_INFO, - "<%s> %s isn't defined in the configuration file" - " or the configuration file doesn't exist." - " Treat it as default", - __func__, intface); + "<%s> %s isn't defined in the configuration file" + " or the configuration file doesn't exist." + " Treat it as default", + __func__, intface); } - tmp = (struct rainfo *)malloc(sizeof(*ralist)); - if (tmp == NULL) { + rai = malloc(sizeof(*rai)); + if (rai == NULL) { syslog(LOG_INFO, "<%s> %s: can't allocate enough memory", __func__, intface); exit(1); } - memset(tmp, 0, sizeof(*tmp)); - tmp->prefix.next = tmp->prefix.prev = &tmp->prefix; + memset(rai, 0, sizeof(*rai)); + TAILQ_INIT(&rai->rai_prefix); #ifdef ROUTEINFO - tmp->route.next = tmp->route.prev = &tmp->route; + TAILQ_INIT(&rai->rai_route); #endif + TAILQ_INIT(&rai->rai_rdnss); + TAILQ_INIT(&rai->rai_dnssl); + TAILQ_INIT(&rai->rai_soliciter); - /* check if we are allowed to forward packets (if not determined) */ - if (forwarding < 0) { - if ((forwarding = getinet6sysctl(IPV6CTL_FORWARDING)) < 0) - exit(1); - } + /* gather on-link prefixes from the network interfaces. */ + if (agetflag("noifprefix")) + rai->rai_advifprefix = 0; + else + rai->rai_advifprefix = 1; /* get interface information */ if (agetflag("nolladdr")) - tmp->advlinkopt = 0; + rai->rai_advlinkopt = 0; else - tmp->advlinkopt = 1; - if (tmp->advlinkopt) { - if ((tmp->sdl = if_nametosdl(intface)) == NULL) { + rai->rai_advlinkopt = 1; + if (rai->rai_advlinkopt) { + if ((rai->rai_sdl = if_nametosdl(intface)) == NULL) { syslog(LOG_ERR, - "<%s> can't get information of %s", - __func__, intface); - exit(1); + "<%s> can't get information of %s", + __func__, intface); + return (-1); } - tmp->ifindex = tmp->sdl->sdl_index; + rai->rai_ifindex = rai->rai_sdl->sdl_index; } else - tmp->ifindex = if_nametoindex(intface); - strncpy(tmp->ifname, intface, sizeof(tmp->ifname)); - if ((tmp->phymtu = if_getmtu(intface)) == 0) { - tmp->phymtu = IPV6_MMTU; + rai->rai_ifindex = if_nametoindex(intface); + strncpy(rai->rai_ifname, intface, sizeof(rai->rai_ifname)); + syslog(LOG_DEBUG, + "<%s> ifindex = %d on %s", __func__, rai->rai_ifindex, + rai->rai_ifname); + + if ((rai->rai_phymtu = if_getmtu(intface)) == 0) { + rai->rai_phymtu = IPV6_MMTU; syslog(LOG_WARNING, - "<%s> can't get interface mtu of %s. Treat as %d", - __func__, intface, IPV6_MMTU); + "<%s> can't get interface mtu of %s. Treat as %d", + __func__, intface, IPV6_MMTU); } /* @@ -159,25 +283,27 @@ getconfig(intface) MAYHAVE(val, "maxinterval", DEF_MAXRTRADVINTERVAL); if (val < MIN_MAXINTERVAL || val > MAX_MAXINTERVAL) { syslog(LOG_ERR, - "<%s> maxinterval (%ld) on %s is invalid " - "(must be between %u and %u)", __func__, val, - intface, MIN_MAXINTERVAL, MAX_MAXINTERVAL); - exit(1); + "<%s> maxinterval (%ld) on %s is invalid " + "(must be between %u and %u)", __func__, val, + intface, MIN_MAXINTERVAL, MAX_MAXINTERVAL); + return (-1); } - tmp->maxinterval = (u_int)val; - MAYHAVE(val, "mininterval", tmp->maxinterval/3); - if (val < MIN_MININTERVAL || val > (tmp->maxinterval * 3) / 4) { + rai->rai_maxinterval = (u_int)val; + + MAYHAVE(val, "mininterval", rai->rai_maxinterval/3); + if ((u_int)val < MIN_MININTERVAL || + (u_int)val > (rai->rai_maxinterval * 3) / 4) { syslog(LOG_ERR, - "<%s> mininterval (%ld) on %s is invalid " - "(must be between %d and %d)", - __func__, val, intface, MIN_MININTERVAL, - (tmp->maxinterval * 3) / 4); - exit(1); + "<%s> mininterval (%ld) on %s is invalid " + "(must be between %d and %d)", + __func__, val, intface, MIN_MININTERVAL, + (rai->rai_maxinterval * 3) / 4); + return (-1); } - tmp->mininterval = (u_int)val; + rai->rai_mininterval = (u_int)val; MAYHAVE(val, "chlim", DEF_ADVCURHOPLIMIT); - tmp->hoplimit = val & 0xff; + rai->rai_hoplimit = val & 0xff; if ((flagstr = (char *)agetstr("raflags", &bp))) { val = 0; @@ -191,77 +317,61 @@ getconfig(intface) if ((val & ND_RA_FLAG_RTPREF_HIGH)) { syslog(LOG_ERR, "<%s> the \'h\' and \'l\'" " router flags are exclusive", __func__); - exit(1); + return (-1); } val |= ND_RA_FLAG_RTPREF_LOW; } - } else { + } else MAYHAVE(val, "raflags", 0); - } - tmp->managedflg = val & ND_RA_FLAG_MANAGED; - tmp->otherflg = val & ND_RA_FLAG_OTHER; + + rai->rai_managedflg = val & ND_RA_FLAG_MANAGED; + rai->rai_otherflg = val & ND_RA_FLAG_OTHER; #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) { + rai->rai_rtpref = val & ND_RA_FLAG_RTPREF_MASK; + if (rai->rai_rtpref == ND_RA_FLAG_RTPREF_RSV) { syslog(LOG_ERR, "<%s> invalid router preference (%02x) on %s", - __func__, tmp->rtpref, intface); - exit(1); + __func__, rai->rai_rtpref, intface); + return (-1); } - MAYHAVE(val, "rltime", tmp->maxinterval * 3); - if (val && (val < tmp->maxinterval || val > MAXROUTERLIFETIME)) { + MAYHAVE(val, "rltime", rai->rai_maxinterval * 3); + if ((u_int)val && ((u_int)val < rai->rai_maxinterval || + (u_int)val > MAXROUTERLIFETIME)) { syslog(LOG_ERR, - "<%s> router lifetime (%ld) on %s is invalid " - "(must be 0 or between %d and %d)", - __func__, val, intface, - tmp->maxinterval, - MAXROUTERLIFETIME); - exit(1); + "<%s> router lifetime (%ld) on %s is invalid " + "(must be 0 or between %d and %d)", + __func__, val, intface, rai->rai_maxinterval, + MAXROUTERLIFETIME); + return (-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_ERR, - "<%s> non zero router lifetime is specified for %s, " - "which must not be allowed for hosts. you must " - "change router lifetime or enable IPv6 forwarding.", - __func__, intface); - exit(1); - } - tmp->lifetime = val & 0xffff; + rai->rai_lifetime = val & 0xffff; MAYHAVE(val, "rtime", DEF_ADVREACHABLETIME); if (val < 0 || val > MAXREACHABLETIME) { syslog(LOG_ERR, - "<%s> reachable time (%ld) on %s is invalid " - "(must be no greater than %d)", - __func__, val, intface, MAXREACHABLETIME); - exit(1); + "<%s> reachable time (%ld) on %s is invalid " + "(must be no greater than %d)", + __func__, val, intface, MAXREACHABLETIME); + return (-1); } - tmp->reachabletime = (u_int32_t)val; + rai->rai_reachabletime = (u_int32_t)val; MAYHAVE(val64, "retrans", DEF_ADVRETRANSTIMER); if (val64 < 0 || val64 > 0xffffffff) { syslog(LOG_ERR, "<%s> retrans time (%lld) on %s out of range", - __func__, (long long)val64, intface); - exit(1); + __func__, (long long)val64, intface); + return (-1); } - tmp->retranstimer = (u_int32_t)val64; + rai->rai_retranstimer = (u_int32_t)val64; if (agetnum("hapref") != -1 || agetnum("hatime") != -1) { syslog(LOG_ERR, - "<%s> mobile-ip6 configuration not supported", - __func__); - exit(1); + "<%s> mobile-ip6 configuration not supported", + __func__); + return (-1); } /* prefix information */ @@ -271,12 +381,11 @@ getconfig(intface) * checking consistency of advertised lifetimes. */ MAYHAVE(val, "clockskew", 0); - tmp->clockskew = val; + rai->rai_clockskew = val; - tmp->pfxs = 0; + rai->rai_pfxs = 0; for (i = -1; i < MAXPREFIX; i++) { struct prefix *pfx; - char entbuf[256]; makeentry(entbuf, sizeof(entbuf), i, "addr"); addr = (char *)agetstr(entbuf, &bp); @@ -284,49 +393,41 @@ getconfig(intface) continue; /* allocate memory to store prefix information */ - if ((pfx = malloc(sizeof(struct prefix))) == NULL) { - syslog(LOG_ERR, - "<%s> can't allocate enough memory", - __func__); - exit(1); - } - memset(pfx, 0, sizeof(*pfx)); + ELM_MALLOC(pfx, exit(1)); /* link into chain */ - insque(pfx, &tmp->prefix); - tmp->pfxs++; - pfx->rainfo = tmp; + TAILQ_INSERT_TAIL(&rai->rai_prefix, pfx, pfx_next); + rai->rai_pfxs++; + pfx->pfx_origin = PREFIX_FROM_CONFIG; - pfx->origin = PREFIX_FROM_CONFIG; - - if (inet_pton(AF_INET6, addr, &pfx->prefix) != 1) { + if (inet_pton(AF_INET6, addr, &pfx->pfx_prefix) != 1) { syslog(LOG_ERR, - "<%s> inet_pton failed for %s", - __func__, addr); - exit(1); + "<%s> inet_pton failed for %s", + __func__, addr); + return (-1); } - if (IN6_IS_ADDR_MULTICAST(&pfx->prefix)) { + if (IN6_IS_ADDR_MULTICAST(&pfx->pfx_prefix)) { syslog(LOG_ERR, - "<%s> multicast prefix (%s) must " - "not be advertised on %s", - __func__, addr, intface); - exit(1); + "<%s> multicast prefix (%s) must " + "not be advertised on %s", + __func__, addr, intface); + return (-1); } - if (IN6_IS_ADDR_LINKLOCAL(&pfx->prefix)) + if (IN6_IS_ADDR_LINKLOCAL(&pfx->pfx_prefix)) syslog(LOG_NOTICE, - "<%s> link-local prefix (%s) will be" - " advertised on %s", - __func__, addr, intface); + "<%s> link-local prefix (%s) will be" + " advertised on %s", + __func__, addr, intface); makeentry(entbuf, sizeof(entbuf), i, "prefixlen"); MAYHAVE(val, entbuf, 64); if (val < 0 || val > 128) { syslog(LOG_ERR, "<%s> prefixlen (%ld) for %s " - "on %s out of range", - __func__, val, addr, intface); - exit(1); + "on %s out of range", + __func__, val, addr, intface); + return (-1); } - pfx->prefixlen = (int)val; + pfx->pfx_prefixlen = (int)val; makeentry(entbuf, sizeof(entbuf), i, "pinfoflags"); if ((flagstr = (char *)agetstr(entbuf, &bp))) { @@ -339,8 +440,8 @@ getconfig(intface) MAYHAVE(val, entbuf, (ND_OPT_PI_FLAG_ONLINK|ND_OPT_PI_FLAG_AUTO)); } - pfx->onlinkflg = val & ND_OPT_PI_FLAG_ONLINK; - pfx->autoconfflg = val & ND_OPT_PI_FLAG_AUTO; + pfx->pfx_onlinkflg = val & ND_OPT_PI_FLAG_ONLINK; + pfx->pfx_autoconfflg = val & ND_OPT_PI_FLAG_AUTO; makeentry(entbuf, sizeof(entbuf), i, "vltime"); MAYHAVE(val64, entbuf, DEF_ADVVALIDLIFETIME); @@ -348,17 +449,17 @@ getconfig(intface) syslog(LOG_ERR, "<%s> vltime (%lld) for " "%s/%d on %s is out of range", __func__, (long long)val64, - addr, pfx->prefixlen, intface); - exit(1); + addr, pfx->pfx_prefixlen, intface); + return (-1); } - pfx->validlifetime = (u_int32_t)val64; + pfx->pfx_validlifetime = (u_int32_t)val64; makeentry(entbuf, sizeof(entbuf), i, "vltimedecr"); if (agetflag(entbuf)) { struct timeval now; gettimeofday(&now, 0); - pfx->vltimeexpire = - now.tv_sec + pfx->validlifetime; + pfx->pfx_vltimeexpire = + now.tv_sec + pfx->pfx_validlifetime; } makeentry(entbuf, sizeof(entbuf), i, "pltime"); @@ -368,44 +469,45 @@ getconfig(intface) "<%s> pltime (%lld) for %s/%d on %s " "is out of range", __func__, (long long)val64, - addr, pfx->prefixlen, intface); - exit(1); + addr, pfx->pfx_prefixlen, intface); + return (-1); } - pfx->preflifetime = (u_int32_t)val64; + pfx->pfx_preflifetime = (u_int32_t)val64; makeentry(entbuf, sizeof(entbuf), i, "pltimedecr"); if (agetflag(entbuf)) { struct timeval now; gettimeofday(&now, 0); - pfx->pltimeexpire = - now.tv_sec + pfx->preflifetime; + pfx->pfx_pltimeexpire = + now.tv_sec + pfx->pfx_preflifetime; } } - if (tmp->pfxs == 0) - get_prefix(tmp); + if (rai->rai_advifprefix && rai->rai_pfxs == 0) + get_prefix(rai); MAYHAVE(val, "mtu", 0); - if (val < 0 || val > 0xffffffff) { + if (val < 0 || (u_int)val > 0xffffffff) { syslog(LOG_ERR, - "<%s> mtu (%ld) on %s out of range", - __func__, val, intface); - exit(1); + "<%s> mtu (%ld) on %s out of range", + __func__, val, intface); + return (-1); } - tmp->linkmtu = (u_int32_t)val; - if (tmp->linkmtu == 0) { + rai->rai_linkmtu = (u_int32_t)val; + if (rai->rai_linkmtu == 0) { char *mtustr; if ((mtustr = (char *)agetstr("mtu", &bp)) && strcmp(mtustr, "auto") == 0) - tmp->linkmtu = tmp->phymtu; + rai->rai_linkmtu = rai->rai_phymtu; } - else if (tmp->linkmtu < IPV6_MMTU || tmp->linkmtu > tmp->phymtu) { + else if (rai->rai_linkmtu < IPV6_MMTU || + rai->rai_linkmtu > rai->rai_phymtu) { syslog(LOG_ERR, - "<%s> advertised link mtu (%lu) on %s is invalid (must " - "be between least MTU (%d) and physical link MTU (%d)", - __func__, (unsigned long)tmp->linkmtu, intface, - IPV6_MMTU, tmp->phymtu); - exit(1); + "<%s> advertised link mtu (%lu) on %s is invalid (must " + "be between least MTU (%d) and physical link MTU (%d)", + __func__, (unsigned long)rai->rai_linkmtu, intface, + IPV6_MMTU, rai->rai_phymtu); + return (-1); } #ifdef SIOCSIFINFO_IN6 @@ -415,65 +517,56 @@ getconfig(intface) if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { syslog(LOG_ERR, "<%s> socket: %s", __func__, - strerror(errno)); + strerror(errno)); exit(1); } memset(&ndi, 0, sizeof(ndi)); strncpy(ndi.ifname, intface, IFNAMSIZ); - if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&ndi) < 0) { + if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&ndi) < 0) syslog(LOG_INFO, "<%s> ioctl:SIOCGIFINFO_IN6 at %s: %s", - __func__, intface, strerror(errno)); - } + __func__, intface, strerror(errno)); /* reflect the RA info to the host variables in kernel */ - ndi.ndi.chlim = tmp->hoplimit; - ndi.ndi.retrans = tmp->retranstimer; - ndi.ndi.basereachable = tmp->reachabletime; - if (ioctl(s, SIOCSIFINFO_IN6, (caddr_t)&ndi) < 0) { + ndi.ndi.chlim = rai->rai_hoplimit; + ndi.ndi.retrans = rai->rai_retranstimer; + ndi.ndi.basereachable = rai->rai_reachabletime; + if (ioctl(s, SIOCSIFINFO_IN6, (caddr_t)&ndi) < 0) syslog(LOG_INFO, "<%s> ioctl:SIOCSIFINFO_IN6 at %s: %s", - __func__, intface, strerror(errno)); - } + __func__, intface, strerror(errno)); + close(s); } #endif /* route information */ #ifdef ROUTEINFO - tmp->routes = 0; + rai->rai_routes = 0; for (i = -1; i < MAXROUTE; i++) { struct rtinfo *rti; - char entbuf[256], oentbuf[256]; makeentry(entbuf, sizeof(entbuf), i, "rtprefix"); addr = (char *)agetstr(entbuf, &bp); if (addr == NULL) { makeentry(oentbuf, sizeof(oentbuf), i, "rtrprefix"); addr = (char *)agetstr(oentbuf, &bp); - if (addr) { + if (addr) fprintf(stderr, "%s was obsoleted. Use %s.\n", - oentbuf, entbuf); - } + oentbuf, entbuf); } if (addr == NULL) continue; /* allocate memory to store prefix information */ - if ((rti = malloc(sizeof(struct rtinfo))) == NULL) { - syslog(LOG_ERR, - "<%s> can't allocate enough memory", - __func__); - exit(1); - } - memset(rti, 0, sizeof(*rti)); + ELM_MALLOC(rti, exit(1)); /* link into chain */ - insque(rti, &tmp->route); - tmp->routes++; + TAILQ_INSERT_TAIL(&rai->rai_route, rti, rti_next); + rai->rai_routes++; - if (inet_pton(AF_INET6, addr, &rti->prefix) != 1) { + if (inet_pton(AF_INET6, addr, &rti->rti_prefix) != 1) { syslog(LOG_ERR, "<%s> inet_pton failed for %s", - __func__, addr); - exit(1); + __func__, addr); + return (-1); } #if 0 /* @@ -485,17 +578,17 @@ getconfig(intface) MAYHAVE(val64, entbuf, DEF_ADVVALIDLIFETIME); if (IN6_IS_ADDR_MULTICAST(&rti->prefix)) { syslog(LOG_ERR, - "<%s> multicast route (%s) must " - "not be advertised on %s", - __func__, addr, intface); - exit(1); + "<%s> multicast route (%s) must " + "not be advertised on %s", + __func__, addr, intface); + return (-1); } if (IN6_IS_ADDR_LINKLOCAL(&rti->prefix)) { syslog(LOG_NOTICE, - "<%s> link-local route (%s) will " - "be advertised on %s", - __func__, addr, intface); - exit(1); + "<%s> link-local route (%s) will " + "be advertised on %s", + __func__, addr, intface); + return (-1); } #endif @@ -505,19 +598,19 @@ getconfig(intface) if (val == 256) { makeentry(oentbuf, sizeof(oentbuf), i, "rtrplen"); MAYHAVE(val, oentbuf, 256); - if (val != 256) { + if (val != 256) fprintf(stderr, "%s was obsoleted. Use %s.\n", - oentbuf, entbuf); - } else + oentbuf, entbuf); + else val = 64; } if (val < 0 || val > 128) { syslog(LOG_ERR, "<%s> prefixlen (%ld) for %s on %s " - "out of range", - __func__, val, addr, intface); - exit(1); + "out of range", + __func__, val, addr, intface); + return (-1); } - rti->prefixlen = (int)val; + rti->rti_prefixlen = (int)val; makeentry(entbuf, sizeof(entbuf), i, "rtflags"); if ((flagstr = (char *)agetstr(entbuf, &bp))) { @@ -541,17 +634,17 @@ getconfig(intface) MAYHAVE(val, oentbuf, 256); if (val != 256) { fprintf(stderr, "%s was obsoleted. Use %s.\n", - oentbuf, entbuf); + oentbuf, entbuf); } else val = 0; } - rti->rtpref = val & ND_RA_FLAG_RTPREF_MASK; - if (rti->rtpref == ND_RA_FLAG_RTPREF_RSV) { + rti->rti_rtpref = val & ND_RA_FLAG_RTPREF_MASK; + if (rti->rti_rtpref == ND_RA_FLAG_RTPREF_RSV) { syslog(LOG_ERR, "<%s> invalid route preference (%02x) " - "for %s/%d on %s", - __func__, rti->rtpref, addr, - rti->prefixlen, intface); - exit(1); + "for %s/%d on %s", + __func__, rti->rti_rtpref, addr, + rti->rti_prefixlen, intface); + return (-1); } /* @@ -565,60 +658,143 @@ getconfig(intface) if (val64 == -1) { makeentry(oentbuf, sizeof(oentbuf), i, "rtrltime"); MAYHAVE(val64, oentbuf, -1); - if (val64 != -1) { + if (val64 != -1) fprintf(stderr, "%s was obsoleted. Use %s.\n", - oentbuf, entbuf); - } else { + oentbuf, entbuf); + else { fprintf(stderr, "%s should be specified " - "for interface %s.\n", - entbuf, intface); - val64 = tmp->lifetime; + "for interface %s.\n", entbuf, intface); + val64 = rai->rai_lifetime; } } if (val64 < 0 || val64 > 0xffffffff) { syslog(LOG_ERR, "<%s> route lifetime (%lld) for " "%s/%d on %s out of range", __func__, - (long long)val64, addr, rti->prefixlen, intface); - exit(1); + (long long)val64, addr, rti->rti_prefixlen, intface); + return (-1); } - rti->ltime = (u_int32_t)val64; + rti->rti_ltime = (u_int32_t)val64; } #endif + /* DNS server and DNS search list information */ + for (i = -1; i < MAXRDNSSENT ; i++) { + struct rdnss *rdn; + struct rdnss_addr *rdna; + char *ap; + int c; + + makeentry(entbuf, sizeof(entbuf), i, "rdnss"); + addr = (char *)agetstr(entbuf, &bp); + if (addr == NULL) + break; + ELM_MALLOC(rdn, exit(1)); + + TAILQ_INIT(&rdn->rd_list); + + for (ap = addr; ap - addr < (ssize_t)strlen(addr); ap += c+1) { + c = strcspn(ap, ","); + strncpy(abuf, ap, c); + abuf[c] = '\0'; + ELM_MALLOC(rdna, exit(1)); + if (inet_pton(AF_INET6, abuf, &rdna->ra_dns) != 1) { + syslog(LOG_ERR, "<%s> inet_pton failed for %s", + __func__, abuf); + free(rdna); + return (-1); + } + TAILQ_INSERT_TAIL(&rdn->rd_list, rdna, ra_next); + } + + makeentry(entbuf, sizeof(entbuf), i, "rdnssltime"); + MAYHAVE(val, entbuf, (rai->rai_maxinterval * 3 / 2)); + if ((u_int)val < rai->rai_maxinterval || + (u_int)val > rai->rai_maxinterval * 2) { + syslog(LOG_ERR, "%s (%ld) on %s is invalid " + "(must be between %d and %d)", + entbuf, val, intface, rai->rai_maxinterval, + rai->rai_maxinterval * 2); + return (-1); + } + rdn->rd_ltime = val; + + /* link into chain */ + TAILQ_INSERT_TAIL(&rai->rai_rdnss, rdn, rd_next); + } + + for (i = -1; i < MAXDNSSLENT ; i++) { + struct dnssl *dns; + struct dnssl_addr *dnsa; + char *ap; + int c; - /* okey */ - tmp->next = ralist; - ralist = tmp; + makeentry(entbuf, sizeof(entbuf), i, "dnssl"); + addr = (char *)agetstr(entbuf, &bp); + if (addr == NULL) + break; + + ELM_MALLOC(dns, exit(1)); + TAILQ_INIT(&dns->dn_list); + + for (ap = addr; ap - addr < (ssize_t)strlen(addr); ap += c+1) { + c = strcspn(ap, ","); + strncpy(abuf, ap, c); + abuf[c] = '\0'; + ELM_MALLOC(dnsa, exit(1)); + dnsa->da_len = dname_labelenc(dnsa->da_dom, abuf); + syslog(LOG_DEBUG, "<%s>: dnsa->da_len = %d", __func__, + dnsa->da_len); + TAILQ_INSERT_TAIL(&dns->dn_list, dnsa, da_next); + } + + makeentry(entbuf, sizeof(entbuf), i, "dnsslltime"); + MAYHAVE(val, entbuf, (rai->rai_maxinterval * 3 / 2)); + if ((u_int)val < rai->rai_maxinterval || + (u_int)val > rai->rai_maxinterval * 2) { + syslog(LOG_ERR, "%s (%ld) on %s is invalid " + "(must be between %d and %d)", + entbuf, val, intface, rai->rai_maxinterval, + rai->rai_maxinterval * 2); + return (-1); + } + dns->dn_ltime = val; + + /* link into chain */ + TAILQ_INSERT_TAIL(&rai->rai_dnssl, dns, dn_next); + } /* construct the sending packet */ - make_packet(tmp); + make_packet(rai); + TAILQ_INSERT_TAIL(&railist, rai, rai_next); /* set timer */ - tmp->timer = rtadvd_add_timer(ra_timeout, ra_timer_update, - tmp, tmp); - ra_timer_update((void *)tmp, &tmp->timer->tm); - rtadvd_set_timer(&tmp->timer->tm, tmp->timer); + rai->rai_timer = rtadvd_add_timer(ra_timeout, ra_timer_update, + rai, rai); + ra_timer_update((void *)rai, &rai->rai_timer->rat_tm); + rtadvd_set_timer(&rai->rai_timer->rat_tm, rai->rai_timer); + + return (0); } void get_prefix(struct rainfo *rai) { struct ifaddrs *ifap, *ifa; - struct prefix *pp; + struct prefix *pfx; 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", - __func__); + "<%s> can't get interface addresses", + __func__); exit(1); } for (ifa = ifap; ifa; ifa = ifa->ifa_next) { int plen; - if (strcmp(ifa->ifa_name, rai->ifname) != 0) + if (strcmp(ifa->ifa_name, rai->rai_ifname) != 0) continue; if (ifa->ifa_addr->sa_family != AF_INET6) continue; @@ -631,8 +807,8 @@ get_prefix(struct rainfo *rai) plen = prefixlen(m, lim); if (plen <= 0 || plen > 128) { syslog(LOG_ERR, "<%s> failed to get prefixlen " - "or prefix is invalid", - __func__); + "or prefix is invalid", + __func__); exit(1); } if (plen == 128) /* XXX */ @@ -643,56 +819,46 @@ get_prefix(struct rainfo *rai) } /* allocate memory to store prefix info. */ - if ((pp = malloc(sizeof(*pp))) == NULL) { - syslog(LOG_ERR, - "<%s> can't get allocate buffer for prefix", - __func__); - exit(1); - } - memset(pp, 0, sizeof(*pp)); + ELM_MALLOC(pfx, exit(1)); /* set prefix, sweep bits outside of prefixlen */ - pp->prefixlen = plen; - memcpy(&pp->prefix, a, sizeof(*a)); - p = (u_char *)&pp->prefix; - ep = (u_char *)(&pp->prefix + 1); + pfx->pfx_prefixlen = plen; + memcpy(&pfx->pfx_prefix, a, sizeof(*a)); + p = (u_char *)&pfx->pfx_prefix; + ep = (u_char *)(&pfx->pfx_prefix + 1); while (m < lim && p < ep) *p++ &= *m++; while (p < ep) *p++ = 0x00; - if (!inet_ntop(AF_INET6, &pp->prefix, ntopbuf, + if (!inet_ntop(AF_INET6, &pfx->pfx_prefix, ntopbuf, sizeof(ntopbuf))) { syslog(LOG_ERR, "<%s> inet_ntop failed", __func__); exit(1); } syslog(LOG_DEBUG, - "<%s> add %s/%d to prefix list on %s", - __func__, ntopbuf, pp->prefixlen, rai->ifname); + "<%s> add %s/%d to prefix list on %s", + __func__, ntopbuf, pfx->pfx_prefixlen, rai->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; - pp->rainfo = rai; + pfx->pfx_validlifetime = DEF_ADVVALIDLIFETIME; + pfx->pfx_preflifetime = DEF_ADVPREFERREDLIFETIME; + pfx->pfx_onlinkflg = 1; + pfx->pfx_autoconfflg = 1; + pfx->pfx_origin = PREFIX_FROM_KERNEL; + pfx->pfx_rainfo = rai; /* link into chain */ - insque(pp, &rai->prefix); + TAILQ_INSERT_TAIL(&rai->rai_prefix, pfx, pfx_next); /* counter increment */ - rai->pfxs++; + rai->rai_pfxs++; } freeifaddrs(ifap); } static void -makeentry(buf, len, id, string) - char *buf; - size_t len; - int id; - char *string; +makeentry(char *buf, size_t len, int id, const char *string) { if (id < 0) @@ -711,37 +877,28 @@ makeentry(buf, len, id, string) static void add_prefix(struct rainfo *rai, struct in6_prefixreq *ipr) { - struct prefix *prefix; + struct prefix *pfx; u_char ntopbuf[INET6_ADDRSTRLEN]; - if ((prefix = malloc(sizeof(*prefix))) == NULL) { - syslog(LOG_ERR, "<%s> memory allocation failed", - __func__); - 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; - prefix->preflifetime = ipr->ipr_pltime; - prefix->onlinkflg = ipr->ipr_raf_onlink; - prefix->autoconfflg = ipr->ipr_raf_auto; - prefix->origin = PREFIX_FROM_DYNAMIC; - - insque(prefix, &rai->prefix); - prefix->rainfo = rai; + ELM_MALLOC(pfx, return); + pfx->pfx_prefix = ipr->ipr_prefix.sin6_addr; + pfx->pfx_prefixlen = ipr->ipr_plen; + pfx->pfx_validlifetime = ipr->ipr_vltime; + pfx->pfx_preflifetime = ipr->ipr_pltime; + pfx->pfx_onlinkflg = ipr->ipr_raf_onlink; + pfx->pfx_autoconfflg = ipr->ipr_raf_auto; + pfx->pfx_origin = PREFIX_FROM_DYNAMIC; - syslog(LOG_DEBUG, "<%s> new prefix %s/%d was added on %s", - __func__, inet_ntop(AF_INET6, &ipr->ipr_prefix.sin6_addr, - ntopbuf, INET6_ADDRSTRLEN), - ipr->ipr_plen, rai->ifname); + TAILQ_INSERT_TAIL(&rai->rai_prefix, pfx, pfx_next); + pfx->pfx_rainfo = rai; - /* free the previous packet */ - free(rai->ra_data); - rai->ra_data = NULL; + syslog(LOG_DEBUG, "<%s> new prefix %s/%d was added on %s", + __func__, + inet_ntop(AF_INET6, &ipr->ipr_prefix.sin6_addr, ntopbuf, + sizeof(ntopbuf)), ipr->ipr_plen, rai->rai_ifname); /* reconstruct the packet */ - rai->pfxs++; + rai->rai_pfxs++; make_packet(rai); } @@ -751,30 +908,33 @@ add_prefix(struct rainfo *rai, struct in6_prefixreq *ipr) * The prefix must be in the list. */ void -delete_prefix(struct prefix *prefix) +delete_prefix(struct prefix *pfx) { u_char ntopbuf[INET6_ADDRSTRLEN]; - struct rainfo *rai = prefix->rainfo; + struct rainfo *rai; - remque(prefix); + rai = pfx->pfx_rainfo; + TAILQ_REMOVE(&rai->rai_prefix, pfx, pfx_next); syslog(LOG_DEBUG, "<%s> prefix %s/%d was deleted on %s", - __func__, inet_ntop(AF_INET6, &prefix->prefix, - ntopbuf, INET6_ADDRSTRLEN), - prefix->prefixlen, rai->ifname); - if (prefix->timer) - rtadvd_remove_timer(&prefix->timer); - free(prefix); - rai->pfxs--; + __func__, + inet_ntop(AF_INET6, &pfx->pfx_prefix, ntopbuf, + sizeof(ntopbuf)), pfx->pfx_prefixlen, rai->rai_ifname); + if (pfx->pfx_timer) + rtadvd_remove_timer(pfx->pfx_timer); + free(pfx); + rai->rai_pfxs--; + make_packet(rai); } void -invalidate_prefix(struct prefix *prefix) +invalidate_prefix(struct prefix *pfx) { u_char ntopbuf[INET6_ADDRSTRLEN]; struct timeval timo; - struct rainfo *rai = prefix->rainfo; + struct rainfo *rai; - if (prefix->timer) { /* sanity check */ + rai = pfx->pfx_rainfo; + if (pfx->pfx_timer) { /* sanity check */ syslog(LOG_ERR, "<%s> assumption failure: timer already exists", __func__); @@ -783,38 +943,38 @@ invalidate_prefix(struct prefix *prefix) syslog(LOG_DEBUG, "<%s> prefix %s/%d was invalidated on %s, " "will expire in %ld seconds", __func__, - inet_ntop(AF_INET6, &prefix->prefix, ntopbuf, INET6_ADDRSTRLEN), - prefix->prefixlen, rai->ifname, (long)prefix_timo); + inet_ntop(AF_INET6, &pfx->pfx_prefix, ntopbuf, sizeof(ntopbuf)), + pfx->pfx_prefixlen, rai->rai_ifname, (long)prefix_timo); /* set the expiration timer */ - prefix->timer = rtadvd_add_timer(prefix_timeout, NULL, prefix, NULL); - if (prefix->timer == NULL) { + pfx->pfx_timer = rtadvd_add_timer(prefix_timeout, NULL, pfx, NULL); + if (pfx->pfx_timer == NULL) { syslog(LOG_ERR, "<%s> failed to add a timer for a prefix. " "remove the prefix", __func__); - delete_prefix(prefix); + delete_prefix(pfx); } timo.tv_sec = prefix_timo; timo.tv_usec = 0; - rtadvd_set_timer(&timo, prefix->timer); + rtadvd_set_timer(&timo, pfx->pfx_timer); } static struct rtadvd_timer * prefix_timeout(void *arg) { - struct prefix *prefix = (struct prefix *)arg; - - delete_prefix(prefix); - return(NULL); + delete_prefix((struct prefix *)arg); + + return (NULL); } void -update_prefix(struct prefix * prefix) +update_prefix(struct prefix *pfx) { u_char ntopbuf[INET6_ADDRSTRLEN]; - struct rainfo *rai = prefix->rainfo; + struct rainfo *rai; - if (prefix->timer == NULL) { /* sanity check */ + rai = pfx->pfx_rainfo; + if (pfx->pfx_timer == NULL) { /* sanity check */ syslog(LOG_ERR, "<%s> assumption failure: timer does not exist", __func__); @@ -822,11 +982,12 @@ update_prefix(struct prefix * prefix) } syslog(LOG_DEBUG, "<%s> prefix %s/%d was re-enabled on %s", - __func__, inet_ntop(AF_INET6, &prefix->prefix, ntopbuf, - INET6_ADDRSTRLEN), prefix->prefixlen, rai->ifname); + __func__, inet_ntop(AF_INET6, &pfx->pfx_prefix, ntopbuf, + sizeof(ntopbuf)), pfx->pfx_prefixlen, rai->rai_ifname); /* stop the expiration timer */ - rtadvd_remove_timer(&prefix->timer); + rtadvd_remove_timer(pfx->pfx_timer); + pfx->pfx_timer = NULL; } /* @@ -842,13 +1003,13 @@ init_prefix(struct in6_prefixreq *ipr) if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { syslog(LOG_ERR, "<%s> socket: %s", __func__, - strerror(errno)); + strerror(errno)); exit(1); } if (ioctl(s, SIOCGIFPREFIX_IN6, (caddr_t)ipr) < 0) { syslog(LOG_INFO, "<%s> ioctl:SIOCGIFPREFIX %s", __func__, - strerror(errno)); + strerror(errno)); ipr->ipr_vltime = DEF_ADVVALIDLIFETIME; ipr->ipr_pltime = DEF_ADVPREFERREDLIFETIME; @@ -860,22 +1021,22 @@ init_prefix(struct in6_prefixreq *ipr) u_char ntopbuf[INET6_ADDRSTRLEN]; syslog(LOG_WARNING, "<%s> Added prefix(%s)'s origin %d is" - "lower than PR_ORIG_RR(router renumbering)." - "This should not happen if I am router", __func__, - inet_ntop(AF_INET6, &ipr->ipr_prefix.sin6_addr, ntopbuf, - sizeof(ntopbuf)), ipr->ipr_origin); + "lower than PR_ORIG_RR(router renumbering)." + "This should not happen if I am router", __func__, + inet_ntop(AF_INET6, &ipr->ipr_prefix.sin6_addr, ntopbuf, + sizeof(ntopbuf)), ipr->ipr_origin); close(s); - return 1; + return (1); } close(s); - return 0; + return (0); #else ipr->ipr_vltime = DEF_ADVVALIDLIFETIME; ipr->ipr_pltime = DEF_ADVPREFERREDLIFETIME; ipr->ipr_raf_onlink = 1; ipr->ipr_raf_auto = 1; - return 0; + return (0); #endif } @@ -887,8 +1048,8 @@ make_prefix(struct rainfo *rai, int ifindex, struct in6_addr *addr, int plen) memset(&ipr, 0, sizeof(ipr)); if (if_indextoname(ifindex, ipr.ipr_name) == NULL) { syslog(LOG_ERR, "<%s> Prefix added interface No.%d doesn't" - "exist. This should not happen! %s", __func__, - ifindex, strerror(errno)); + "exist. This should not happen! %s", __func__, + ifindex, strerror(errno)); exit(1); } ipr.ipr_prefix.sin6_len = sizeof(ipr.ipr_prefix); @@ -902,7 +1063,7 @@ make_prefix(struct rainfo *rai, int ifindex, struct in6_addr *addr, int plen) } void -make_packet(struct rainfo *rainfo) +make_packet(struct rainfo *rai) { size_t packlen, lladdroptlen = 0; char *buf; @@ -913,45 +1074,68 @@ make_packet(struct rainfo *rainfo) struct nd_opt_route_info *ndopt_rti; struct rtinfo *rti; #endif + struct nd_opt_rdnss *ndopt_rdnss; + struct rdnss *rdn; + struct nd_opt_dnssl *ndopt_dnssl; + struct dnssl *dns; + size_t len; struct prefix *pfx; /* calculate total length */ packlen = sizeof(struct nd_router_advert); - if (rainfo->advlinkopt) { - if ((lladdroptlen = lladdropt_length(rainfo->sdl)) == 0) { + if (rai->rai_advlinkopt) { + if ((lladdroptlen = lladdropt_length(rai->rai_sdl)) == 0) { syslog(LOG_INFO, - "<%s> link-layer address option has" - " null length on %s. Treat as not included.", - __func__, rainfo->ifname); - rainfo->advlinkopt = 0; + "<%s> link-layer address option has" + " null length on %s. Treat as not included.", + __func__, rai->rai_ifname); + rai->rai_advlinkopt = 0; } packlen += lladdroptlen; } - if (rainfo->pfxs) - packlen += sizeof(struct nd_opt_prefix_info) * rainfo->pfxs; - if (rainfo->linkmtu) + if (rai->rai_pfxs) + packlen += sizeof(struct nd_opt_prefix_info) * rai->rai_pfxs; + if (rai->rai_linkmtu) packlen += sizeof(struct nd_opt_mtu); #ifdef ROUTEINFO - for (rti = rainfo->route.next; rti != &rainfo->route; rti = rti->next) - packlen += sizeof(struct nd_opt_route_info) + - ((rti->prefixlen + 0x3f) >> 6) * 8; + TAILQ_FOREACH(rti, &rai->rai_route, rti_next) + packlen += sizeof(struct nd_opt_route_info) + + ((rti->rti_prefixlen + 0x3f) >> 6) * 8; #endif + TAILQ_FOREACH(rdn, &rai->rai_rdnss, rd_next) { + struct rdnss_addr *rdna; + packlen += sizeof(struct nd_opt_rdnss); + TAILQ_FOREACH(rdna, &rdn->rd_list, ra_next) + packlen += sizeof(rdna->ra_dns); + } + TAILQ_FOREACH(dns, &rai->rai_dnssl, dn_next) { + struct dnssl_addr *dnsa; + + packlen += sizeof(struct nd_opt_dnssl); + len = 0; + TAILQ_FOREACH(dnsa, &dns->dn_list, da_next) + len += dnsa->da_len; + + /* A zero octet and 8 octet boundary */ + len++; + len += (len % 8) ? 8 - len % 8 : 0; + + packlen += len; + } /* allocate memory for the packet */ if ((buf = malloc(packlen)) == NULL) { syslog(LOG_ERR, - "<%s> can't get enough memory for an RA packet", - __func__); + "<%s> can't get enough memory for an RA packet", + __func__); exit(1); } - if (rainfo->ra_data) { - /* free the previous packet */ - free(rainfo->ra_data); - rainfo->ra_data = NULL; - } - rainfo->ra_data = buf; + memset(buf, 0, packlen); + if (rai->rai_ra_data) /* Free old data if any. */ + free(rai->rai_ra_data); + rai->rai_ra_data = buf; /* XXX: what if packlen > 576? */ - rainfo->ra_datalen = packlen; + rai->rai_ra_datalen = packlen; /* * construct the packet @@ -960,71 +1144,70 @@ make_packet(struct rainfo *rainfo) ra->nd_ra_type = ND_ROUTER_ADVERT; ra->nd_ra_code = 0; ra->nd_ra_cksum = 0; - ra->nd_ra_curhoplimit = (u_int8_t)(0xff & rainfo->hoplimit); + ra->nd_ra_curhoplimit = (u_int8_t)(0xff & rai->rai_hoplimit); 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 = 0xff & rai->rai_rtpref; ra->nd_ra_flags_reserved |= - rainfo->managedflg ? ND_RA_FLAG_MANAGED : 0; + rai->rai_managedflg ? ND_RA_FLAG_MANAGED : 0; ra->nd_ra_flags_reserved |= - rainfo->otherflg ? ND_RA_FLAG_OTHER : 0; - ra->nd_ra_router_lifetime = htons(rainfo->lifetime); - ra->nd_ra_reachable = htonl(rainfo->reachabletime); - ra->nd_ra_retransmit = htonl(rainfo->retranstimer); + rai->rai_otherflg ? ND_RA_FLAG_OTHER : 0; + ra->nd_ra_router_lifetime = htons(rai->rai_lifetime); + ra->nd_ra_reachable = htonl(rai->rai_reachabletime); + ra->nd_ra_retransmit = htonl(rai->rai_retranstimer); buf += sizeof(*ra); - if (rainfo->advlinkopt) { - lladdropt_fill(rainfo->sdl, (struct nd_opt_hdr *)buf); + if (rai->rai_advlinkopt) { + lladdropt_fill(rai->rai_sdl, (struct nd_opt_hdr *)buf); buf += lladdroptlen; } - if (rainfo->linkmtu) { + if (rai->rai_linkmtu) { ndopt_mtu = (struct nd_opt_mtu *)buf; 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 = htonl(rainfo->linkmtu); + ndopt_mtu->nd_opt_mtu_mtu = htonl(rai->rai_linkmtu); buf += sizeof(struct nd_opt_mtu); } - for (pfx = rainfo->prefix.next; - pfx != &rainfo->prefix; pfx = pfx->next) { + TAILQ_FOREACH(pfx, &rai->rai_prefix, 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; - ndopt_pi->nd_opt_pi_prefix_len = pfx->prefixlen; + ndopt_pi->nd_opt_pi_prefix_len = pfx->pfx_prefixlen; ndopt_pi->nd_opt_pi_flags_reserved = 0; - if (pfx->onlinkflg) + if (pfx->pfx_onlinkflg) ndopt_pi->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_ONLINK; - if (pfx->autoconfflg) + if (pfx->pfx_autoconfflg) ndopt_pi->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_AUTO; - if (pfx->timer) + if (pfx->pfx_timer) vltime = 0; else { - if (pfx->vltimeexpire || pfx->pltimeexpire) + if (pfx->pfx_vltimeexpire || pfx->pfx_pltimeexpire) gettimeofday(&now, NULL); - if (pfx->vltimeexpire == 0) - vltime = pfx->validlifetime; + if (pfx->pfx_vltimeexpire == 0) + vltime = pfx->pfx_validlifetime; else - vltime = (pfx->vltimeexpire > now.tv_sec) ? - pfx->vltimeexpire - now.tv_sec : 0; + vltime = (pfx->pfx_vltimeexpire > now.tv_sec) ? + pfx->pfx_vltimeexpire - now.tv_sec : 0; } - if (pfx->timer) + if (pfx->pfx_timer) pltime = 0; else { - if (pfx->pltimeexpire == 0) - pltime = pfx->preflifetime; + if (pfx->pfx_pltimeexpire == 0) + pltime = pfx->pfx_preflifetime; else - pltime = (pfx->pltimeexpire > now.tv_sec) ? - pfx->pltimeexpire - now.tv_sec : 0; + pltime = (pfx->pfx_pltimeexpire > now.tv_sec) ? + pfx->pfx_pltimeexpire - now.tv_sec : 0; } if (vltime < pltime) { /* @@ -1036,45 +1219,72 @@ make_packet(struct rainfo *rainfo) 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; + ndopt_pi->nd_opt_pi_prefix = pfx->pfx_prefix; buf += sizeof(struct nd_opt_prefix_info); } #ifdef ROUTEINFO - for (rti = rainfo->route.next; rti != &rainfo->route; rti = rti->next) { - u_int8_t psize = (rti->prefixlen + 0x3f) >> 6; + TAILQ_FOREACH(rti, &rai->rai_route, rti_next) { + u_int8_t psize = (rti->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 = htonl(rti->ltime); - memcpy(ndopt_rti + 1, &rti->prefix, psize * 8); + ndopt_rti->nd_opt_rti_prefixlen = rti->rti_prefixlen; + ndopt_rti->nd_opt_rti_flags = 0xff & rti->rti_rtpref; + ndopt_rti->nd_opt_rti_lifetime = htonl(rti->rti_ltime); + memcpy(ndopt_rti + 1, &rti->rti_prefix, psize * 8); buf += sizeof(struct nd_opt_route_info) + psize * 8; } #endif + TAILQ_FOREACH(rdn, &rai->rai_rdnss, rd_next) { + struct rdnss_addr *rdna; + + ndopt_rdnss = (struct nd_opt_rdnss *)buf; + ndopt_rdnss->nd_opt_rdnss_type = ND_OPT_RDNSS; + ndopt_rdnss->nd_opt_rdnss_len = 0; + ndopt_rdnss->nd_opt_rdnss_reserved = 0; + ndopt_rdnss->nd_opt_rdnss_lifetime = htonl(rdn->rd_ltime); + buf += sizeof(struct nd_opt_rdnss); + + TAILQ_FOREACH(rdna, &rdn->rd_list, ra_next) { + memcpy(buf, &rdna->ra_dns, sizeof(rdna->ra_dns)); + buf += sizeof(rdna->ra_dns); + } + /* Length field should be in 8 octets */ + ndopt_rdnss->nd_opt_rdnss_len = (buf - (char *)ndopt_rdnss) / 8; - return; -} + syslog(LOG_DEBUG, "<%s>: nd_opt_dnss_len = %d", __func__, + ndopt_rdnss->nd_opt_rdnss_len); + } + TAILQ_FOREACH(dns, &rai->rai_dnssl, dn_next) { + struct dnssl_addr *dnsa; + + ndopt_dnssl = (struct nd_opt_dnssl *)buf; + ndopt_dnssl->nd_opt_dnssl_type = ND_OPT_DNSSL; + ndopt_dnssl->nd_opt_dnssl_len = 0; + ndopt_dnssl->nd_opt_dnssl_reserved = 0; + ndopt_dnssl->nd_opt_dnssl_lifetime = htonl(dns->dn_ltime); + buf += sizeof(*ndopt_dnssl); + + TAILQ_FOREACH(dnsa, &dns->dn_list, da_next) { + memcpy(buf, dnsa->da_dom, dnsa->da_len); + buf += dnsa->da_len; + } -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", - __func__, code, - strerror(errno)); - return(-1); + /* A zero octet after encoded DNS server list. */ + *buf++ = '\0'; + + /* Padding to next 8 octets boundary */ + len = buf - (char *)ndopt_dnssl; + len += (len % 8) ? 8 - len % 8 : 0; + + /* Length field must be in 8 octets */ + ndopt_dnssl->nd_opt_dnssl_len = len / 8; + + syslog(LOG_DEBUG, "<%s>: nd_opt_dnssl_len = %d", __func__, + ndopt_dnssl->nd_opt_dnssl_len); } - else - return(value); + return; } diff --git a/usr.sbin/rtadvd/config.h b/usr.sbin/rtadvd/config.h index 2d02b8a..38c19b8 100644 --- a/usr.sbin/rtadvd/config.h +++ b/usr.sbin/rtadvd/config.h @@ -4,7 +4,7 @@ /* * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -16,7 +16,7 @@ * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -30,7 +30,8 @@ * SUCH DAMAGE. */ -extern void getconfig(char *); +extern int getconfig(int); +extern int rmconfig(int); extern void delete_prefix(struct prefix *); extern void invalidate_prefix(struct prefix *); extern void update_prefix(struct prefix *); @@ -45,3 +46,5 @@ extern void get_prefix(struct rainfo *); */ #define MAXPREFIX 100 #define MAXROUTE 100 +#define MAXRDNSSENT 100 +#define MAXDNSSLENT 100 diff --git a/usr.sbin/rtadvd/dump.c b/usr.sbin/rtadvd/dump.c index d37f5db..f79319b 100644 --- a/usr.sbin/rtadvd/dump.c +++ b/usr.sbin/rtadvd/dump.c @@ -4,7 +4,7 @@ /* * Copyright (C) 2000 WIDE Project. * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -16,7 +16,7 @@ * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -45,6 +45,7 @@ #include <arpa/inet.h> +#include <netdb.h> #include <time.h> #include <stdio.h> #include <stdarg.h> @@ -63,8 +64,9 @@ extern struct rainfo *ralist; static char *ether_str(struct sockaddr_dl *); static void if_dump(void); +static size_t dname_labeldec(char *, size_t, const char *); -static char *rtpref_str[] = { +static const char *rtpref_str[] = { "medium", /* 00 */ "high", /* 01 */ "rsv", /* 10 */ @@ -72,8 +74,7 @@ static char *rtpref_str[] = { }; static char * -ether_str(sdl) - struct sockaddr_dl *sdl; +ether_str(struct sockaddr_dl *sdl) { static char hbuf[32]; u_char *cp; @@ -85,84 +86,86 @@ ether_str(sdl) } else snprintf(hbuf, sizeof(hbuf), "NONE"); - return(hbuf); + return (hbuf); } static void -if_dump() +if_dump(void) { struct rainfo *rai; struct prefix *pfx; #ifdef ROUTEINFO struct rtinfo *rti; #endif + struct rdnss *rdn; + struct dnssl *dns; char prefixbuf[INET6_ADDRSTRLEN]; - int first; struct timeval now; gettimeofday(&now, NULL); /* XXX: unused in most cases */ - for (rai = ralist; rai; rai = rai->next) { - fprintf(fp, "%s:\n", rai->ifname); + TAILQ_FOREACH(rai, &railist, rai_next) { + fprintf(fp, "%s:\n", rai->rai_ifname); fprintf(fp, " Status: %s\n", - (iflist[rai->ifindex]->ifm_flags & IFF_UP) ? "UP" : - "DOWN"); + (iflist[rai->rai_ifindex]->ifm_flags & IFF_UP) ? "UP" : + "DOWN"); /* control information */ - if (rai->lastsent.tv_sec) { + if (rai->rai_lastsent.tv_sec) { /* note that ctime() appends CR by itself */ fprintf(fp, " Last RA sent: %s", - ctime((time_t *)&rai->lastsent.tv_sec)); + ctime((time_t *)&rai->rai_lastsent.tv_sec)); } - if (rai->timer) { + if (rai->rai_timer) fprintf(fp, " Next RA will be sent: %s", - ctime((time_t *)&rai->timer->tm.tv_sec)); - } + ctime((time_t *)&rai->rai_timer->rat_tm.tv_sec)); else fprintf(fp, " RA timer is stopped"); fprintf(fp, " waits: %d, initcount: %d\n", - rai->waiting, rai->initcounter); + rai->rai_waiting, rai->rai_initcounter); /* statistics */ fprintf(fp, " statistics: RA(out/in/inconsistent): " "%llu/%llu/%llu, ", - (unsigned long long)rai->raoutput, - (unsigned long long)rai->rainput, - (unsigned long long)rai->rainconsistent); + (unsigned long long)rai->rai_raoutput, + (unsigned long long)rai->rai_rainput, + (unsigned long long)rai->rai_rainconsistent); fprintf(fp, "RS(input): %llu\n", - (unsigned long long)rai->rsinput); + (unsigned long long)rai->rai_rsinput); /* interface information */ - if (rai->advlinkopt) + if (rai->rai_advlinkopt) fprintf(fp, " Link-layer address: %s\n", - ether_str(rai->sdl)); - fprintf(fp, " MTU: %d\n", rai->phymtu); + ether_str(rai->rai_sdl)); + fprintf(fp, " MTU: %d\n", rai->rai_phymtu); /* Router configuration variables */ fprintf(fp, " DefaultLifetime: %d, MaxAdvInterval: %d, " - "MinAdvInterval: %d\n", rai->lifetime, rai->maxinterval, - rai->mininterval); - fprintf(fp, " Flags: %s%s%s, ", - rai->managedflg ? "M" : "", rai->otherflg ? "O" : "", ""); + "MinAdvInterval: %d\n", rai->rai_lifetime, + rai->rai_maxinterval, rai->rai_mininterval); + fprintf(fp, " Flags: "); + if (rai->rai_managedflg || rai->rai_otherflg) { + fprintf(fp, "%s", rai->rai_managedflg ? "M" : ""); + fprintf(fp, "%s", rai->rai_otherflg ? "O" : ""); + } else + fprintf(fp, "<none>"); + fprintf(fp, ", "); fprintf(fp, "Preference: %s, ", - rtpref_str[(rai->rtpref >> 3) & 0xff]); - fprintf(fp, "MTU: %d\n", rai->linkmtu); + rtpref_str[(rai->rai_rtpref >> 3) & 0xff]); + fprintf(fp, "MTU: %d\n", rai->rai_linkmtu); fprintf(fp, " ReachableTime: %d, RetransTimer: %d, " - "CurHopLimit: %d\n", rai->reachabletime, - rai->retranstimer, rai->hoplimit); - if (rai->clockskew) + "CurHopLimit: %d\n", rai->rai_reachabletime, + rai->rai_retranstimer, rai->rai_hoplimit); + if (rai->rai_clockskew) fprintf(fp, " Clock skew: %ldsec\n", - rai->clockskew); - for (first = 1, pfx = rai->prefix.next; pfx != &rai->prefix; - pfx = pfx->next) { - if (first) { + rai->rai_clockskew); + TAILQ_FOREACH(pfx, &rai->rai_prefix, pfx_next) { + if (pfx == TAILQ_FIRST(&rai->rai_prefix)) fprintf(fp, " Prefixes:\n"); - first = 0; - } fprintf(fp, " %s/%d(", - inet_ntop(AF_INET6, &pfx->prefix, prefixbuf, - sizeof(prefixbuf)), pfx->prefixlen); - switch (pfx->origin) { + inet_ntop(AF_INET6, &pfx->pfx_prefix, prefixbuf, + sizeof(prefixbuf)), pfx->pfx_prefixlen); + switch (pfx->pfx_origin) { case PREFIX_FROM_KERNEL: fprintf(fp, "KERNEL, "); break; @@ -173,36 +176,42 @@ if_dump() fprintf(fp, "DYNAMIC, "); break; } - if (pfx->validlifetime == ND6_INFINITE_LIFETIME) + if (pfx->pfx_validlifetime == ND6_INFINITE_LIFETIME) fprintf(fp, "vltime: infinity"); else fprintf(fp, "vltime: %ld", - (long)pfx->validlifetime); - if (pfx->vltimeexpire != 0) - fprintf(fp, "(decr,expire %ld), ", (long) - pfx->vltimeexpire > now.tv_sec ? - pfx->vltimeexpire - now.tv_sec : 0); + (long)pfx->pfx_validlifetime); + if (pfx->pfx_vltimeexpire != 0) + fprintf(fp, "(decr,expire %ld), ", + (long)pfx->pfx_vltimeexpire > now.tv_sec ? + (long)pfx->pfx_vltimeexpire - now.tv_sec : + 0); else fprintf(fp, ", "); - if (pfx->preflifetime == ND6_INFINITE_LIFETIME) + if (pfx->pfx_preflifetime == ND6_INFINITE_LIFETIME) fprintf(fp, "pltime: infinity"); else fprintf(fp, "pltime: %ld", - (long)pfx->preflifetime); - if (pfx->pltimeexpire != 0) - fprintf(fp, "(decr,expire %ld), ", (long) - pfx->pltimeexpire > now.tv_sec ? - pfx->pltimeexpire - now.tv_sec : 0); + (long)pfx->pfx_preflifetime); + if (pfx->pfx_pltimeexpire != 0) + fprintf(fp, "(decr,expire %ld), ", + (long)pfx->pfx_pltimeexpire > now.tv_sec ? + (long)pfx->pfx_pltimeexpire - now.tv_sec : + 0); else fprintf(fp, ", "); - fprintf(fp, "flags: %s%s%s", - pfx->onlinkflg ? "L" : "", - pfx->autoconfflg ? "A" : "", - ""); - if (pfx->timer) { + fprintf(fp, "flags: "); + if (pfx->pfx_onlinkflg || pfx->pfx_autoconfflg) { + fprintf(fp, "%s", + pfx->pfx_onlinkflg ? "L" : ""); + fprintf(fp, "%s", + pfx->pfx_autoconfflg ? "A" : ""); + } else + fprintf(fp, "<none>"); + if (pfx->pfx_timer) { struct timeval *rest; - rest = rtadvd_timer_rest(pfx->timer); + rest = rtadvd_timer_rest(pfx->pfx_timer); if (rest) { /* XXX: what if not? */ fprintf(fp, ", expire in: %ld", (long)rest->tv_sec); @@ -211,31 +220,64 @@ if_dump() fprintf(fp, ")\n"); } #ifdef ROUTEINFO - for (first = 1, rti = rai->route.next; rti != &rai->route; - rti = rti->next) { - if (first) { + TAILQ_FOREACH(rti, &rai->rai_route, rti_next) { + if (rti == TAILQ_FIRST(&rai->rai_route)) fprintf(fp, " Route Information:\n"); - first = 0; - } fprintf(fp, " %s/%d (", - inet_ntop(AF_INET6, &rti->prefix, - prefixbuf, sizeof(prefixbuf)), - rti->prefixlen); + inet_ntop(AF_INET6, &rti->rti_prefix, + prefixbuf, sizeof(prefixbuf)), + rti->rti_prefixlen); fprintf(fp, "preference: %s, ", - rtpref_str[0xff & (rti->rtpref >> 3)]); - if (rti->ltime == ND6_INFINITE_LIFETIME) + rtpref_str[0xff & (rti->rti_rtpref >> 3)]); + if (rti->rti_ltime == ND6_INFINITE_LIFETIME) fprintf(fp, "lifetime: infinity"); else - fprintf(fp, "lifetime: %ld", (long)rti->ltime); + fprintf(fp, "lifetime: %ld", + (long)rti->rti_ltime); fprintf(fp, ")\n"); } #endif + TAILQ_FOREACH(rdn, &rai->rai_rdnss, rd_next) { + struct rdnss_addr *rdna; + + if (rdn == TAILQ_FIRST(&rai->rai_rdnss)) + fprintf(fp, " Recursive DNS servers:\n" + " Lifetime\tServers\n"); + + fprintf(fp, " %8u\t", rdn->rd_ltime); + TAILQ_FOREACH(rdna, &rdn->rd_list, ra_next) { + inet_ntop(AF_INET6, &rdna->ra_dns, + prefixbuf, sizeof(prefixbuf)); + + if (rdna != TAILQ_FIRST(&rdn->rd_list)) + fprintf(fp, " \t"); + fprintf(fp, "%s\n", prefixbuf); + } + fprintf(fp, "\n"); + } + + TAILQ_FOREACH(dns, &rai->rai_dnssl, dn_next) { + struct dnssl_addr *dnsa; + char buf[NI_MAXHOST]; + + if (dns == TAILQ_FIRST(&rai->rai_dnssl)) + fprintf(fp, " DNS search list:\n" + " Lifetime\tDomains\n"); + + fprintf(fp, " %8u\t", dns->dn_ltime); + TAILQ_FOREACH(dnsa, &dns->dn_list, da_next) { + dname_labeldec(buf, sizeof(buf), dnsa->da_dom); + if (dnsa != TAILQ_FIRST(&dns->dn_list)) + fprintf(fp, " \t"); + fprintf(fp, "%s(%d)\n", buf, dnsa->da_len); + } + fprintf(fp, "\n"); + } } } void -rtadvd_dump_file(dumpfile) - char *dumpfile; +rtadvd_dump_file(const char *dumpfile) { syslog(LOG_DEBUG, "<%s> dump current status to %s", __func__, dumpfile); @@ -250,3 +292,30 @@ rtadvd_dump_file(dumpfile) fclose(fp); } + +/* Decode domain name label encoding in RFC 1035 Section 3.1 */ +static size_t +dname_labeldec(char *dst, size_t dlen, const char *src) +{ + size_t len; + const char *src_origin; + const char *src_last; + const char *dst_origin; + + src_origin = src; + src_last = strchr(src, '\0'); + dst_origin = dst; + memset(dst, '\0', dlen); + while (src && (len = (uint8_t)(*src++) & 0x3f) && + (src + len) <= src_last) { + if (dst != dst_origin) + *dst++ = '.'; + syslog(LOG_DEBUG, "<%s> labellen = %d", __func__, len); + memcpy(dst, src, len); + src += len; + dst += len; + } + *dst = '\0'; + + return (src - src_origin); +} diff --git a/usr.sbin/rtadvd/dump.h b/usr.sbin/rtadvd/dump.h index c8a6b22..8696e13 100644 --- a/usr.sbin/rtadvd/dump.h +++ b/usr.sbin/rtadvd/dump.h @@ -4,7 +4,7 @@ /* * Copyright (C) 1998 WIDE Project. * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -16,7 +16,7 @@ * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -30,4 +30,4 @@ * SUCH DAMAGE. */ -extern void rtadvd_dump_file(char *); +extern void rtadvd_dump_file(const char *); diff --git a/usr.sbin/rtadvd/if.c b/usr.sbin/rtadvd/if.c index d8ed088..302c334 100644 --- a/usr.sbin/rtadvd/if.c +++ b/usr.sbin/rtadvd/if.c @@ -4,7 +4,7 @@ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -16,7 +16,7 @@ * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -44,34 +44,35 @@ #include <netinet/icmp6.h> #include <unistd.h> #include <errno.h> +#include <netdb.h> #include <stdlib.h> #include <string.h> #include <syslog.h> #include "rtadvd.h" #include "if.h" -#define ROUNDUP(a, size) \ +#define ROUNDUP(a, size) \ (((a) & ((size)-1)) ? (1 + ((a) | ((size)-1))) : (a)) -#define NEXT_SA(ap) (ap) = (struct sockaddr *) \ - ((caddr_t)(ap) + ((ap)->sa_len ? ROUNDUP((ap)->sa_len,\ - sizeof(u_long)) :\ - sizeof(u_long))) +#define NEXT_SA(ap) \ + (ap) = (struct sockaddr *)((caddr_t)(ap) + \ + ((ap)->sa_len ? ROUNDUP((ap)->sa_len, sizeof(u_long)) : \ + sizeof(u_long))) struct if_msghdr **iflist; int iflist_init_ok; size_t ifblock_size; char *ifblock; -static void get_iflist(char **buf, size_t *size); -static void parse_iflist(struct if_msghdr ***ifmlist_p, char *buf, - size_t bufsize); +static void get_iflist(char **buf, size_t *size); +static void parse_iflist(struct if_msghdr ***ifmlist_p, + char *buf, size_t bufsize); static void get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info) { int i; - + for (i = 0; i < RTAX_MAX; i++) { if (addrs & (1 << i)) { rti_info[i] = sa; @@ -93,12 +94,12 @@ if_nametosdl(char *name) struct sockaddr_dl *sdl = NULL, *ret_sdl; if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) - return(NULL); + return (NULL); if ((buf = malloc(len)) == NULL) - return(NULL); + return (NULL); if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) { free(buf); - return(NULL); + return (NULL); } lim = buf + len; @@ -124,7 +125,7 @@ if_nametosdl(char *name) if (next == lim) { /* search failed */ free(buf); - return(NULL); + return (NULL); } if ((ret_sdl = malloc(sdl->sdl_len)) == NULL) @@ -133,7 +134,7 @@ if_nametosdl(char *name) end: free(buf); - return(ret_sdl); + return (ret_sdl); } int @@ -144,7 +145,7 @@ if_getmtu(char *name) u_long mtu = 0; if (getifaddrs(&ifap) < 0) - return(0); + return (0); for (ifa = ifap; ifa; ifa = ifa->ifa_next) { if (strcmp(ifa->ifa_name, name) == 0) { ifd = ifa->ifa_data; @@ -161,14 +162,14 @@ if_getmtu(char *name) int s; if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) - return(0); + return (0); ifr.ifr_addr.sa_family = AF_INET6; strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); if (ioctl(s, SIOCGIFMTU, (caddr_t)&ifr) < 0) { close(s); - return(0); + return (0); } close(s); @@ -176,7 +177,7 @@ if_getmtu(char *name) } #endif - return(mtu); + return (mtu); } /* give interface index and its old flags, then new flags returned */ @@ -188,14 +189,14 @@ if_getflags(int ifindex, int oifflags) if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { syslog(LOG_ERR, "<%s> socket: %s", __func__, - strerror(errno)); + strerror(errno)); return (oifflags & ~IFF_UP); } if_indextoname(ifindex, ifr.ifr_name); if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) { syslog(LOG_ERR, "<%s> ioctl:SIOCGIFFLAGS: failed for %s", - __func__, ifr.ifr_name); + __func__, ifr.ifr_name); close(s); return (oifflags & ~IFF_UP); } @@ -209,9 +210,9 @@ lladdropt_length(struct sockaddr_dl *sdl) { switch (sdl->sdl_type) { case IFT_ETHER: - return(ROUNDUP8(ETHER_ADDR_LEN + 2)); + return (ROUNDUP8(ETHER_ADDR_LEN + 2)); default: - return(0); + return (0); } } @@ -238,16 +239,15 @@ lladdropt_fill(struct sockaddr_dl *sdl, struct nd_opt_hdr *ndopt) } int -rtbuf_len() +rtbuf_len(void) { size_t len; - int mib[6] = {CTL_NET, AF_ROUTE, 0, AF_INET6, NET_RT_DUMP, 0}; if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) - return(-1); + return (-1); - return(len); + return (len); } #define FILTER_MATCH(type, filter) ((0x1 << type) & filter) @@ -267,14 +267,21 @@ get_next_msg(char *buf, char *lim, int ifindex, size_t *lenp, int filter) /* just for safety */ if (!rtm->rtm_msglen) { syslog(LOG_WARNING, "<%s> rtm_msglen is 0 " - "(buf=%p lim=%p rtm=%p)", __func__, - buf, lim, rtm); + "(buf=%p lim=%p rtm=%p)", __func__, + buf, lim, rtm); break; } - if (FILTER_MATCH(rtm->rtm_type, filter) == 0) { + if (((struct rt_msghdr *)buf)->rtm_version != RTM_VERSION) { + syslog(LOG_WARNING, + "<%s> routing message version mismatch " + "(buf=%p lim=%p rtm=%p)", __func__, + buf, lim, rtm); continue; } + if (FILTER_MATCH(rtm->rtm_type, filter) == 0) + continue; + switch (rtm->rtm_type) { case RTM_GET: case RTM_ADD: @@ -328,6 +335,7 @@ get_next_msg(char *buf, char *lim, int ifindex, size_t *lenp, int filter) return (char *)rtm; /* NOTREACHED */ case RTM_IFINFO: + case RTM_IFANNOUNCE: /* found */ *lenp = rtm->rtm_msglen; return (char *)rtm; @@ -335,7 +343,7 @@ get_next_msg(char *buf, char *lim, int ifindex, size_t *lenp, int filter) } } - return (char *)rtm; + return ((char *)rtm); } #undef FILTER_MATCH @@ -348,7 +356,7 @@ get_addr(char *buf) sa = (struct sockaddr *)(rtm + 1); get_rtaddrs(rtm->rtm_addrs, sa, rti_info); - return(&SIN6(rti_info[RTAX_DST])->sin6_addr); + return (&SIN6(rti_info[RTAX_DST])->sin6_addr); } int @@ -360,7 +368,7 @@ get_rtm_ifindex(char *buf) sa = (struct sockaddr *)(rtm + 1); get_rtaddrs(rtm->rtm_addrs, sa, rti_info); - return(((struct sockaddr_dl *)rti_info[RTAX_GATEWAY])->sdl_index); + return (((struct sockaddr_dl *)rti_info[RTAX_GATEWAY])->sdl_index); } int @@ -393,7 +401,7 @@ get_prefixlen(char *buf) struct rt_msghdr *rtm = (struct rt_msghdr *)buf; struct sockaddr *sa, *rti_info[RTAX_MAX]; u_char *p, *lim; - + sa = (struct sockaddr *)(rtm + 1); get_rtaddrs(rtm->rtm_addrs, sa, rti_info); sa = rti_info[RTAX_NETMASK]; @@ -437,11 +445,11 @@ prefixlen(u_char *p, u_char *lim) case 0x00: break; default: - return(-1); + return (-1); } } - return(masklen); + return (masklen); } int @@ -449,7 +457,7 @@ rtmsg_type(char *buf) { struct rt_msghdr *rtm = (struct rt_msghdr *)buf; - return(rtm->rtm_type); + return (rtm->rtm_type); } int @@ -457,7 +465,7 @@ rtmsg_len(char *buf) { struct rt_msghdr *rtm = (struct rt_msghdr *)buf; - return(rtm->rtm_msglen); + return (rtm->rtm_msglen); } int @@ -465,7 +473,7 @@ ifmsg_len(char *buf) { struct if_msghdr *ifm = (struct if_msghdr *)buf; - return(ifm->ifm_msglen); + return (ifm->ifm_msglen); } /* @@ -486,7 +494,7 @@ get_iflist(char **buf, size_t *size) if (sysctl(mib, 6, NULL, size, NULL, 0) < 0) { syslog(LOG_ERR, "<%s> sysctl: iflist size get failed", - __func__); + __func__); exit(1); } if ((*buf = malloc(*size)) == NULL) { @@ -495,7 +503,7 @@ get_iflist(char **buf, size_t *size) } if (sysctl(mib, 6, *buf, size, NULL, 0) < 0) { syslog(LOG_ERR, "<%s> sysctl: iflist get failed", - __func__); + __func__); exit(1); } return; @@ -529,8 +537,8 @@ parse_iflist(struct if_msghdr ***ifmlist_p, char *buf, size_t bufsize) for (ifm = (struct if_msghdr *)buf; ifm < (struct if_msghdr *)lim;) { if (ifm->ifm_msglen == 0) { syslog(LOG_WARNING, "<%s> ifm_msglen is 0 " - "(buf=%p lim=%p ifm=%p)", __func__, - buf, lim, ifm); + "(buf=%p lim=%p ifm=%p)", __func__, + buf, lim, ifm); return; } @@ -538,10 +546,10 @@ parse_iflist(struct if_msghdr ***ifmlist_p, char *buf, size_t bufsize) (*ifmlist_p)[ifm->ifm_index] = ifm; } else { syslog(LOG_ERR, "out of sync parsing NET_RT_IFLIST\n" - "expected %d, got %d\n msglen = %d\n" - "buf:%p, ifm:%p, lim:%p\n", - RTM_IFINFO, ifm->ifm_type, ifm->ifm_msglen, - buf, ifm, lim); + "expected %d, got %d\n msglen = %d\n" + "buf:%p, ifm:%p, lim:%p\n", + RTM_IFINFO, ifm->ifm_type, ifm->ifm_msglen, + buf, ifm, lim); exit (1); } for (ifam = (struct ifa_msghdr *) @@ -552,8 +560,8 @@ parse_iflist(struct if_msghdr ***ifmlist_p, char *buf, size_t bufsize) /* just for safety */ if (!ifam->ifam_msglen) { syslog(LOG_WARNING, "<%s> ifa_msglen is 0 " - "(buf=%p lim=%p ifam=%p)", __func__, - buf, lim, ifam); + "(buf=%p lim=%p ifam=%p)", __func__, + buf, lim, ifam); return; } if (ifam->ifam_type != RTM_NEWADDR) @@ -564,8 +572,11 @@ parse_iflist(struct if_msghdr ***ifmlist_p, char *buf, size_t bufsize) } void -init_iflist() +init_iflist(void) { + syslog(LOG_DEBUG, + "<%s> generate iflist.", __func__); + if (ifblock) { free(ifblock); ifblock_size = 0; diff --git a/usr.sbin/rtadvd/if.h b/usr.sbin/rtadvd/if.h index 216eaa0..8728e19 100644 --- a/usr.sbin/rtadvd/if.h +++ b/usr.sbin/rtadvd/if.h @@ -4,7 +4,7 @@ /* * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -16,7 +16,7 @@ * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE diff --git a/usr.sbin/rtadvd/pathnames.h b/usr.sbin/rtadvd/pathnames.h index 3afee55..13329da 100644 --- a/usr.sbin/rtadvd/pathnames.h +++ b/usr.sbin/rtadvd/pathnames.h @@ -1,4 +1,7 @@ /* $KAME: pathnames.h,v 1.2 2000/05/16 13:34:13 itojun Exp $ */ /* $FreeBSD$ */ -#define _PATH_RTADVDCONF "/etc/rtadvd.conf" +#define _PATH_RTADVDCONF "/etc/rtadvd.conf" +#define _PATH_RTADVDDUMP "/var/run/rtadvd.dump" +#define _PATH_RTADVDPID "/var/run/rtadvd.pid" + diff --git a/usr.sbin/rtadvd/rrenum.c b/usr.sbin/rtadvd/rrenum.c index aafa0f9..660ed53 100644 --- a/usr.sbin/rtadvd/rrenum.c +++ b/usr.sbin/rtadvd/rrenum.c @@ -45,6 +45,7 @@ #include <arpa/inet.h> #include <errno.h> +#include <netdb.h> #include <string.h> #include <stdlib.h> #include <syslog.h> @@ -74,7 +75,7 @@ static int s = -1; /* * Check validity of a Prefix Control Operation(PCO). - * Return 0 on success, 1 on failure. + * return 0 on success, 1 on failure. */ static int rr_pco_check(int len, struct rr_pco_match *rpm) @@ -86,8 +87,8 @@ rr_pco_check(int len, struct rr_pco_match *rpm) if ((rpm->rpm_len - 3) < 0 || /* must be at least 3 */ (rpm->rpm_len - 3) & 0x3) { /* must be multiple of 4 */ syslog(LOG_WARNING, "<%s> rpm_len %d is not 4N * 3", - __func__, rpm->rpm_len); - return 1; + __func__, rpm->rpm_len); + return (1); } /* rpm->rpm_code must be valid value */ switch (rpm->rpm_code) { @@ -97,14 +98,14 @@ rr_pco_check(int len, struct rr_pco_match *rpm) break; default: syslog(LOG_WARNING, "<%s> unknown rpm_code %d", __func__, - rpm->rpm_code); - return 1; + rpm->rpm_code); + return (1); } /* rpm->rpm_matchlen must be 0 to 128 inclusive */ if (rpm->rpm_matchlen > 128) { syslog(LOG_WARNING, "<%s> rpm_matchlen %d is over 128", - __func__, rpm->rpm_matchlen); - return 1; + __func__, rpm->rpm_matchlen); + return (1); } /* @@ -126,23 +127,22 @@ rr_pco_check(int len, struct rr_pco_match *rpm) */ if (checklen > 128) { syslog(LOG_WARNING, "<%s> sum of rpu_uselen %d and" - " rpu_keeplen %d is %d(over 128)", - __func__, rpu->rpu_uselen, - rpu->rpu_keeplen, - rpu->rpu_uselen + rpu->rpu_keeplen); - return 1; + " rpu_keeplen %d is %d(over 128)", + __func__, rpu->rpu_uselen, rpu->rpu_keeplen, + rpu->rpu_uselen + rpu->rpu_keeplen); + return (1); } } - return 0; + return (0); } static void do_use_prefix(int len, struct rr_pco_match *rpm, - struct in6_rrenumreq *irr, int ifindex) + struct in6_rrenumreq *irr, int ifindex) { struct rr_pco_use *rpu, *rpulim; struct rainfo *rai; - struct prefix *pp; + struct prefix *pfx; rpu = (struct rr_pco_use *)(rpm + 1); rpulim = (struct rr_pco_use *)((char *)rpm + len); @@ -164,7 +164,7 @@ do_use_prefix(int len, struct rr_pco_match *rpm, if (ioctl(s, rrcmd2pco[rpm->rpm_code], (caddr_t)irr) < 0 && errno != EADDRNOTAVAIL) syslog(LOG_ERR, "<%s> ioctl: %s", __func__, - strerror(errno)); + strerror(errno)); return; } @@ -176,19 +176,23 @@ do_use_prefix(int len, struct rr_pco_match *rpm, irr->irr_u_uselen = rpu->rpu_uselen; irr->irr_u_keeplen = rpu->rpu_keeplen; irr->irr_raf_mask_onlink = - !!(rpu->rpu_ramask & ICMP6_RR_PCOUSE_RAFLAGS_ONLINK); + !!(rpu->rpu_ramask & ICMP6_RR_PCOUSE_RAFLAGS_ONLINK); irr->irr_raf_mask_auto = - !!(rpu->rpu_ramask & ICMP6_RR_PCOUSE_RAFLAGS_AUTO); + !!(rpu->rpu_ramask & ICMP6_RR_PCOUSE_RAFLAGS_AUTO); irr->irr_vltime = ntohl(rpu->rpu_vltime); irr->irr_pltime = ntohl(rpu->rpu_pltime); irr->irr_raf_onlink = - (rpu->rpu_raflags & ICMP6_RR_PCOUSE_RAFLAGS_ONLINK) == 0 ? 0 : 1; + (rpu->rpu_raflags & ICMP6_RR_PCOUSE_RAFLAGS_ONLINK) == 0 ? + 0 : 1; irr->irr_raf_auto = - (rpu->rpu_raflags & ICMP6_RR_PCOUSE_RAFLAGS_AUTO) == 0 ? 0 : 1; + (rpu->rpu_raflags & ICMP6_RR_PCOUSE_RAFLAGS_AUTO) == 0 ? + 0 : 1; irr->irr_rrf_decrvalid = - (rpu->rpu_flags & ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME) == 0 ? 0 : 1; + (rpu->rpu_flags & ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME) == 0 ? + 0 : 1; irr->irr_rrf_decrprefd = - (rpu->rpu_flags & ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME) == 0 ? 0 : 1; + (rpu->rpu_flags & ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME) == 0 ? + 0 : 1; irr->irr_useprefix.sin6_len = sizeof(irr->irr_useprefix); irr->irr_useprefix.sin6_family = AF_INET6; irr->irr_useprefix.sin6_addr = rpu->rpu_prefix; @@ -196,7 +200,7 @@ do_use_prefix(int len, struct rr_pco_match *rpm, if (ioctl(s, rrcmd2pco[rpm->rpm_code], (caddr_t)irr) < 0 && errno != EADDRNOTAVAIL) syslog(LOG_ERR, "<%s> ioctl: %s", __func__, - strerror(errno)); + strerror(errno)); /* very adhoc: should be rewritten */ if (rpm->rpm_code == RPM_PCO_CHANGE && @@ -206,28 +210,31 @@ do_use_prefix(int len, struct rr_pco_match *rpm, if ((rai = if_indextorainfo(ifindex)) == NULL) continue; /* non-advertising IF */ - for (pp = rai->prefix.next; pp != &rai->prefix; - pp = pp->next) { + TAILQ_FOREACH(pfx, &rai->rai_prefix, pfx_next) { struct timeval now; - if (prefix_match(&pp->prefix, pp->prefixlen, - &rpm->rpm_prefix, - rpm->rpm_matchlen)) { + if (prefix_match(&pfx->pfx_prefix, + pfx->pfx_prefixlen, &rpm->rpm_prefix, + rpm->rpm_matchlen)) { /* change parameters */ - pp->validlifetime = ntohl(rpu->rpu_vltime); - pp->preflifetime = ntohl(rpu->rpu_pltime); + pfx->pfx_validlifetime = + ntohl(rpu->rpu_vltime); + pfx->pfx_preflifetime = + ntohl(rpu->rpu_pltime); if (irr->irr_rrf_decrvalid) { gettimeofday(&now, 0); - pp->vltimeexpire = - now.tv_sec + pp->validlifetime; + pfx->pfx_vltimeexpire = + now.tv_sec + + pfx->pfx_validlifetime; } else - pp->vltimeexpire = 0; + pfx->pfx_vltimeexpire = 0; if (irr->irr_rrf_decrprefd) { gettimeofday(&now, 0); - pp->pltimeexpire = - now.tv_sec + pp->preflifetime; + pfx->pfx_pltimeexpire = + now.tv_sec + + pfx->pfx_preflifetime; } else - pp->pltimeexpire = 0; + pfx->pfx_pltimeexpire = 0; } } } @@ -245,11 +252,11 @@ do_pco(struct icmp6_router_renum *rr, int len, struct rr_pco_match *rpm) struct in6_rrenumreq irr; if ((rr_pco_check(len, rpm) != 0)) - return 1; + return (1); if (s == -1 && (s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { syslog(LOG_ERR, "<%s> socket: %s", __func__, - strerror(errno)); + strerror(errno)); exit(1); } @@ -264,8 +271,8 @@ do_pco(struct icmp6_router_renum *rr, int len, struct rr_pco_match *rpm) while (if_indextoname(++ifindex, irr.irr_name)) { /* - * if ICMP6_RR_FLAGS_FORCEAPPLY(A flag) is 0 and IFF_UP is off, - * the interface is not applied + * if ICMP6_RR_FLAGS_FORCEAPPLY(A flag) is 0 and + * IFF_UP is off, the interface is not applied */ if ((rr->rr_flags & ICMP6_RR_FLAGS_FORCEAPPLY) == 0 && (iflist[ifindex]->ifm_flags & IFF_UP) == 0) @@ -274,13 +281,13 @@ do_pco(struct icmp6_router_renum *rr, int len, struct rr_pco_match *rpm) do_use_prefix(len, rpm, &irr, ifindex); } if (errno == ENXIO) - return 0; + return (0); else if (errno) { syslog(LOG_ERR, "<%s> if_indextoname: %s", __func__, - strerror(errno)); - return 1; + strerror(errno)); + return (1); } - return 0; + return (0); } /* @@ -305,11 +312,11 @@ do_rr(int len, struct icmp6_router_renum *rr) int rpmlen; rpm = (struct rr_pco_match *)cp; - if (len < sizeof(struct rr_pco_match)) { + if ((size_t)len < sizeof(struct rr_pco_match)) { tooshort: syslog(LOG_ERR, "<%s> pkt too short. left len = %d. " - "gabage at end of pkt?", __func__, len); - return 1; + "gabage at end of pkt?", __func__, len); + return (1); } rpmlen = rpm->rpm_len << 3; if (len < rpmlen) @@ -325,7 +332,7 @@ do_rr(int len, struct icmp6_router_renum *rr) len -= rpmlen; } - return 0; + return (0); } /* @@ -334,46 +341,45 @@ do_rr(int len, struct icmp6_router_renum *rr) */ static int rr_command_check(int len, struct icmp6_router_renum *rr, struct in6_addr *from, - struct in6_addr *dst) + struct in6_addr *dst) { u_char ntopbuf[INET6_ADDRSTRLEN]; /* omit rr minimal length check. hope kernel have done it. */ /* rr_command length check */ - if (len < (sizeof(struct icmp6_router_renum) + - sizeof(struct rr_pco_match))) { + if ((size_t)len < (sizeof(struct icmp6_router_renum) + + sizeof(struct rr_pco_match))) { syslog(LOG_ERR, "<%s> rr_command len %d is too short", - __func__, len); - return 1; + __func__, len); + return (1); } /* destination check. only for multicast. omit unicast check. */ if (IN6_IS_ADDR_MULTICAST(dst) && !IN6_IS_ADDR_MC_LINKLOCAL(dst) && !IN6_IS_ADDR_MC_SITELOCAL(dst)) { syslog(LOG_ERR, "<%s> dst mcast addr %s is illegal", - __func__, - inet_ntop(AF_INET6, dst, ntopbuf, INET6_ADDRSTRLEN)); - return 1; + __func__, + inet_ntop(AF_INET6, dst, ntopbuf, sizeof(ntopbuf))); + return (1); } /* seqnum and segnum check */ if (rro.rro_seqnum > rr->rr_seqnum) { syslog(LOG_WARNING, - "<%s> rcvd old seqnum %d from %s", - __func__, (u_int32_t)ntohl(rr->rr_seqnum), - inet_ntop(AF_INET6, from, ntopbuf, INET6_ADDRSTRLEN)); - return 1; + "<%s> rcvd old seqnum %d from %s", + __func__, (u_int32_t)ntohl(rr->rr_seqnum), + inet_ntop(AF_INET6, from, ntopbuf, sizeof(ntopbuf))); + return (1); } if (rro.rro_seqnum == rr->rr_seqnum && (rr->rr_flags & ICMP6_RR_FLAGS_TEST) == 0 && RR_ISSET_SEGNUM(rro.rro_segnum_bits, rr->rr_segnum)) { if ((rr->rr_flags & ICMP6_RR_FLAGS_REQRESULT) != 0) syslog(LOG_WARNING, - "<%s> rcvd duped segnum %d from %s", - __func__, rr->rr_segnum, - inet_ntop(AF_INET6, from, ntopbuf, - INET6_ADDRSTRLEN)); - return 0; + "<%s> rcvd duped segnum %d from %s", + __func__, rr->rr_segnum, inet_ntop(AF_INET6, from, + ntopbuf, sizeof(ntopbuf))); + return (0); } /* update seqnum */ @@ -382,16 +388,16 @@ rr_command_check(int len, struct icmp6_router_renum *rr, struct in6_addr *from, /* init rro_segnum_bits */ memset(rro.rro_segnum_bits, 0, - sizeof(rro.rro_segnum_bits)); + sizeof(rro.rro_segnum_bits)); } rro.rro_seqnum = rr->rr_seqnum; - return 0; + return (0); } static void rr_command_input(int len, struct icmp6_router_renum *rr, - struct in6_addr *from, struct in6_addr *dst) + struct in6_addr *from, struct in6_addr *dst) { /* rr_command validity check */ if (rr_command_check(len, rr, from, dst)) @@ -401,9 +407,8 @@ rr_command_input(int len, struct icmp6_router_renum *rr, return; /* do router renumbering */ - if (do_rr(len, rr)) { + if (do_rr(len, rr)) goto failed; - } /* update segnum */ RR_SET_SEGNUM(rro.rro_segnum_bits, rr->rr_segnum); @@ -417,27 +422,26 @@ rr_command_input(int len, struct icmp6_router_renum *rr, void rr_input(int len, struct icmp6_router_renum *rr, struct in6_pktinfo *pi, - struct sockaddr_in6 *from, struct in6_addr *dst) + struct sockaddr_in6 *from, struct in6_addr *dst) { u_char ntopbuf[2][INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ]; syslog(LOG_DEBUG, - "<%s> RR received from %s to %s on %s", - __func__, - inet_ntop(AF_INET6, &from->sin6_addr, - ntopbuf[0], INET6_ADDRSTRLEN), - inet_ntop(AF_INET6, &dst, ntopbuf[1], INET6_ADDRSTRLEN), - if_indextoname(pi->ipi6_ifindex, ifnamebuf)); + "<%s> RR received from %s to %s on %s", + __func__, + inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf[0] ,sizeof(ntopbuf[0])), + inet_ntop(AF_INET6, &dst, ntopbuf[1], sizeof(ntopbuf[1])), + if_indextoname(pi->ipi6_ifindex, ifnamebuf)); /* packet validation based on Section 4.1 of RFC2894 */ - if (len < sizeof(struct icmp6_router_renum)) { + if ((size_t)len < sizeof(struct icmp6_router_renum)) { syslog(LOG_NOTICE, - "<%s>: RR short message (size %d) from %s to %s on %s", - __func__, len, - inet_ntop(AF_INET6, &from->sin6_addr, - ntopbuf[0], INET6_ADDRSTRLEN), - inet_ntop(AF_INET6, &dst, ntopbuf[1], INET6_ADDRSTRLEN), - if_indextoname(pi->ipi6_ifindex, ifnamebuf)); + "<%s>: RR short message (size %d) from %s to %s on %s", + __func__, len, + inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf[0], + sizeof(ntopbuf[0])), + inet_ntop(AF_INET6, &dst, ntopbuf[1], sizeof(ntopbuf[1])), + if_indextoname(pi->ipi6_ifindex, ifnamebuf)); return; } @@ -449,16 +453,16 @@ rr_input(int len, struct icmp6_router_renum *rr, struct in6_pktinfo *pi, * We rely on the kernel input routine for unicast addresses, and thus * check multicast destinations only. */ - if (IN6_IS_ADDR_MULTICAST(&pi->ipi6_addr) && - !IN6_ARE_ADDR_EQUAL(&in6a_site_allrouters, &pi->ipi6_addr)) { + if (IN6_IS_ADDR_MULTICAST(&pi->ipi6_addr) && !IN6_ARE_ADDR_EQUAL( + &sin6_sitelocal_allrouters.sin6_addr, &pi->ipi6_addr)) { syslog(LOG_NOTICE, - "<%s>: RR message with invalid destination (%s) " - "from %s on %s", - __func__, - inet_ntop(AF_INET6, &dst, ntopbuf[0], INET6_ADDRSTRLEN), - inet_ntop(AF_INET6, &from->sin6_addr, - ntopbuf[1], INET6_ADDRSTRLEN), - if_indextoname(pi->ipi6_ifindex, ifnamebuf)); + "<%s>: RR message with invalid destination (%s) " + "from %s on %s", + __func__, + inet_ntop(AF_INET6, &dst, ntopbuf[0], sizeof(ntopbuf[0])), + inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf[1], + sizeof(ntopbuf[1])), + if_indextoname(pi->ipi6_ifindex, ifnamebuf)); return; } @@ -477,7 +481,7 @@ rr_input(int len, struct icmp6_router_renum *rr, struct in6_pktinfo *pi, break; default: syslog(LOG_ERR, "<%s> received unknown code %d", - __func__, rr->rr_code); + __func__, rr->rr_code); break; } diff --git a/usr.sbin/rtadvd/rrenum.h b/usr.sbin/rtadvd/rrenum.h index c358a2b..2b20d59 100644 --- a/usr.sbin/rtadvd/rrenum.h +++ b/usr.sbin/rtadvd/rrenum.h @@ -4,7 +4,7 @@ /* * Copyright (C) 1998 WIDE Project. * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -16,7 +16,7 @@ * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE diff --git a/usr.sbin/rtadvd/rtadvd.8 b/usr.sbin/rtadvd/rtadvd.8 index 7bc3064..5159624 100644 --- a/usr.sbin/rtadvd/rtadvd.8 +++ b/usr.sbin/rtadvd/rtadvd.8 @@ -37,9 +37,10 @@ .Nd router advertisement daemon .Sh SYNOPSIS .Nm -.Op Fl dDfMRs +.Op Fl dDfRs .Op Fl c Ar configfile .Op Fl F Ar dumpfile +.Op Fl M Ar ifname .Op Fl p Ar pidfile .Ar interface ... .Sh DESCRIPTION @@ -103,7 +104,7 @@ will not watch the routing table and the whole functionality described above will be suppressed. .Pp Basically, hosts MUST NOT send Router Advertisement messages at any -time (RFC 2461, Section 6.2.3). +time (RFC 4861, 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, @@ -176,7 +177,7 @@ In this case, .Nm will transmit router advertisement with router lifetime 0 to all the interfaces -.Pq in accordance with RFC2461 6.2.5 . +.Pq in accordance with RFC 4861 6.2.5 . .Sh FILES .Bl -tag -width Pa -compact .It Pa /etc/rtadvd.conf @@ -193,6 +194,34 @@ dumps its internal state. .Sh SEE ALSO .Xr rtadvd.conf 5 , .Xr rtsol 8 +.Rs +.%A Thomas Narten +.%A Erik Nordmark +.%A W. A. Simpson +.%A Hesham Soliman +.%T Neighbor Discovery for IP version 6 (IPv6) +.%R RFC 4861 +.Re +.Rs +.%A Thomas Narten +.%A Erik Nordmark +.%A W. A. Simpson +.%T Neighbor Discovery for IP version 6 (IPv6) +.%R RFC 2461 (obsoleted by RFC 4861) +.Re +.Rs +.%A Richard Draves +.%T Default Router Preferences and More-Specific Routes +.%R draft-ietf-ipngwg-router-selection-xx.txt +.Re +.Rs +.%A J. Jeong +.%A S. Park +.%A L. Beloeil +.%A S. Madanapalli +.%T IPv6 Router Advertisement Options for DNS Configuration +.%R RFC 6106 +.Re .Sh HISTORY The .Nm diff --git a/usr.sbin/rtadvd/rtadvd.c b/usr.sbin/rtadvd/rtadvd.c index 02e3dc7..614d109 100644 --- a/usr.sbin/rtadvd/rtadvd.c +++ b/usr.sbin/rtadvd/rtadvd.c @@ -4,7 +4,7 @@ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -16,7 +16,7 @@ * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -31,12 +31,15 @@ */ #include <sys/param.h> +#include <sys/ioctl.h> #include <sys/socket.h> #include <sys/uio.h> #include <sys/time.h> #include <sys/queue.h> +#include <sys/sysctl.h> #include <net/if.h> +#include <net/if_media.h> #include <net/route.h> #include <net/if_dl.h> #include <netinet/in.h> @@ -46,12 +49,17 @@ #include <arpa/inet.h> +#include <net/if_var.h> +#include <netinet/in_var.h> +#include <netinet6/nd6.h> + #include <time.h> #include <unistd.h> #include <stdio.h> #include <err.h> #include <errno.h> #include <libutil.h> +#include <netdb.h> #include <string.h> #include <stdlib.h> #include <syslog.h> @@ -66,6 +74,7 @@ #include "if.h" #include "config.h" #include "dump.h" +#include "pathnames.h" struct msghdr rcvmhdr; static u_char *rcvcmsgbuf; @@ -78,26 +87,27 @@ struct msghdr sndmhdr; struct iovec rcviov[2]; struct iovec sndiov[2]; struct sockaddr_in6 rcvfrom; -struct sockaddr_in6 sin6_allnodes = {sizeof(sin6_allnodes), AF_INET6}; -struct in6_addr in6a_site_allrouters; -static char *dumpfilename = "/var/run/rtadvd.dump"; -static char *pidfilename = "/var/run/rtadvd.pid"; +static const char *dumpfilename = _PATH_RTADVDDUMP; +static const char *pidfilename = _PATH_RTADVDPID; +const char *conffile = _PATH_RTADVDCONF; static struct pidfh *pfh; static char *mcastif; int sock; int rtsock = -1; int accept_rr = 0; int dflag = 0, sflag = 0; +static int ifl_len; +static char **ifl_names; -u_char *conffile = NULL; +struct railist_head_t railist = + TAILQ_HEAD_INITIALIZER(railist); -struct rainfo *ralist = NULL; struct nd_optlist { - struct nd_optlist *next; - struct nd_opt_hdr *opt; + TAILQ_ENTRY(nd_optlist) nol_next; + struct nd_opt_hdr *nol_opt; }; -union nd_opts { - struct nd_opt_hdr *nd_opt_array[9]; +union nd_opt { + struct nd_opt_hdr *opt_array[9]; struct { struct nd_opt_hdr *zero; struct nd_opt_hdr *src_lladdr; @@ -105,51 +115,76 @@ union nd_opts { struct nd_opt_prefix_info *pi; struct nd_opt_rd_hdr *rh; struct nd_opt_mtu *mtu; - struct nd_optlist *list; + TAILQ_HEAD(, nd_optlist) opt_list; } nd_opt_each; }; -#define nd_opts_src_lladdr nd_opt_each.src_lladdr -#define nd_opts_tgt_lladdr nd_opt_each.tgt_lladdr -#define nd_opts_pi nd_opt_each.pi -#define nd_opts_rh nd_opt_each.rh -#define nd_opts_mtu nd_opt_each.mtu -#define nd_opts_list nd_opt_each.list - -#define NDOPT_FLAG_SRCLINKADDR 0x1 -#define NDOPT_FLAG_TGTLINKADDR 0x2 -#define NDOPT_FLAG_PREFIXINFO 0x4 -#define NDOPT_FLAG_RDHDR 0x8 -#define NDOPT_FLAG_MTU 0x10 +#define opt_src_lladdr nd_opt_each.src_lladdr +#define opt_tgt_lladdr nd_opt_each.tgt_lladdr +#define opt_pi nd_opt_each.pi +#define opt_rh nd_opt_each.rh +#define opt_mtu nd_opt_each.mtu +#define opt_list nd_opt_each.opt_list + +#define NDOPT_FLAG_SRCLINKADDR (1 << 0) +#define NDOPT_FLAG_TGTLINKADDR (1 << 1) +#define NDOPT_FLAG_PREFIXINFO (1 << 2) +#define NDOPT_FLAG_RDHDR (1 << 3) +#define NDOPT_FLAG_MTU (1 << 4) +#define NDOPT_FLAG_RDNSS (1 << 5) +#define NDOPT_FLAG_DNSSL (1 << 6) u_int32_t ndopt_flags[] = { - 0, NDOPT_FLAG_SRCLINKADDR, NDOPT_FLAG_TGTLINKADDR, - NDOPT_FLAG_PREFIXINFO, NDOPT_FLAG_RDHDR, NDOPT_FLAG_MTU, + [ND_OPT_SOURCE_LINKADDR] = NDOPT_FLAG_SRCLINKADDR, + [ND_OPT_TARGET_LINKADDR] = NDOPT_FLAG_TGTLINKADDR, + [ND_OPT_PREFIX_INFORMATION] = NDOPT_FLAG_PREFIXINFO, + [ND_OPT_REDIRECTED_HEADER] = NDOPT_FLAG_RDHDR, + [ND_OPT_MTU] = NDOPT_FLAG_MTU, + [ND_OPT_RDNSS] = NDOPT_FLAG_RDNSS, + [ND_OPT_DNSSL] = NDOPT_FLAG_DNSSL, +}; + +struct sockaddr_in6 sin6_linklocal_allnodes = { + .sin6_len = sizeof(sin6_linklocal_allnodes), + .sin6_family = AF_INET6, + .sin6_addr = IN6ADDR_LINKLOCAL_ALLNODES_INIT, }; -int main(int, char *[]); -static void set_die(int); -static void die(void); -static void sock_open(void); -static void rtsock_open(void); -static void rtadvd_input(void); -static void rs_input(int, struct nd_router_solicit *, - struct in6_pktinfo *, struct sockaddr_in6 *); -static void ra_input(int, struct nd_router_advert *, - struct in6_pktinfo *, struct sockaddr_in6 *); -static int prefix_check(struct nd_opt_prefix_info *, struct rainfo *, - struct sockaddr_in6 *); -static int nd6_options(struct nd_opt_hdr *, int, - union nd_opts *, u_int32_t); -static void free_ndopts(union nd_opts *); -static void ra_output(struct rainfo *); -static void rtmsg_input(void); -static void rtadvd_set_dump_file(int); -static void set_short_delay(struct rainfo *); +struct sockaddr_in6 sin6_linklocal_allrouters = { + .sin6_len = sizeof(sin6_linklocal_allrouters), + .sin6_family = AF_INET6, + .sin6_addr = IN6ADDR_LINKLOCAL_ALLROUTERS_INIT, +}; + +struct sockaddr_in6 sin6_sitelocal_allrouters = { + .sin6_len = sizeof(sin6_sitelocal_allrouters), + .sin6_family = AF_INET6, + .sin6_addr = IN6ADDR_SITELOCAL_ALLROUTERS_INIT, +}; + +static void set_die(int); +static void die(void); +static void sock_open(void); +static void rtsock_open(void); +static void rtadvd_input(void); +static void rs_input(int, struct nd_router_solicit *, + struct in6_pktinfo *, struct sockaddr_in6 *); +static void ra_input(int, struct nd_router_advert *, + struct in6_pktinfo *, struct sockaddr_in6 *); +static int prefix_check(struct nd_opt_prefix_info *, struct rainfo *, + struct sockaddr_in6 *); +static int nd6_options(struct nd_opt_hdr *, int, + union nd_opt *, u_int32_t); +static void free_ndopts(union nd_opt *); +static void ra_output(struct rainfo *); +static void rtmsg_input(void); +static void rtadvd_set_dump_file(int); +static void set_short_delay(struct rainfo *); +static int ifl_lookup(char *, char **, int); +static int check_accept_rtadv(int); +static int getinet6sysctl(int); int -main(argc, argv) - int argc; - char *argv[]; +main(int argc, char *argv[]) { #ifdef HAVE_POLL_H struct pollfd set[2]; @@ -162,18 +197,19 @@ main(argc, argv) int i, ch; int fflag = 0, logopt; pid_t pid, otherpid; + int error; /* get command line options and arguments */ - while ((ch = getopt(argc, argv, "c:dDF:fMp:Rs")) != -1) { + while ((ch = getopt(argc, argv, "c:dDfF:M:p:Rs")) != -1) { switch (ch) { case 'c': conffile = optarg; break; case 'd': - dflag = 1; + dflag++; break; case 'D': - dflag = 2; + dflag += 2; break; case 'f': fflag = 1; @@ -202,8 +238,9 @@ main(argc, argv) argv += optind; if (argc == 0) { fprintf(stderr, - "usage: rtadvd [-dDfMRs] [-c conffile] " - "[-F dumpfile] [-p pidfile] interfaces...\n"); + "usage: rtadvd [-dDfRs] [-c conffile] " + "[-F dumpfile] [-M ifname] " + "[-p pidfile] interfaces...\n"); exit(1); } @@ -213,10 +250,12 @@ main(argc, argv) openlog("rtadvd", logopt, LOG_DAEMON); /* set log level */ - if (dflag == 0) - (void)setlogmask(LOG_UPTO(LOG_ERR)); - if (dflag == 1) + if (dflag > 1) + (void)setlogmask(LOG_UPTO(LOG_DEBUG)); + else if (dflag > 0) (void)setlogmask(LOG_UPTO(LOG_INFO)); + else + (void)setlogmask(LOG_UPTO(LOG_ERR)); /* timer initialization */ rtadvd_timer_init(); @@ -229,16 +268,26 @@ main(argc, argv) srandom((u_long)time(NULL)); #endif #endif - /* get iflist block from kernel */ init_iflist(); + ifl_names = argv; + ifl_len = argc; - while (argc--) - getconfig(*argv++); + for (i = 0; i < ifl_len; i++) { + int idx; - if (inet_pton(AF_INET6, ALLNODES, &sin6_allnodes.sin6_addr) != 1) { - fprintf(stderr, "fatal: inet_pton failed\n"); - exit(1); + idx = if_nametoindex(ifl_names[i]); + if (idx == 0) { + syslog(LOG_INFO, + "<%s> interface %s not found." + "Ignored at this moment.", __func__, ifl_names[i]); + continue; + } + error = getconfig(idx); + if (error) + syslog(LOG_INFO, + "<%s> invalid configuration for %s." + "Ignored at this moment.", __func__, ifl_names[i]); } pfh = pidfile_open(pidfilename, 0600, &otherpid); @@ -292,7 +341,6 @@ main(argc, argv) if (rtsock >= 0) FD_SET(rtsock, fdsetp); #endif - signal(SIGTERM, set_die); signal(SIGUSR1, rtadvd_set_dump_file); @@ -300,7 +348,6 @@ main(argc, argv) #ifndef HAVE_POLL_H memcpy(selectfdp, fdsetp, fdmasks); /* reinitialize */ #endif - if (do_dump) { /* SIGUSR1 */ do_dump = 0; rtadvd_dump_file(dumpfilename); @@ -325,7 +372,6 @@ main(argc, argv) "<%s> there's no timer. waiting for inputs", __func__); } - #ifdef HAVE_POLL_H if ((i = poll(set, 2, timeout ? (timeout->tv_sec * 1000 + timeout->tv_usec / 1000) : INFTIM)) < 0) @@ -358,75 +404,88 @@ main(argc, argv) exit(0); /* NOTREACHED */ } +static int +ifl_lookup(char *ifn, char **names, int len) +{ + while (len--) + if (strncmp(names[len], ifn, IFNAMSIZ) == 0) + return (0); + return (-1); +} + static void -rtadvd_set_dump_file(sig) - int sig; +rtadvd_set_dump_file(int sig __unused) { + do_dump = 1; } static void -set_die(sig) - int sig; +set_die(int sig __unused) { + do_die = 1; } static void -die() +die(void) { - struct rainfo *ra; + struct rainfo *rai; + struct rdnss *rdn; + struct dnssl *dns; int i; const int retrans = MAX_FINAL_RTR_ADVERTISEMENTS; - if (dflag > 1) { - syslog(LOG_DEBUG, "<%s> cease to be an advertising router\n", - __func__); - } + syslog(LOG_DEBUG, "<%s> cease to be an advertising router\n", + __func__); - for (ra = ralist; ra; ra = ra->next) { - ra->lifetime = 0; - make_packet(ra); + TAILQ_FOREACH(rai, &railist, rai_next) { + rai->rai_lifetime = 0; + TAILQ_FOREACH(rdn, &rai->rai_rdnss, rd_next) + rdn->rd_ltime = 0; + TAILQ_FOREACH(dns, &rai->rai_dnssl, dn_next) + dns->dn_ltime = 0; + make_packet(rai); } for (i = 0; i < retrans; i++) { - for (ra = ralist; ra; ra = ra->next) - ra_output(ra); + TAILQ_FOREACH(rai, &railist, rai_next) + ra_output(rai); sleep(MIN_DELAY_BETWEEN_RAS); } pidfile_remove(pfh); + exit(0); - /*NOTREACHED*/ } static void -rtmsg_input() +rtmsg_input(void) { int n, type, ifindex = 0, plen; size_t len; char msg[2048], *next, *lim; - u_char ifname[IF_NAMESIZE]; - struct prefix *prefix; + u_char ifname[IFNAMSIZ]; + struct if_announcemsghdr *ifan; + struct prefix *pfx; struct rainfo *rai; struct in6_addr *addr; char addrbuf[INET6_ADDRSTRLEN]; int prefixchange = 0; + int error; n = read(rtsock, msg, sizeof(msg)); - if (dflag > 1) { - syslog(LOG_DEBUG, "<%s> received a routing message " - "(type = %d, len = %d)", __func__, rtmsg_type(msg), n); - } + syslog(LOG_DEBUG, "<%s> received a routing message " + "(type = %d, len = %d)", __func__, rtmsg_type(msg), n); + if (n > rtmsg_len(msg)) { /* - * This usually won't happen for messages received on + * This usually won't happen for messages received on * a routing socket. */ - if (dflag > 1) - syslog(LOG_DEBUG, - "<%s> received data length is larger than " - "1st routing message len. multiple messages? " - "read %d bytes, but 1st msg len = %d", - __func__, n, rtmsg_len(msg)); + syslog(LOG_DEBUG, + "<%s> received data length is larger than " + "1st routing message len. multiple messages? " + "read %d bytes, but 1st msg len = %d", + __func__, n, rtmsg_len(msg)); #if 0 /* adjust length */ n = rtmsg_len(msg); @@ -438,11 +497,12 @@ rtmsg_input() int oldifflags; next = get_next_msg(next, lim, 0, &len, - RTADV_TYPE2BITMASK(RTM_ADD) | - RTADV_TYPE2BITMASK(RTM_DELETE) | - RTADV_TYPE2BITMASK(RTM_NEWADDR) | - RTADV_TYPE2BITMASK(RTM_DELADDR) | - RTADV_TYPE2BITMASK(RTM_IFINFO)); + RTADV_TYPE2BITMASK(RTM_ADD) | + RTADV_TYPE2BITMASK(RTM_DELETE) | + RTADV_TYPE2BITMASK(RTM_NEWADDR) | + RTADV_TYPE2BITMASK(RTM_DELADDR) | + RTADV_TYPE2BITMASK(RTM_IFINFO) | + RTADV_TYPE2BITMASK(RTM_IFANNOUNCE)); if (len == 0) break; type = rtmsg_type(next); @@ -458,25 +518,65 @@ rtmsg_input() case RTM_IFINFO: ifindex = get_ifm_ifindex(next); break; - default: - /* should not reach here */ - if (dflag > 1) { + case RTM_IFANNOUNCE: + ifan = (struct if_announcemsghdr *)next; + switch (ifan->ifan_what) { + case IFAN_ARRIVAL: + case IFAN_DEPARTURE: + break; + default: syslog(LOG_DEBUG, - "<%s:%d> unknown rtmsg %d on %s", - __func__, __LINE__, type, - if_indextoname(ifindex, ifname)); + "<%s:%d> unknown ifan msg (ifan_what=%d)", + __func__, __LINE__, ifan->ifan_what); + continue; + } + + syslog(LOG_INFO, "<%s>: if_announcemsg (idx=%d:%d)", + __func__, ifan->ifan_index, ifan->ifan_what); + init_iflist(); + error = ifl_lookup(ifan->ifan_name, + ifl_names, ifl_len); + if (error) { + syslog(LOG_INFO, "<%s>: not a target " + "interface (idx=%d)", __func__, + ifan->ifan_index); + continue; } + + switch (ifan->ifan_what) { + case IFAN_ARRIVAL: + error = getconfig(ifan->ifan_index); + if (error) + syslog(LOG_ERR, + "<%s>: getconfig failed (idx=%d)" + " Ignored.", __func__, + ifan->ifan_index); + break; + case IFAN_DEPARTURE: + error = rmconfig(ifan->ifan_index); + if (error) + syslog(LOG_ERR, + "<%s>: rmconfig failed (idx=%d)" + " Ignored.", __func__, + ifan->ifan_index); + break; + } + continue; + default: + /* should not reach here */ + syslog(LOG_DEBUG, + "<%s:%d> unknown rtmsg %d on %s", + __func__, __LINE__, type, + if_indextoname(ifindex, ifname)); continue; } if ((rai = if_indextorainfo(ifindex)) == NULL) { - if (dflag > 1) { - syslog(LOG_DEBUG, - "<%s> route changed on " - "non advertising interface(%s)", - __func__, - if_indextoname(ifindex, ifname)); - } + syslog(LOG_DEBUG, + "<%s> route changed on " + "non advertising interface(%s)", + __func__, + if_indextoname(ifindex, ifname)); continue; } oldifflags = iflist[ifindex]->ifm_flags; @@ -500,25 +600,25 @@ rtmsg_input() __func__, plen); break; } - prefix = find_prefix(rai, addr, plen); - if (prefix) { - if (prefix->timer) { + pfx = find_prefix(rai, addr, plen); + if (pfx) { + if (pfx->pfx_timer) { /* * If the prefix has been invalidated, * make it available again. */ - update_prefix(prefix); + update_prefix(pfx); prefixchange = 1; - } else if (dflag > 1) { + } else syslog(LOG_DEBUG, "<%s> new prefix(%s/%d) " "added on %s, " "but it was already in list", __func__, inet_ntop(AF_INET6, addr, - (char *)addrbuf, INET6_ADDRSTRLEN), - plen, rai->ifname); - } + (char *)addrbuf, + sizeof(addrbuf)), + plen, rai->rai_ifname); break; } make_prefix(rai, ifindex, addr, plen); @@ -543,21 +643,17 @@ rtmsg_input() __func__, plen); break; } - prefix = find_prefix(rai, addr, plen); - if (prefix == NULL) { - if (dflag > 1) { - syslog(LOG_DEBUG, - "<%s> prefix(%s/%d) was " - "deleted on %s, " - "but it was not in list", - __func__, - inet_ntop(AF_INET6, addr, - (char *)addrbuf, INET6_ADDRSTRLEN), - plen, rai->ifname); - } + pfx = find_prefix(rai, addr, plen); + if (pfx == NULL) { + syslog(LOG_DEBUG, + "<%s> prefix(%s/%d) was deleted on %s, " + "but it was not in list", + __func__, inet_ntop(AF_INET6, addr, + (char *)addrbuf, sizeof(addrbuf)), + plen, rai->rai_ifname); break; } - invalidate_prefix(prefix); + invalidate_prefix(pfx); prefixchange = 1; break; case RTM_NEWADDR: @@ -571,12 +667,10 @@ rtmsg_input() break; default: /* should not reach here */ - if (dflag > 1) { - syslog(LOG_DEBUG, - "<%s:%d> unknown rtmsg %d on %s", - __func__, __LINE__, type, - if_indextoname(ifindex, ifname)); - } + syslog(LOG_DEBUG, + "<%s:%d> unknown rtmsg %d on %s", + __func__, __LINE__, type, + if_indextoname(ifindex, ifname)); return; } @@ -585,27 +679,29 @@ rtmsg_input() !(iflist[ifindex]->ifm_flags & IFF_UP)) { syslog(LOG_INFO, "<%s> interface %s becomes down. stop timer.", - __func__, rai->ifname); - rtadvd_remove_timer(&rai->timer); + __func__, rai->rai_ifname); + rtadvd_remove_timer(rai->rai_timer); + rai->rai_timer = NULL; } else if (!(oldifflags & IFF_UP) && /* DOWN to UP */ - (iflist[ifindex]->ifm_flags & IFF_UP)) { + (iflist[ifindex]->ifm_flags & IFF_UP)) { syslog(LOG_INFO, "<%s> interface %s becomes up. restart timer.", - __func__, rai->ifname); + __func__, rai->rai_ifname); - rai->initcounter = 0; /* reset the counter */ - rai->waiting = 0; /* XXX */ - rai->timer = rtadvd_add_timer(ra_timeout, + rai->rai_initcounter = 0; /* reset the counter */ + rai->rai_waiting = 0; /* XXX */ + rai->rai_timer = rtadvd_add_timer(ra_timeout, ra_timer_update, rai, rai); - ra_timer_update((void *)rai, &rai->timer->tm); - rtadvd_set_timer(&rai->timer->tm, rai->timer); + ra_timer_update(rai, &rai->rai_timer->rat_tm); + rtadvd_set_timer(&rai->rai_timer->rat_tm, + rai->rai_timer); } else if (prefixchange && (iflist[ifindex]->ifm_flags & IFF_UP)) { /* * An advertised prefix has been added or invalidated. * Will notice the change in a short delay. */ - rai->initcounter = 0; + rai->rai_initcounter = 0; set_short_delay(rai); } } @@ -614,13 +710,13 @@ rtmsg_input() } void -rtadvd_input() +rtadvd_input(void) { - int i; + ssize_t i; int *hlimp = NULL; #ifdef OLDRAWSOCKET struct ip6_hdr *ip; -#endif +#endif struct icmp6_hdr *icp; int ifindex = 0; struct cmsghdr *cm; @@ -655,14 +751,14 @@ rtadvd_input() } if (ifindex == 0) { syslog(LOG_ERR, - "<%s> failed to get receiving interface", - __func__); + "<%s> failed to get receiving interface", + __func__); return; } if (hlimp == NULL) { syslog(LOG_ERR, - "<%s> failed to get receiving hop limit", - __func__); + "<%s> failed to get receiving hop limit", + __func__); return; } @@ -673,28 +769,28 @@ rtadvd_input() if (iflist[pi->ipi6_ifindex] == NULL || (iflist[pi->ipi6_ifindex]->ifm_flags & IFF_UP) == 0) { syslog(LOG_INFO, - "<%s> received data on a disabled interface (%s)", - __func__, - (iflist[pi->ipi6_ifindex] == NULL) ? "[gone]" : - if_indextoname(pi->ipi6_ifindex, ifnamebuf)); + "<%s> received data on a disabled interface (%s)", + __func__, + (iflist[pi->ipi6_ifindex] == NULL) ? "[gone]" : + if_indextoname(pi->ipi6_ifindex, ifnamebuf)); return; } #ifdef OLDRAWSOCKET - if (i < sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr)) { + if ((size_t)i < sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr)) { syslog(LOG_ERR, - "<%s> packet size(%d) is too short", - __func__, i); + "<%s> packet size(%d) is too short", + __func__, i); return; } ip = (struct ip6_hdr *)rcvmhdr.msg_iov[0].iov_base; icp = (struct icmp6_hdr *)(ip + 1); /* XXX: ext. hdr? */ #else - if (i < sizeof(struct icmp6_hdr)) { + if ((size_t)i < sizeof(struct icmp6_hdr)) { syslog(LOG_ERR, - "<%s> packet size(%d) is too short", - __func__, i); + "<%s> packet size(%d) is too short", + __func__, i); return; } @@ -704,7 +800,7 @@ rtadvd_input() switch (icp->icmp6_type) { case ND_ROUTER_SOLICIT: /* - * Message verification - RFC-2461 6.1.1 + * Message verification - RFC 4861 6.1.1 * XXX: these checks must be done in the kernel as well, * but we can't completely rely on them. */ @@ -714,7 +810,7 @@ rtadvd_input() "received from %s on %s", __func__, *hlimp, inet_ntop(AF_INET6, &rcvfrom.sin6_addr, ntopbuf, - INET6_ADDRSTRLEN), + sizeof(ntopbuf)), if_indextoname(pi->ipi6_ifindex, ifnamebuf)); return; } @@ -724,17 +820,17 @@ rtadvd_input() "received from %s on %s", __func__, icp->icmp6_code, inet_ntop(AF_INET6, &rcvfrom.sin6_addr, ntopbuf, - INET6_ADDRSTRLEN), + sizeof(ntopbuf)), if_indextoname(pi->ipi6_ifindex, ifnamebuf)); return; } - if (i < sizeof(struct nd_router_solicit)) { + if ((size_t)i < sizeof(struct nd_router_solicit)) { syslog(LOG_NOTICE, "<%s> RS from %s on %s does not have enough " "length (len = %d)", __func__, inet_ntop(AF_INET6, &rcvfrom.sin6_addr, ntopbuf, - INET6_ADDRSTRLEN), + sizeof(ntopbuf)), if_indextoname(pi->ipi6_ifindex, ifnamebuf), i); return; } @@ -742,16 +838,25 @@ rtadvd_input() break; case ND_ROUTER_ADVERT: /* - * Message verification - RFC-2461 6.1.2 - * XXX: there's a same dilemma as above... + * Message verification - RFC 4861 6.1.2 + * XXX: there's the same dilemma as above... */ + if (!IN6_IS_ADDR_LINKLOCAL(&rcvfrom.sin6_addr)) { + syslog(LOG_NOTICE, + "<%s> RA witn non-linklocal source address " + "received from %s on %s", + __func__, inet_ntop(AF_INET6, &rcvfrom.sin6_addr, + ntopbuf, sizeof(ntopbuf)), + if_indextoname(pi->ipi6_ifindex, ifnamebuf)); + return; + } if (*hlimp != 255) { syslog(LOG_NOTICE, "<%s> RA with invalid hop limit(%d) " "received from %s on %s", __func__, *hlimp, inet_ntop(AF_INET6, &rcvfrom.sin6_addr, ntopbuf, - INET6_ADDRSTRLEN), + sizeof(ntopbuf)), if_indextoname(pi->ipi6_ifindex, ifnamebuf)); return; } @@ -761,17 +866,17 @@ rtadvd_input() "received from %s on %s", __func__, icp->icmp6_code, inet_ntop(AF_INET6, &rcvfrom.sin6_addr, ntopbuf, - INET6_ADDRSTRLEN), + sizeof(ntopbuf)), if_indextoname(pi->ipi6_ifindex, ifnamebuf)); return; } - if (i < sizeof(struct nd_router_advert)) { + if ((size_t)i < sizeof(struct nd_router_advert)) { syslog(LOG_NOTICE, "<%s> RA from %s on %s does not have enough " "length (len = %d)", __func__, inet_ntop(AF_INET6, &rcvfrom.sin6_addr, ntopbuf, - INET6_ADDRSTRLEN), + sizeof(ntopbuf)), if_indextoname(pi->ipi6_ifindex, ifnamebuf), i); return; } @@ -785,7 +890,7 @@ rtadvd_input() break; } rr_input(i, (struct icmp6_router_renum *)icp, pi, &rcvfrom, - &dst); + &dst); break; default: /* @@ -806,17 +911,17 @@ static void rs_input(int len, struct nd_router_solicit *rs, struct in6_pktinfo *pi, struct sockaddr_in6 *from) { - u_char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ]; - union nd_opts ndopts; - struct rainfo *ra; + u_char ntopbuf[INET6_ADDRSTRLEN]; + u_char ifnamebuf[IFNAMSIZ]; + union nd_opt ndopts; + struct rainfo *rai; struct soliciter *sol; syslog(LOG_DEBUG, - "<%s> RS received from %s on %s", - __func__, - inet_ntop(AF_INET6, &from->sin6_addr, - ntopbuf, INET6_ADDRSTRLEN), - if_indextoname(pi->ipi6_ifindex, ifnamebuf)); + "<%s> RS received from %s on %s", + __func__, + inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, sizeof(ntopbuf)), + if_indextoname(pi->ipi6_ifindex, ifnamebuf)); /* ND option check */ memset(&ndopts, 0, sizeof(ndopts)); @@ -824,36 +929,33 @@ rs_input(int len, struct nd_router_solicit *rs, len - sizeof(struct nd_router_solicit), &ndopts, NDOPT_FLAG_SRCLINKADDR)) { syslog(LOG_INFO, - "<%s> ND option check failed for an RS from %s on %s", - __func__, - inet_ntop(AF_INET6, &from->sin6_addr, - ntopbuf, INET6_ADDRSTRLEN), - if_indextoname(pi->ipi6_ifindex, ifnamebuf)); + "<%s> ND option check failed for an RS from %s on %s", + __func__, + inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, + sizeof(ntopbuf)), + if_indextoname(pi->ipi6_ifindex, ifnamebuf)); return; } /* * If the IP source address is the unspecified address, there * must be no source link-layer address option in the message. - * (RFC-2461 6.1.1) + * (RFC 4861 6.1.1) */ if (IN6_IS_ADDR_UNSPECIFIED(&from->sin6_addr) && - ndopts.nd_opts_src_lladdr) { + ndopts.opt_src_lladdr) { syslog(LOG_INFO, - "<%s> RS from unspecified src on %s has a link-layer" - " address option", - __func__, - if_indextoname(pi->ipi6_ifindex, ifnamebuf)); + "<%s> RS from unspecified src on %s has a link-layer" + " address option", + __func__, if_indextoname(pi->ipi6_ifindex, ifnamebuf)); goto done; } - ra = ralist; - while (ra != NULL) { - if (pi->ipi6_ifindex == ra->ifindex) + TAILQ_FOREACH(rai, &railist, rai_next) + if (pi->ipi6_ifindex == (unsigned int)rai->rai_ifindex) break; - ra = ra->next; - } - if (ra == NULL) { + + if (rai == NULL) { syslog(LOG_INFO, "<%s> RS received on non advertising interface(%s)", __func__, @@ -861,7 +963,7 @@ rs_input(int len, struct nd_router_solicit *rs, goto done; } - ra->rsinput++; /* increment statistics */ + rai->rai_rsinput++; /* increment statistics */ /* * Decide whether to send RA according to the rate-limit @@ -871,21 +973,20 @@ rs_input(int len, struct nd_router_solicit *rs, /* record sockaddr waiting for RA, if possible */ sol = (struct soliciter *)malloc(sizeof(*sol)); if (sol) { - sol->addr = *from; - /* XXX RFC2553 need clarification on flowinfo */ - sol->addr.sin6_flowinfo = 0; - sol->next = ra->soliciter; - ra->soliciter = sol; + sol->sol_addr = *from; + /* XXX RFC 2553 need clarification on flowinfo */ + sol->sol_addr.sin6_flowinfo = 0; + TAILQ_INSERT_TAIL(&rai->rai_soliciter, sol, sol_next); } /* * If there is already a waiting RS packet, don't * update the timer. */ - if (ra->waiting++) + if (rai->rai_waiting++) goto done; - set_short_delay(ra); + set_short_delay(rai); done: free_ndopts(&ndopts); @@ -893,8 +994,7 @@ rs_input(int len, struct nd_router_solicit *rs, } static void -set_short_delay(rai) - struct rainfo *rai; +set_short_delay(struct rainfo *rai) { long delay; /* must not be greater than 1000000 */ struct timeval interval, now, min_delay, tm_tmp, *rest; @@ -904,7 +1004,7 @@ set_short_delay(rai) * corresponds to a time later than the time the next * multicast RA is scheduled to be sent, ignore the random * delay and send the advertisement at the - * already-scheduled time. RFC-2461 6.2.6 + * already-scheduled time. RFC 4861 6.2.6 */ #ifdef HAVE_ARC4RANDOM delay = arc4random_uniform(MAX_RA_DELAY_TIME); @@ -913,8 +1013,8 @@ set_short_delay(rai) #endif interval.tv_sec = 0; interval.tv_usec = delay; - rest = rtadvd_timer_rest(rai->timer); - if (TIMEVAL_LT(*rest, interval)) { + rest = rtadvd_timer_rest(rai->rai_timer); + if (TIMEVAL_LT(rest, &interval)) { syslog(LOG_DEBUG, "<%s> random delay is larger than " "the rest of the current timer", __func__); interval = *rest; @@ -928,170 +1028,217 @@ set_short_delay(rai) * previous advertisement was sent. */ gettimeofday(&now, NULL); - TIMEVAL_SUB(&now, &rai->lastsent, &tm_tmp); + TIMEVAL_SUB(&now, &rai->rai_lastsent, &tm_tmp); min_delay.tv_sec = MIN_DELAY_BETWEEN_RAS; min_delay.tv_usec = 0; - if (TIMEVAL_LT(tm_tmp, min_delay)) { + if (TIMEVAL_LT(&tm_tmp, &min_delay)) { TIMEVAL_SUB(&min_delay, &tm_tmp, &min_delay); TIMEVAL_ADD(&min_delay, &interval, &interval); } - rtadvd_set_timer(&interval, rai->timer); + rtadvd_set_timer(&interval, rai->rai_timer); +} + +static int +check_accept_rtadv(int idx) +{ + struct in6_ndireq nd; + u_char ifname[IFNAMSIZ]; + int s6; + int error; + + if ((s6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + syslog(LOG_ERR, + "<%s> open socket failed for idx=%d.", + __func__, idx); + return (0); + } + if ((if_indextoname(idx, ifname)) == NULL) { + syslog(LOG_ERR, + "<%s> ifindex->ifname failed (idx=%d).", + __func__, idx); + close(s6); + return (0); + } + memset(&nd, 0, sizeof(nd)); + strncpy(nd.ifname, ifname, sizeof(nd.ifname)); + error = ioctl(s6, SIOCGIFINFO_IN6, &nd); + if (error) { + syslog(LOG_ERR, + "<%s> ioctl(SIOCGIFINFO_IN6) failed for idx=%d.", + __func__, idx); + nd.ndi.flags = 0; + } + close(s6); + + return (nd.ndi.flags & ND6_IFF_ACCEPT_RTADV); +} + +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", + __func__, code, + strerror(errno)); + return (-1); + } + else + return (value); } static void -ra_input(int len, struct nd_router_advert *ra, +ra_input(int len, struct nd_router_advert *nra, struct in6_pktinfo *pi, struct sockaddr_in6 *from) { struct rainfo *rai; - u_char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ]; - union nd_opts ndopts; - char *on_off[] = {"OFF", "ON"}; + u_char ntopbuf[INET6_ADDRSTRLEN]; + u_char ifnamebuf[IFNAMSIZ]; + union nd_opt ndopts; + const char *on_off[] = {"OFF", "ON"}; u_int32_t reachabletime, retranstimer, mtu; int inconsistent = 0; + int error; + + syslog(LOG_DEBUG, "<%s> RA received from %s on %s", __func__, + inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, sizeof(ntopbuf)), + if_indextoname(pi->ipi6_ifindex, ifnamebuf)); + + if (!check_accept_rtadv(pi->ipi6_ifindex)) { + syslog(LOG_INFO, + "<%s> An RA from %s on %s ignored (no ACCEPT_RTADV flag).", + __func__, + inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, + sizeof(ntopbuf)), if_indextoname(pi->ipi6_ifindex, + ifnamebuf)); + return; + } - syslog(LOG_DEBUG, - "<%s> RA received from %s on %s", - __func__, - inet_ntop(AF_INET6, &from->sin6_addr, - ntopbuf, INET6_ADDRSTRLEN), - if_indextoname(pi->ipi6_ifindex, ifnamebuf)); - /* ND option check */ memset(&ndopts, 0, sizeof(ndopts)); - if (nd6_options((struct nd_opt_hdr *)(ra + 1), - len - sizeof(struct nd_router_advert), - &ndopts, NDOPT_FLAG_SRCLINKADDR | - NDOPT_FLAG_PREFIXINFO | NDOPT_FLAG_MTU)) { + error = nd6_options((struct nd_opt_hdr *)(nra + 1), + len - sizeof(struct nd_router_advert), &ndopts, + NDOPT_FLAG_SRCLINKADDR | NDOPT_FLAG_PREFIXINFO | NDOPT_FLAG_MTU | + NDOPT_FLAG_RDNSS | NDOPT_FLAG_DNSSL); + if (error) { syslog(LOG_INFO, - "<%s> ND option check failed for an RA from %s on %s", - __func__, - inet_ntop(AF_INET6, &from->sin6_addr, - ntopbuf, INET6_ADDRSTRLEN), - if_indextoname(pi->ipi6_ifindex, ifnamebuf)); + "<%s> ND option check failed for an RA from %s on %s", + __func__, + inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, + sizeof(ntopbuf)), if_indextoname(pi->ipi6_ifindex, + ifnamebuf)); return; } /* - * RA consistency check according to RFC-2461 6.2.7 + * RA consistency check according to RFC 4861 6.2.7 */ - if ((rai = if_indextorainfo(pi->ipi6_ifindex)) == 0) { + rai = if_indextorainfo(pi->ipi6_ifindex); + if (rai == NULL) { syslog(LOG_INFO, - "<%s> received RA from %s on non-advertising" - " interface(%s)", - __func__, - inet_ntop(AF_INET6, &from->sin6_addr, - ntopbuf, INET6_ADDRSTRLEN), - if_indextoname(pi->ipi6_ifindex, ifnamebuf)); + "<%s> received RA from %s on non-advertising" + " interface(%s)", + __func__, + inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, + sizeof(ntopbuf)), if_indextoname(pi->ipi6_ifindex, + ifnamebuf)); goto done; } - rai->rainput++; /* increment statistics */ - + rai->rai_rainput++; /* increment statistics */ + /* Cur Hop Limit value */ - if (ra->nd_ra_curhoplimit && rai->hoplimit && - ra->nd_ra_curhoplimit != rai->hoplimit) { + if (nra->nd_ra_curhoplimit && rai->rai_hoplimit && + nra->nd_ra_curhoplimit != rai->rai_hoplimit) { syslog(LOG_INFO, - "<%s> CurHopLimit inconsistent on %s:" - " %d from %s, %d from us", - __func__, - rai->ifname, - ra->nd_ra_curhoplimit, - inet_ntop(AF_INET6, &from->sin6_addr, - ntopbuf, INET6_ADDRSTRLEN), - rai->hoplimit); + "<%s> CurHopLimit inconsistent on %s:" + " %d from %s, %d from us", + __func__, rai->rai_ifname, nra->nd_ra_curhoplimit, + inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, + sizeof(ntopbuf)), rai->rai_hoplimit); inconsistent++; } /* M flag */ - if ((ra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) != - rai->managedflg) { + if ((nra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) != + rai->rai_managedflg) { syslog(LOG_INFO, - "<%s> M flag inconsistent on %s:" - " %s from %s, %s from us", - __func__, - rai->ifname, - on_off[!rai->managedflg], - inet_ntop(AF_INET6, &from->sin6_addr, - ntopbuf, INET6_ADDRSTRLEN), - on_off[rai->managedflg]); + "<%s> M flag inconsistent on %s:" + " %s from %s, %s from us", + __func__, rai->rai_ifname, on_off[!rai->rai_managedflg], + inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, + sizeof(ntopbuf)), on_off[rai->rai_managedflg]); inconsistent++; } /* O flag */ - if ((ra->nd_ra_flags_reserved & ND_RA_FLAG_OTHER) != - rai->otherflg) { + if ((nra->nd_ra_flags_reserved & ND_RA_FLAG_OTHER) != + rai->rai_otherflg) { syslog(LOG_INFO, - "<%s> O flag inconsistent on %s:" - " %s from %s, %s from us", - __func__, - rai->ifname, - on_off[!rai->otherflg], - inet_ntop(AF_INET6, &from->sin6_addr, - ntopbuf, INET6_ADDRSTRLEN), - on_off[rai->otherflg]); + "<%s> O flag inconsistent on %s:" + " %s from %s, %s from us", + __func__, rai->rai_ifname, on_off[!rai->rai_otherflg], + inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, + sizeof(ntopbuf)), on_off[rai->rai_otherflg]); inconsistent++; } /* Reachable Time */ - reachabletime = ntohl(ra->nd_ra_reachable); - if (reachabletime && rai->reachabletime && - reachabletime != rai->reachabletime) { + reachabletime = ntohl(nra->nd_ra_reachable); + if (reachabletime && rai->rai_reachabletime && + reachabletime != rai->rai_reachabletime) { syslog(LOG_INFO, - "<%s> ReachableTime inconsistent on %s:" - " %d from %s, %d from us", - __func__, - rai->ifname, - reachabletime, - inet_ntop(AF_INET6, &from->sin6_addr, - ntopbuf, INET6_ADDRSTRLEN), - rai->reachabletime); + "<%s> ReachableTime inconsistent on %s:" + " %d from %s, %d from us", + __func__, rai->rai_ifname, reachabletime, + inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, + sizeof(ntopbuf)), rai->rai_reachabletime); inconsistent++; } /* Retrans Timer */ - retranstimer = ntohl(ra->nd_ra_retransmit); - if (retranstimer && rai->retranstimer && - retranstimer != rai->retranstimer) { + retranstimer = ntohl(nra->nd_ra_retransmit); + if (retranstimer && rai->rai_retranstimer && + retranstimer != rai->rai_retranstimer) { syslog(LOG_INFO, - "<%s> RetranceTimer inconsistent on %s:" - " %d from %s, %d from us", - __func__, - rai->ifname, - retranstimer, - inet_ntop(AF_INET6, &from->sin6_addr, - ntopbuf, INET6_ADDRSTRLEN), - rai->retranstimer); + "<%s> RetranceTimer inconsistent on %s:" + " %d from %s, %d from us", + __func__, rai->rai_ifname, retranstimer, + inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, + sizeof(ntopbuf)), rai->rai_retranstimer); inconsistent++; } /* Values in the MTU options */ - if (ndopts.nd_opts_mtu) { - mtu = ntohl(ndopts.nd_opts_mtu->nd_opt_mtu_mtu); - if (mtu && rai->linkmtu && mtu != rai->linkmtu) { + if (ndopts.opt_mtu) { + mtu = ntohl(ndopts.opt_mtu->nd_opt_mtu_mtu); + if (mtu && rai->rai_linkmtu && mtu != rai->rai_linkmtu) { syslog(LOG_INFO, - "<%s> MTU option value inconsistent on %s:" - " %d from %s, %d from us", - __func__, - rai->ifname, mtu, - inet_ntop(AF_INET6, &from->sin6_addr, - ntopbuf, INET6_ADDRSTRLEN), - rai->linkmtu); + "<%s> MTU option value inconsistent on %s:" + " %d from %s, %d from us", + __func__, rai->rai_ifname, mtu, + inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, + sizeof(ntopbuf)), rai->rai_linkmtu); inconsistent++; } } /* Preferred and Valid Lifetimes for prefixes */ { - struct nd_optlist *optp = ndopts.nd_opts_list; + struct nd_optlist *nol; - if (ndopts.nd_opts_pi) { - if (prefix_check(ndopts.nd_opts_pi, rai, from)) + if (ndopts.opt_pi) + if (prefix_check(ndopts.opt_pi, rai, from)) inconsistent++; - } - while (optp) { - if (prefix_check((struct nd_opt_prefix_info *)optp->opt, - rai, from)) + + TAILQ_FOREACH(nol, &ndopts.opt_list, nol_next) + if (prefix_check((struct nd_opt_prefix_info *)nol->nol_opt, + rai, from)) inconsistent++; - optp = optp->next; - } } if (inconsistent) - rai->rainconsistent++; - + rai->rai_rainconsistent++; + done: free_ndopts(&ndopts); return; @@ -1100,51 +1247,49 @@ ra_input(int len, struct nd_router_advert *ra, /* return a non-zero value if the received prefix is inconsitent with ours */ static int prefix_check(struct nd_opt_prefix_info *pinfo, - struct rainfo *rai, struct sockaddr_in6 *from) + struct rainfo *rai, struct sockaddr_in6 *from) { u_int32_t preferred_time, valid_time; - struct prefix *pp; + struct prefix *pfx; int inconsistent = 0; - u_char ntopbuf[INET6_ADDRSTRLEN], prefixbuf[INET6_ADDRSTRLEN]; + u_char ntopbuf[INET6_ADDRSTRLEN]; + u_char prefixbuf[INET6_ADDRSTRLEN]; struct timeval now; #if 0 /* impossible */ if (pinfo->nd_opt_pi_type != ND_OPT_PREFIX_INFORMATION) - return(0); + return (0); #endif /* * log if the adveritsed prefix has link-local scope(sanity check?) */ - if (IN6_IS_ADDR_LINKLOCAL(&pinfo->nd_opt_pi_prefix)) { + if (IN6_IS_ADDR_LINKLOCAL(&pinfo->nd_opt_pi_prefix)) syslog(LOG_INFO, - "<%s> link-local prefix %s/%d is advertised " - "from %s on %s", - __func__, - inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix, - prefixbuf, INET6_ADDRSTRLEN), - pinfo->nd_opt_pi_prefix_len, - inet_ntop(AF_INET6, &from->sin6_addr, - ntopbuf, INET6_ADDRSTRLEN), - rai->ifname); - } - - if ((pp = find_prefix(rai, &pinfo->nd_opt_pi_prefix, - pinfo->nd_opt_pi_prefix_len)) == NULL) { + "<%s> link-local prefix %s/%d is advertised " + "from %s on %s", + __func__, + inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix, prefixbuf, + sizeof(prefixbuf)), + pinfo->nd_opt_pi_prefix_len, + inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, + sizeof(ntopbuf)), rai->rai_ifname); + + if ((pfx = find_prefix(rai, &pinfo->nd_opt_pi_prefix, + pinfo->nd_opt_pi_prefix_len)) == NULL) { syslog(LOG_INFO, - "<%s> prefix %s/%d from %s on %s is not in our list", - __func__, - inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix, - prefixbuf, INET6_ADDRSTRLEN), - pinfo->nd_opt_pi_prefix_len, - inet_ntop(AF_INET6, &from->sin6_addr, - ntopbuf, INET6_ADDRSTRLEN), - rai->ifname); - return(0); + "<%s> prefix %s/%d from %s on %s is not in our list", + __func__, + inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix, prefixbuf, + sizeof(prefixbuf)), + pinfo->nd_opt_pi_prefix_len, + inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, + sizeof(ntopbuf)), rai->rai_ifname); + return (0); } preferred_time = ntohl(pinfo->nd_opt_pi_preferred_time); - if (pp->pltimeexpire) { + if (pfx->pfx_pltimeexpire) { /* * The lifetime is decremented in real time, so we should * compare the expiration time. @@ -1155,134 +1300,135 @@ prefix_check(struct nd_opt_prefix_info *pinfo, gettimeofday(&now, NULL); preferred_time += now.tv_sec; - if (!pp->timer && rai->clockskew && - abs(preferred_time - pp->pltimeexpire) > rai->clockskew) { + if (!pfx->pfx_timer && rai->rai_clockskew && + abs(preferred_time - pfx->pfx_pltimeexpire) > rai->rai_clockskew) { syslog(LOG_INFO, - "<%s> preferred lifetime for %s/%d" - " (decr. in real time) inconsistent on %s:" - " %d from %s, %ld from us", - __func__, - inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix, - prefixbuf, INET6_ADDRSTRLEN), - pinfo->nd_opt_pi_prefix_len, - rai->ifname, preferred_time, - inet_ntop(AF_INET6, &from->sin6_addr, - ntopbuf, INET6_ADDRSTRLEN), - pp->pltimeexpire); + "<%s> preferred lifetime for %s/%d" + " (decr. in real time) inconsistent on %s:" + " %d from %s, %ld from us", + __func__, + inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix, prefixbuf, + sizeof(prefixbuf)), + pinfo->nd_opt_pi_prefix_len, + rai->rai_ifname, preferred_time, + inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, + sizeof(ntopbuf)), pfx->pfx_pltimeexpire); inconsistent++; } - } else if (!pp->timer && preferred_time != pp->preflifetime) { + } else if (!pfx->pfx_timer && preferred_time != pfx->pfx_preflifetime) syslog(LOG_INFO, - "<%s> preferred lifetime for %s/%d" - " inconsistent on %s:" - " %d from %s, %d from us", - __func__, - inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix, - prefixbuf, INET6_ADDRSTRLEN), - pinfo->nd_opt_pi_prefix_len, - rai->ifname, preferred_time, - inet_ntop(AF_INET6, &from->sin6_addr, - ntopbuf, INET6_ADDRSTRLEN), - pp->preflifetime); - } + "<%s> preferred lifetime for %s/%d" + " inconsistent on %s:" + " %d from %s, %d from us", + __func__, + inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix, prefixbuf, + sizeof(prefixbuf)), + pinfo->nd_opt_pi_prefix_len, + rai->rai_ifname, preferred_time, + inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, + sizeof(ntopbuf)), pfx->pfx_preflifetime); valid_time = ntohl(pinfo->nd_opt_pi_valid_time); - if (pp->vltimeexpire) { + if (pfx->pfx_vltimeexpire) { gettimeofday(&now, NULL); valid_time += now.tv_sec; - if (!pp->timer && rai->clockskew && - abs(valid_time - pp->vltimeexpire) > rai->clockskew) { + if (!pfx->pfx_timer && rai->rai_clockskew && + abs(valid_time - pfx->pfx_vltimeexpire) > rai->rai_clockskew) { syslog(LOG_INFO, - "<%s> valid lifetime for %s/%d" - " (decr. in real time) inconsistent on %s:" - " %d from %s, %ld from us", - __func__, - inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix, - prefixbuf, INET6_ADDRSTRLEN), - pinfo->nd_opt_pi_prefix_len, - rai->ifname, preferred_time, - inet_ntop(AF_INET6, &from->sin6_addr, - ntopbuf, INET6_ADDRSTRLEN), - pp->vltimeexpire); + "<%s> valid lifetime for %s/%d" + " (decr. in real time) inconsistent on %s:" + " %d from %s, %ld from us", + __func__, + inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix, prefixbuf, + sizeof(prefixbuf)), + pinfo->nd_opt_pi_prefix_len, + rai->rai_ifname, preferred_time, + inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, + sizeof(ntopbuf)), pfx->pfx_vltimeexpire); inconsistent++; } - } else if (!pp->timer && valid_time != pp->validlifetime) { + } else if (!pfx->pfx_timer && valid_time != pfx->pfx_validlifetime) { syslog(LOG_INFO, - "<%s> valid lifetime for %s/%d" - " inconsistent on %s:" - " %d from %s, %d from us", - __func__, - inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix, - prefixbuf, INET6_ADDRSTRLEN), - pinfo->nd_opt_pi_prefix_len, - rai->ifname, valid_time, - inet_ntop(AF_INET6, &from->sin6_addr, - ntopbuf, INET6_ADDRSTRLEN), - pp->validlifetime); + "<%s> valid lifetime for %s/%d" + " inconsistent on %s:" + " %d from %s, %d from us", + __func__, + inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix, prefixbuf, + sizeof(prefixbuf)), + pinfo->nd_opt_pi_prefix_len, + rai->rai_ifname, valid_time, + inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, + sizeof(ntopbuf)), pfx->pfx_validlifetime); inconsistent++; } - return(inconsistent); + return (inconsistent); } struct prefix * find_prefix(struct rainfo *rai, struct in6_addr *prefix, int plen) { - struct prefix *pp; + struct prefix *pfx; int bytelen, bitlen; u_char bitmask; - for (pp = rai->prefix.next; pp != &rai->prefix; pp = pp->next) { - if (plen != pp->prefixlen) + TAILQ_FOREACH(pfx, &rai->rai_prefix, pfx_next) { + if (plen != pfx->pfx_prefixlen) continue; + bytelen = plen / 8; bitlen = plen % 8; bitmask = 0xff << (8 - bitlen); - if (memcmp((void *)prefix, (void *)&pp->prefix, bytelen)) + + if (memcmp((void *)prefix, (void *)&pfx->pfx_prefix, bytelen)) continue; + if (bitlen == 0 || - ((prefix->s6_addr[bytelen] & bitmask) == - (pp->prefix.s6_addr[bytelen] & bitmask))) { - return(pp); + ((prefix->s6_addr[bytelen] & bitmask) == + (pfx->pfx_prefix.s6_addr[bytelen] & bitmask))) { + return (pfx); } } - return(NULL); + return (NULL); } /* check if p0/plen0 matches p1/plen1; return 1 if matches, otherwise 0. */ int prefix_match(struct in6_addr *p0, int plen0, - struct in6_addr *p1, int plen1) + struct in6_addr *p1, int plen1) { int bytelen, bitlen; u_char bitmask; if (plen0 < plen1) - return(0); + return (0); + bytelen = plen1 / 8; bitlen = plen1 % 8; bitmask = 0xff << (8 - bitlen); + if (memcmp((void *)p0, (void *)p1, bytelen)) - return(0); + return (0); + if (bitlen == 0 || ((p0->s6_addr[bytelen] & bitmask) == (p1->s6_addr[bytelen] & bitmask))) { - return(1); + return (1); } - return(0); + return (0); } static int nd6_options(struct nd_opt_hdr *hdr, int limit, - union nd_opts *ndopts, u_int32_t optflags) + union nd_opt *ndopts, u_int32_t optflags) { int optlen = 0; for (; limit > 0; limit -= optlen) { - if (limit < sizeof(struct nd_opt_hdr)) { + if ((size_t)limit < sizeof(struct nd_opt_hdr)) { syslog(LOG_INFO, "<%s> short option header", __func__); goto bad; } @@ -1300,7 +1446,9 @@ nd6_options(struct nd_opt_hdr *hdr, int limit, goto bad; } - if (hdr->nd_opt_type > ND_OPT_MTU) { + if (hdr->nd_opt_type > ND_OPT_MTU && + hdr->nd_opt_type != ND_OPT_RDNSS && + hdr->nd_opt_type != ND_OPT_DNSSL) { syslog(LOG_INFO, "<%s> unknown ND option(type %d)", __func__, hdr->nd_opt_type); continue; @@ -1316,10 +1464,25 @@ nd6_options(struct nd_opt_hdr *hdr, int limit, * Option length check. Do it here for all fixed-length * options. */ - if ((hdr->nd_opt_type == ND_OPT_MTU && - (optlen != sizeof(struct nd_opt_mtu))) || - ((hdr->nd_opt_type == ND_OPT_PREFIX_INFORMATION && - optlen != sizeof(struct nd_opt_prefix_info)))) { + switch (hdr->nd_opt_type) { + case ND_OPT_MTU: + if (optlen == sizeof(struct nd_opt_mtu)) + break; + goto skip; + case ND_OPT_RDNSS: + if (optlen >= 24 && + (optlen - sizeof(struct nd_opt_rdnss)) % 16 == 0) + break; + goto skip; + case ND_OPT_DNSSL: + if (optlen >= 16 && + (optlen - sizeof(struct nd_opt_dnssl)) % 8 == 0) + break; + goto skip; + case ND_OPT_PREFIX_INFORMATION: + if (optlen == sizeof(struct nd_opt_prefix_info)) + break; +skip: syslog(LOG_INFO, "<%s> invalid option length", __func__); continue; @@ -1328,33 +1491,35 @@ nd6_options(struct nd_opt_hdr *hdr, int limit, switch (hdr->nd_opt_type) { case ND_OPT_TARGET_LINKADDR: case ND_OPT_REDIRECTED_HEADER: + case ND_OPT_RDNSS: + case ND_OPT_DNSSL: break; /* we don't care about these options */ case ND_OPT_SOURCE_LINKADDR: case ND_OPT_MTU: - if (ndopts->nd_opt_array[hdr->nd_opt_type]) { + if (ndopts->opt_array[hdr->nd_opt_type]) { syslog(LOG_INFO, "<%s> duplicated ND option (type = %d)", __func__, hdr->nd_opt_type); } - ndopts->nd_opt_array[hdr->nd_opt_type] = hdr; + ndopts->opt_array[hdr->nd_opt_type] = hdr; break; case ND_OPT_PREFIX_INFORMATION: { - struct nd_optlist *pfxlist; + struct nd_optlist *nol; - if (ndopts->nd_opts_pi == 0) { - ndopts->nd_opts_pi = + if (ndopts->opt_pi == 0) { + ndopts->opt_pi = (struct nd_opt_prefix_info *)hdr; continue; } - if ((pfxlist = malloc(sizeof(*pfxlist))) == NULL) { + nol = malloc(sizeof(*nol)); + if (nol == NULL) { syslog(LOG_ERR, "<%s> can't allocate memory", __func__); goto bad; } - pfxlist->next = ndopts->nd_opts_list; - pfxlist->opt = hdr; - ndopts->nd_opts_list = pfxlist; + nol->nol_opt = hdr; + TAILQ_INSERT_TAIL(&(ndopts->opt_list), nol, nol_next); break; } @@ -1363,46 +1528,45 @@ nd6_options(struct nd_opt_hdr *hdr, int limit, } } - return(0); + return (0); bad: free_ndopts(ndopts); - return(-1); + return (-1); } static void -free_ndopts(union nd_opts *ndopts) +free_ndopts(union nd_opt *ndopts) { - struct nd_optlist *opt = ndopts->nd_opts_list, *next; + struct nd_optlist *nol; - while (opt) { - next = opt->next; - free(opt); - opt = next; + while ((nol = TAILQ_FIRST(&ndopts->opt_list)) != NULL) { + TAILQ_REMOVE(&ndopts->opt_list, nol, nol_next); + free(nol); } } void -sock_open() +sock_open(void) { struct icmp6_filter filt; struct ipv6_mreq mreq; - struct rainfo *ra = ralist; + struct rainfo *rai; int on; /* XXX: should be max MTU attached to the node */ static u_char answer[1500]; rcvcmsgbuflen = CMSG_SPACE(sizeof(struct in6_pktinfo)) + - CMSG_SPACE(sizeof(int)); + CMSG_SPACE(sizeof(int)); rcvcmsgbuf = (u_char *)malloc(rcvcmsgbuflen); if (rcvcmsgbuf == NULL) { syslog(LOG_ERR, "<%s> not enough core", __func__); exit(1); } - sndcmsgbuflen = CMSG_SPACE(sizeof(struct in6_pktinfo)) + - CMSG_SPACE(sizeof(int)); + sndcmsgbuflen = CMSG_SPACE(sizeof(struct in6_pktinfo)) + + CMSG_SPACE(sizeof(int)); sndcmsgbuf = (u_char *)malloc(sndcmsgbuflen); if (sndcmsgbuf == NULL) { syslog(LOG_ERR, "<%s> not enough core", __func__); @@ -1410,113 +1574,84 @@ sock_open() } if ((sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) { - syslog(LOG_ERR, "<%s> socket: %s", __func__, - strerror(errno)); + syslog(LOG_ERR, "<%s> socket: %s", __func__, strerror(errno)); exit(1); } - /* specify to tell receiving interface */ on = 1; -#ifdef IPV6_RECVPKTINFO if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, - sizeof(on)) < 0) { - syslog(LOG_ERR, "<%s> IPV6_RECVPKTINFO: %s", - __func__, strerror(errno)); + sizeof(on)) < 0) { + syslog(LOG_ERR, "<%s> IPV6_RECVPKTINFO: %s", __func__, + strerror(errno)); exit(1); } -#else /* old adv. API */ - if (setsockopt(sock, IPPROTO_IPV6, IPV6_PKTINFO, &on, - sizeof(on)) < 0) { - syslog(LOG_ERR, "<%s> IPV6_PKTINFO: %s", - __func__, strerror(errno)); - exit(1); - } -#endif - on = 1; /* specify to tell value of hoplimit field of received IP6 hdr */ -#ifdef IPV6_RECVHOPLIMIT if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on, - sizeof(on)) < 0) { - syslog(LOG_ERR, "<%s> IPV6_RECVHOPLIMIT: %s", - __func__, strerror(errno)); + sizeof(on)) < 0) { + syslog(LOG_ERR, "<%s> IPV6_RECVHOPLIMIT: %s", __func__, + strerror(errno)); exit(1); } -#else /* old adv. API */ - if (setsockopt(sock, IPPROTO_IPV6, IPV6_HOPLIMIT, &on, - sizeof(on)) < 0) { - syslog(LOG_ERR, "<%s> IPV6_HOPLIMIT: %s", - __func__, strerror(errno)); - exit(1); - } -#endif - ICMP6_FILTER_SETBLOCKALL(&filt); ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filt); ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filt); if (accept_rr) ICMP6_FILTER_SETPASS(ICMP6_ROUTER_RENUMBERING, &filt); + if (setsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filt, - sizeof(filt)) < 0) { + sizeof(filt)) < 0) { syslog(LOG_ERR, "<%s> IICMP6_FILTER: %s", - __func__, strerror(errno)); + __func__, strerror(errno)); exit(1); } /* * join all routers multicast address on each advertising interface. */ - if (inet_pton(AF_INET6, ALLROUTERS_LINK, - &mreq.ipv6mr_multiaddr.s6_addr) - != 1) { - syslog(LOG_ERR, "<%s> inet_pton failed(library bug?)", - __func__); - exit(1); - } - while (ra) { - mreq.ipv6mr_interface = ra->ifindex; + memcpy(&mreq.ipv6mr_multiaddr.s6_addr, + &sin6_linklocal_allrouters.sin6_addr, + sizeof(mreq.ipv6mr_multiaddr.s6_addr)); + TAILQ_FOREACH(rai, &railist, rai_next) { + mreq.ipv6mr_interface = rai->rai_ifindex; if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, - sizeof(mreq)) < 0) { + sizeof(mreq)) < 0) { syslog(LOG_ERR, "<%s> IPV6_JOIN_GROUP(link) on %s: %s", - __func__, ra->ifname, strerror(errno)); + __func__, rai->rai_ifname, strerror(errno)); exit(1); } - ra = ra->next; } /* * When attending router renumbering, join all-routers site-local - * multicast group. + * multicast group. */ if (accept_rr) { - if (inet_pton(AF_INET6, ALLROUTERS_SITE, - &in6a_site_allrouters) != 1) { - syslog(LOG_ERR, "<%s> inet_pton failed(library bug?)", - __func__); - exit(1); - } - mreq.ipv6mr_multiaddr = in6a_site_allrouters; + memcpy(&mreq.ipv6mr_multiaddr.s6_addr, + &sin6_sitelocal_allrouters.sin6_addr, + sizeof(mreq.ipv6mr_multiaddr.s6_addr)); if (mcastif) { if ((mreq.ipv6mr_interface = if_nametoindex(mcastif)) == 0) { syslog(LOG_ERR, - "<%s> invalid interface: %s", - __func__, mcastif); + "<%s> invalid interface: %s", + __func__, mcastif); exit(1); } } else - mreq.ipv6mr_interface = ralist->ifindex; + mreq.ipv6mr_interface = + TAILQ_FIRST(&railist)->rai_ifindex; if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, - &mreq, sizeof(mreq)) < 0) { + &mreq, sizeof(mreq)) < 0) { syslog(LOG_ERR, - "<%s> IPV6_JOIN_GROUP(site) on %s: %s", - __func__, - mcastif ? mcastif : ralist->ifname, - strerror(errno)); + "<%s> IPV6_JOIN_GROUP(site) on %s: %s", __func__, + mcastif ? mcastif : + TAILQ_FIRST(&railist)->rai_ifname, + strerror(errno)); exit(1); } } - + /* initialize msghdr for receiving packets */ rcviov[0].iov_base = (caddr_t)answer; rcviov[0].iov_len = sizeof(answer); @@ -1533,17 +1668,17 @@ sock_open() sndmhdr.msg_iovlen = 1; sndmhdr.msg_control = (caddr_t)sndcmsgbuf; sndmhdr.msg_controllen = sndcmsgbuflen; - + return; } /* open a routing socket to watch the routing table */ static void -rtsock_open() +rtsock_open(void) { if ((rtsock = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) { syslog(LOG_ERR, - "<%s> socket: %s", __func__, strerror(errno)); + "<%s> socket: %s", __func__, strerror(errno)); exit(1); } } @@ -1551,36 +1686,72 @@ rtsock_open() struct rainfo * if_indextorainfo(int idx) { - struct rainfo *rai = ralist; + struct rainfo *rai; - for (rai = ralist; rai; rai = rai->next) { - if (rai->ifindex == idx) - return(rai); + TAILQ_FOREACH(rai, &railist, rai_next) { + syslog(LOG_DEBUG, "<%s> rai->rai_ifindex %d == idx %d?", + __func__, rai->rai_ifindex, idx); + if (rai->rai_ifindex == idx) + return (rai); } - return(NULL); /* search failed */ + return (NULL); /* search failed */ } static void -ra_output(rainfo) -struct rainfo *rainfo; +ra_output(struct rainfo *rai) { int i; struct cmsghdr *cm; struct in6_pktinfo *pi; - struct soliciter *sol, *nextsol; + struct soliciter *sol; - if ((iflist[rainfo->ifindex]->ifm_flags & IFF_UP) == 0) { + if ((iflist[rai->rai_ifindex]->ifm_flags & IFF_UP) == 0) { syslog(LOG_DEBUG, "<%s> %s is not up, skip sending RA", - __func__, rainfo->ifname); + __func__, rai->rai_ifname); return; } - make_packet(rainfo); /* XXX: inefficient */ + /* + * Check lifetime, ACCEPT_RTADV flag, and ip6.forwarding. + * + * (lifetime == 0) = output + * (lifetime != 0 && (ACCEPT_RTADV || !ip6.forwarding) = no output + * + * Basically, hosts MUST NOT send Router Advertisement + * messages at any time (RFC 4861, 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) + */ + syslog(LOG_DEBUG, + "<%s> check lifetime=%d, ACCEPT_RTADV=%d, ip6.forwarding=%d on %s", + __func__, rai->rai_lifetime, check_accept_rtadv(rai->rai_ifindex), + getinet6sysctl(IPV6CTL_FORWARDING), rai->rai_ifname); + if (rai->rai_lifetime != 0) { + if (check_accept_rtadv(rai->rai_ifindex)) { + syslog(LOG_INFO, + "<%s> non-zero lifetime RA " + "on RA receiving interface %s." + " Ignored.", __func__, rai->rai_ifname); + return; + } + if (getinet6sysctl(IPV6CTL_FORWARDING) == 0) { + syslog(LOG_INFO, + "<%s> non-zero lifetime RA " + "but net.inet6.ip6.forwarding=0. " + "Ignored.", __func__); + return; + } + } + + make_packet(rai); /* XXX: inefficient */ - sndmhdr.msg_name = (caddr_t)&sin6_allnodes; - sndmhdr.msg_iov[0].iov_base = (caddr_t)rainfo->ra_data; - sndmhdr.msg_iov[0].iov_len = rainfo->ra_datalen; + sndmhdr.msg_name = (caddr_t)&sin6_linklocal_allnodes; + sndmhdr.msg_iov[0].iov_base = (caddr_t)rai->rai_ra_data; + sndmhdr.msg_iov[0].iov_len = rai->rai_ra_datalen; cm = CMSG_FIRSTHDR(&sndmhdr); /* specify the outgoing interface */ @@ -1589,7 +1760,7 @@ struct rainfo *rainfo; cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); pi = (struct in6_pktinfo *)CMSG_DATA(cm); memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr)); /*XXX*/ - pi->ipi6_ifindex = rainfo->ifindex; + pi->ipi6_ifindex = rai->rai_ifindex; /* specify the hop limit of the packet */ { @@ -1603,80 +1774,79 @@ struct rainfo *rainfo; } syslog(LOG_DEBUG, - "<%s> send RA on %s, # of waitings = %d", - __func__, rainfo->ifname, rainfo->waiting); + "<%s> send RA on %s, # of waitings = %d", + __func__, rai->rai_ifname, rai->rai_waiting); i = sendmsg(sock, &sndmhdr, 0); - if (i < 0 || i != rainfo->ra_datalen) { + if (i < 0 || (size_t)i != rai->rai_ra_datalen) { if (i < 0) { syslog(LOG_ERR, "<%s> sendmsg on %s: %s", - __func__, rainfo->ifname, - strerror(errno)); + __func__, rai->rai_ifname, + strerror(errno)); } } /* update counter */ - if (rainfo->initcounter < MAX_INITIAL_RTR_ADVERTISEMENTS) - rainfo->initcounter++; - rainfo->raoutput++; + if (rai->rai_initcounter < MAX_INITIAL_RTR_ADVERTISEMENTS) + rai->rai_initcounter++; + rai->rai_raoutput++; /* * unicast advertisements * XXX commented out. reason: though spec does not forbit it, unicast * advert does not really help */ - for (sol = rainfo->soliciter; sol; sol = nextsol) { - nextsol = sol->next; - - sol->next = NULL; + while ((sol = TAILQ_FIRST(&rai->rai_soliciter)) != NULL) { + TAILQ_REMOVE(&rai->rai_soliciter, sol, sol_next); free(sol); } - rainfo->soliciter = NULL; /* update timestamp */ - gettimeofday(&rainfo->lastsent, NULL); + gettimeofday(&rai->rai_lastsent, NULL); /* reset waiting conter */ - rainfo->waiting = 0; + rai->rai_waiting = 0; } /* process RA timer */ struct rtadvd_timer * -ra_timeout(void *data) +ra_timeout(void *arg) { - struct rainfo *rai = (struct rainfo *)data; + struct rainfo *rai; #ifdef notyet /* if necessary, reconstruct the packet. */ #endif - - syslog(LOG_DEBUG, - "<%s> RA timer on %s is expired", - __func__, rai->ifname); + rai = (struct rainfo *)arg; + syslog(LOG_DEBUG, "<%s> RA timer on %s is expired", + __func__, rai->rai_ifname); ra_output(rai); - return(rai->timer); + return (rai->rai_timer); } /* update RA timer */ void -ra_timer_update(void *data, struct timeval *tm) +ra_timer_update(void *arg, struct timeval *tm) { - struct rainfo *rai = (struct rainfo *)data; long interval; + struct rainfo *rai; + rai = (struct rainfo *)arg; /* * Whenever a multicast advertisement is sent from an interface, * the timer is reset to a uniformly-distributed random value * between the interface's configured MinRtrAdvInterval and * MaxRtrAdvInterval (RFC2461 6.2.4). */ - interval = rai->mininterval; + interval = rai->rai_mininterval; #ifdef HAVE_ARC4RANDOM - interval += arc4random_uniform(rai->maxinterval - rai->mininterval); + interval += arc4random_uniform(rai->rai_maxinterval - + rai->rai_mininterval); #else - interval += random() % (rai->maxinterval - rai->mininterval); + interval += random() % (rai->rai_maxinterval - + rai->rai_mininterval); #endif /* @@ -1684,9 +1854,9 @@ ra_timer_update(void *data, struct timeval *tm) * MAX_INITIAL_RTR_ADVERTISEMENTS), if the randomly chosen interval * is greater than MAX_INITIAL_RTR_ADVERT_INTERVAL, the timer * SHOULD be set to MAX_INITIAL_RTR_ADVERT_INTERVAL instead. - * (RFC-2461 6.2.4) + * (RFC 4861 6.2.4) */ - if (rai->initcounter < MAX_INITIAL_RTR_ADVERTISEMENTS && + if (rai->rai_initcounter < MAX_INITIAL_RTR_ADVERTISEMENTS && interval > MAX_INITIAL_RTR_ADVERT_INTERVAL) interval = MAX_INITIAL_RTR_ADVERT_INTERVAL; @@ -1694,9 +1864,9 @@ ra_timer_update(void *data, struct timeval *tm) tm->tv_usec = 0; syslog(LOG_DEBUG, - "<%s> RA timer on %s is set to %ld:%ld", - __func__, rai->ifname, - (long int)tm->tv_sec, (long int)tm->tv_usec); + "<%s> RA timer on %s is set to %ld:%ld", + __func__, rai->rai_ifname, + (long int)tm->tv_sec, (long int)tm->tv_usec); return; } diff --git a/usr.sbin/rtadvd/rtadvd.conf b/usr.sbin/rtadvd/rtadvd.conf index 33ab7f3..1e42c75 100644 --- a/usr.sbin/rtadvd/rtadvd.conf +++ b/usr.sbin/rtadvd/rtadvd.conf @@ -18,4 +18,5 @@ # this part by hand, and then invoke rtadvd with the -s option. #ef0:\ -# :addr="3ffe:501:ffff:1000::":prefixlen#64: +# :addr="2001:db8:ffff:1000::":prefixlen#64:\ +# :rdnss="2001:db8:ffff:1000::1":dnssl="example.com": diff --git a/usr.sbin/rtadvd/rtadvd.conf.5 b/usr.sbin/rtadvd/rtadvd.conf.5 index 81ffa70..ba2f490 100644 --- a/usr.sbin/rtadvd/rtadvd.conf.5 +++ b/usr.sbin/rtadvd/rtadvd.conf.5 @@ -29,7 +29,7 @@ .\" .\" $FreeBSD$ .\" -.Dd May 17, 1998 +.Dd June 4, 2011 .Dt RTADVD.CONF 5 .Os .Sh NAME @@ -179,10 +179,25 @@ will automatically get appropriate prefixes from the kernel's routing table, and advertise the prefixes with the default parameters. Keywords other than .Cm clockskew +and +.Cm noifprefix can be augmented with a number, like .Dq Li prefix2 , to specify multiple prefixes. .Bl -tag -width indent +.It Cm \&noifprefix +(bool) Specifies no prefix on the network interfaces will be advertised. +By default +.Nm rtadvd +automatically gathers on-link prefixes from all of the network interfaces +and advertise them. +The +.Cm noifprefix +disables that behavior. +If this is specified and no +.Cm addr +keyword is specified, no prefix information option will be included in the +message. .It Cm \&clockskew (num) Time skew to adjust link propagation delays and clock skews between routers on the link @@ -355,6 +370,66 @@ However, keywords that start with .Dq Li rtr have basically been obsoleted, and should not be used any more. .Pp +The following items are for ICMPv6 Recursive DNS Server Option and +DNS Search List Option +.Pq RFC 6106 , +which will be attached to router advertisement header. +These items are optional. +.Bl -tag -width indent +.It Cm \&rdnss +(str) The IPv6 address of one or more recursive DNS servers. +The argument must be inside double quotes. +Multiple DNS servers can be specified in a comma-separated string. +If different lifetimes are needed for different servers, +separate entries can be given by using +.Cm rdnss , +.Cm rdnss0 , +.Cm rdnss1 , +.Cm rdnss2 ... +options with corresponding +.Cm rdnssltime , +.Cm rdnssltime0 , +.Cm rdnssltime1 , +.Cm rdnssltime2 ... +entries. +Note that the maximum number of servers depends on the receiver side. +See also +.Xr resolver 5 +manual page for resolver implementation in +.Fx . +.It Cm \&rdnssltime +The lifetime of the +.Cm rdnss +DNS server entries. +The default value is 3/2 of the interval time. +.It Cm \&dnssl +(str) One or more domain names in a comma-separated string. +These domain names will be used when making DNS queries on a +non-fully-qualified domain name. +If different lifetimes are needed for different domains, separate entries +can be given by using +.Cm dnssl , +.Cm dnssl0 , +.Cm dnssl1 , +.Cm dnssl2 ... +options with corresponding +.Cm dnsslltime , +.Cm dnsslltime0 , +.Cm dnsslltime1 , +.Cm dnsslltime2 ... +entries. +Note that the maximum number of names depends on the receiver side. +See also +.Xr resolver 5 +manual page for resolver implementation in +.Fx . +.It Cm \&dnsslltime +The lifetime of the +.Cm dnssl +DNS search list entries. +The default value is 3/2 of the interval time. +.El +.Pp You can also refer one line from another by using .Cm tc capability. @@ -388,7 +463,18 @@ option to .Xr rtadvd 8 . .Bd -literal -offset ef0:\\ - :addr="3ffe:501:ffff:1000::":prefixlen#64: + :addr="2001:db8:ffff:1000::":prefixlen#64: +.Ed +.Pp +The following example configures the +.Li wlan0 +interface and adds two DNS servers and a DNS domain search options +using the default option lifetime values. +.Bd -literal -offset +wlan0:\\ + :addr="2001:db8:ffff:1000::":prefixlen#64:\\ + :rdnss="2001:db8:ffff::10,2001:db8:ffff::2:43":\\ + :dnssl="example.com": .Ed .Pp The following example presents the default values in an explicit manner. @@ -399,24 +485,41 @@ default:\\ :chlim#64:raflags#0:rltime#1800:rtime#0:retrans#0:\\ :pinfoflags="la":vltime#2592000:pltime#604800:mtu#0: ef0:\\ - :addr="3ffe:501:ffff:1000::":prefixlen#64:tc=default: + :addr="2001:db8:ffff:1000::":prefixlen#64:tc=default: .Ed .Sh SEE ALSO .Xr termcap 5 , +.Xr resolver 5 , .Xr rtadvd 8 , .Xr rtsol 8 .Rs .%A Thomas Narten .%A Erik Nordmark .%A W. A. Simpson +.%A Hesham Soliman .%T Neighbor Discovery for IP version 6 (IPv6) -.%R RFC 2461 +.%R RFC 4861 +.Re +.Rs +.%A Thomas Narten +.%A Erik Nordmark +.%A W. A. Simpson +.%T Neighbor Discovery for IP version 6 (IPv6) +.%R RFC 2461 (obsoleted by RFC 4861) .Re .Rs .%A Richard Draves .%T Default Router Preferences and More-Specific Routes .%R draft-ietf-ipngwg-router-selection-xx.txt .Re +.Rs +.%A J. Jeong +.%A S. Park +.%A L. Beloeil +.%A S. Madanapalli +.%T IPv6 Router Advertisement Options for DNS Configuration +.%R RFC 6106 +.Re .Sh HISTORY The .Xr rtadvd 8 diff --git a/usr.sbin/rtadvd/rtadvd.h b/usr.sbin/rtadvd/rtadvd.h index 828fec6..f65a837 100644 --- a/usr.sbin/rtadvd/rtadvd.h +++ b/usr.sbin/rtadvd/rtadvd.h @@ -4,7 +4,7 @@ /* * Copyright (C) 1998 WIDE Project. * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -16,7 +16,7 @@ * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -30,11 +30,41 @@ * SUCH DAMAGE. */ -#define ALLNODES "ff02::1" -#define ALLROUTERS_LINK "ff02::2" -#define ALLROUTERS_SITE "ff05::2" -#define ANY "::" -#define RTSOLLEN 8 +#define IN6ADDR_LINKLOCAL_ALLNODES_INIT \ + {{{ 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }}} + +#define IN6ADDR_LINKLOCAL_ALLROUTERS_INIT \ + {{{ 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 }}} + +#define IN6ADDR_SITELOCAL_ALLROUTERS_INIT \ + {{{ 0xff, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 }}} + +extern struct sockaddr_in6 sin6_linklocal_allnodes; +extern struct sockaddr_in6 sin6_linklocal_allrouters; +extern struct sockaddr_in6 sin6_sitelocal_allrouters; + +/* + * RFC 3542 API deprecates IPV6_PKTINFO in favor of + * IPV6_RECVPKTINFO + */ +#ifndef IPV6_RECVPKTINFO +#ifdef IPV6_PKTINFO +#define IPV6_RECVPKTINFO IPV6_PKTINFO +#endif +#endif + +/* + * RFC 3542 API deprecates IPV6_HOPLIMIT in favor of + * IPV6_RECVHOPLIMIT + */ +#ifndef IPV6_RECVHOPLIMIT +#ifdef IPV6_HOPLIMIT +#define IPV6_RECVHOPLIMIT IPV6_HOPLIMIT +#endif +#endif /* protocol constants and default values */ #define DEF_MAXRTRADVINTERVAL 600 @@ -62,100 +92,150 @@ #define PREFIX_FROM_DYNAMIC 3 struct prefix { - struct prefix *next; /* forward link */ - struct prefix *prev; /* previous link */ - - struct rainfo *rainfo; /* back pointer to the interface */ - - struct rtadvd_timer *timer; /* expiration timer. used when a prefix - * derived from the kernel is deleted. - */ - - u_int32_t validlifetime; /* AdvValidLifetime */ - long vltimeexpire; /* expiration of vltime; decrement case only */ - u_int32_t preflifetime; /* AdvPreferredLifetime */ - long pltimeexpire; /* expiration of pltime; decrement case only */ - u_int onlinkflg; /* bool: AdvOnLinkFlag */ - u_int autoconfflg; /* bool: AdvAutonomousFlag */ - int prefixlen; - int origin; /* from kernel or config */ - struct in6_addr prefix; + TAILQ_ENTRY(prefix) pfx_next; + + struct rainfo *pfx_rainfo; /* back pointer to the interface */ + /* + * Expiration timer. This is used when a prefix derived from + * the kernel is deleted. + */ + struct rtadvd_timer *pfx_timer; + + u_int32_t pfx_validlifetime; /* AdvValidLifetime */ + long pfx_vltimeexpire; /* Expiration of vltime */ + u_int32_t pfx_preflifetime; /* AdvPreferredLifetime */ + long pfx_pltimeexpire; /* Expiration of pltime */ + u_int pfx_onlinkflg; /* bool: AdvOnLinkFlag */ + u_int pfx_autoconfflg; /* bool: AdvAutonomousFlag */ + int pfx_prefixlen; + int pfx_origin; /* From kernel or config */ + + struct in6_addr pfx_prefix; }; #ifdef ROUTEINFO struct rtinfo { - struct rtinfo *prev; /* previous link */ - struct rtinfo *next; /* forward link */ + TAILQ_ENTRY(rtinfo) rti_next; - u_int32_t ltime; /* route lifetime */ - u_int rtpref; /* route preference */ - int prefixlen; - struct in6_addr prefix; + u_int32_t rti_ltime; /* route lifetime */ + u_int rti_rtpref; /* route preference */ + int rti_prefixlen; + struct in6_addr rti_prefix; }; #endif +struct rdnss_addr { + TAILQ_ENTRY(rdnss_addr) ra_next; + + struct in6_addr ra_dns; /* DNS server entry */ +}; + +struct rdnss { + TAILQ_ENTRY(rdnss) rd_next; + + TAILQ_HEAD(, rdnss_addr) rd_list; /* list of DNS servers */ + int rd_cnt; /* number of DNS servers */ + u_int32_t rd_ltime; /* number of seconds valid */ +}; + +/* + * The maximum length of a domain name in a DNS search list is calculated + * by a domain name + length fields per 63 octets + a zero octet at + * the tail and adding 8 octet boundary padding. + */ +#define _DNAME_LABELENC_MAXLEN \ + (NI_MAXHOST + (NI_MAXHOST / 64 + 1) + 1) + +#define DNAME_LABELENC_MAXLEN \ + (_DNAME_LABELENC_MAXLEN + 8 - _DNAME_LABELENC_MAXLEN % 8) + +struct dnssl_addr { + TAILQ_ENTRY(dnssl_addr) da_next; + + int da_len; /* length of entry */ + char da_dom[DNAME_LABELENC_MAXLEN]; /* search domain name entry */ +}; + +struct dnssl { + TAILQ_ENTRY(dnssl) dn_next; + + TAILQ_HEAD(, dnssl_addr) dn_list; /* list of search domains */ + u_int32_t dn_ltime; /* number of seconds valid */ +}; + struct soliciter { - struct soliciter *next; - struct sockaddr_in6 addr; + TAILQ_ENTRY(soliciter) sol_next; + + struct sockaddr_in6 sol_addr; }; struct rainfo { /* pointer for list */ - struct rainfo *next; + TAILQ_ENTRY(rainfo) rai_next; /* timer related parameters */ - struct rtadvd_timer *timer; - int initcounter; /* counter for the first few advertisements */ - struct timeval lastsent; /* timestamp when the latest RA was sent */ - int waiting; /* number of RS waiting for RA */ + struct rtadvd_timer *rai_timer; + /* counter for the first few advertisements */ + int rai_initcounter; + /* timestamp when the latest RA was sent */ + struct timeval rai_lastsent; + /* number of RS waiting for RA */ + int rai_waiting; /* interface information */ - int ifindex; - int advlinkopt; /* bool: whether include link-layer addr opt */ - struct sockaddr_dl *sdl; - char ifname[16]; - int phymtu; /* mtu of the physical interface */ + int rai_ifindex; + int rai_advlinkopt; /* bool: whether include link-layer addr opt */ + int rai_advifprefix; /* bool: gather IF prefixes? */ + struct sockaddr_dl *rai_sdl; + char rai_ifname[IFNAMSIZ]; + u_int32_t rai_phymtu; /* mtu of the physical interface */ /* Router configuration variables */ - u_short lifetime; /* AdvDefaultLifetime */ - u_int maxinterval; /* MaxRtrAdvInterval */ - u_int mininterval; /* MinRtrAdvInterval */ - int managedflg; /* AdvManagedFlag */ - int otherflg; /* AdvOtherConfigFlag */ - - int rtpref; /* router preference */ - u_int32_t linkmtu; /* AdvLinkMTU */ - u_int32_t reachabletime; /* AdvReachableTime */ - u_int32_t retranstimer; /* AdvRetransTimer */ - u_int hoplimit; /* AdvCurHopLimit */ - struct prefix prefix; /* AdvPrefixList(link head) */ - int pfxs; /* number of prefixes */ - long clockskew; /* used for consisitency check of lifetimes */ + u_short rai_lifetime; /* AdvDefaultLifetime */ + u_int rai_maxinterval; /* MaxRtrAdvInterval */ + u_int rai_mininterval; /* MinRtrAdvInterval */ + int rai_managedflg; /* AdvManagedFlag */ + int rai_otherflg; /* AdvOtherConfigFlag */ + int rai_rtpref; /* router preference */ + u_int32_t rai_linkmtu; /* AdvLinkMTU */ + u_int32_t rai_reachabletime; /* AdvReachableTime */ + u_int32_t rai_retranstimer; /* AdvRetransTimer */ + u_int rai_hoplimit; /* AdvCurHopLimit */ + + TAILQ_HEAD(, prefix) rai_prefix;/* AdvPrefixList(link head) */ + int rai_pfxs; /* number of prefixes */ + + long rai_clockskew; /* used for consisitency check of lifetimes */ + + TAILQ_HEAD(, rdnss) rai_rdnss; /* DNS server list */ + TAILQ_HEAD(, dnssl) rai_dnssl; /* search domain list */ #ifdef ROUTEINFO - struct rtinfo route; /* route information option (link head) */ - int routes; /* number of route information options */ + TAILQ_HEAD(, rtinfo) rai_route; /* route information option (link head) */ + int rai_routes; /* number of route information options */ #endif - /* actual RA packet data and its length */ - size_t ra_datalen; - u_char *ra_data; + size_t rai_ra_datalen; + u_char *rai_ra_data; /* statistics */ - u_quad_t raoutput; /* number of RAs sent */ - u_quad_t rainput; /* number of RAs received */ - u_quad_t rainconsistent; /* number of RAs inconsistent with ours */ - u_quad_t rsinput; /* number of RSs received */ + u_quad_t rai_raoutput; /* # of RAs sent */ + u_quad_t rai_rainput; /* # of RAs received */ + u_quad_t rai_rainconsistent; /* # of RAs inconsistent with ours */ + u_quad_t rai_rsinput; /* # of RSs received */ /* info about soliciter */ - struct soliciter *soliciter; /* recent solication source */ + TAILQ_HEAD(, soliciter) rai_soliciter; /* recent solication source */ }; -struct rtadvd_timer *ra_timeout(void *); -void ra_timer_update(void *, struct timeval *); +/* Interface list including RA information */ +extern TAILQ_HEAD(railist_head_t, rainfo) railist; -int prefix_match(struct in6_addr *, int, struct in6_addr *, int); -struct rainfo *if_indextorainfo(int); -struct prefix *find_prefix(struct rainfo *, struct in6_addr *, int); +struct rtadvd_timer *ra_timeout(void *); +void ra_timer_update(void *, struct timeval *); -extern struct in6_addr in6a_site_allrouters; +int prefix_match(struct in6_addr *, int, + struct in6_addr *, int); +struct rainfo *if_indextorainfo(int); +struct prefix *find_prefix(struct rainfo *, + struct in6_addr *, int); diff --git a/usr.sbin/rtadvd/timer.c b/usr.sbin/rtadvd/timer.c index 7fb0902..8cad6ad 100644 --- a/usr.sbin/rtadvd/timer.c +++ b/usr.sbin/rtadvd/timer.c @@ -4,7 +4,7 @@ /* * Copyright (C) 1998 WIDE Project. * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -16,7 +16,7 @@ * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -31,6 +31,7 @@ */ #include <sys/time.h> +#include <sys/queue.h> #include <unistd.h> #include <syslog.h> @@ -39,21 +40,19 @@ #include <search.h> #include "timer.h" -static struct rtadvd_timer timer_head; - #define MILLION 1000000 -#define TIMEVAL_EQUAL(t1,t2) ((t1)->tv_sec == (t2)->tv_sec &&\ - (t1)->tv_usec == (t2)->tv_usec) -static struct timeval tm_max = {0x7fffffff, 0x7fffffff}; +struct rtadvd_timer_head_t ra_timer = + TAILQ_HEAD_INITIALIZER(ra_timer); +static struct timeval tm_limit = {0x7fffffff, 0x7fffffff}; +static struct timeval tm_max; void -rtadvd_timer_init() +rtadvd_timer_init(void) { - memset(&timer_head, 0, sizeof(timer_head)); - timer_head.next = timer_head.prev = &timer_head; - timer_head.tm = tm_max; + tm_max = tm_limit; + TAILQ_INIT(&ra_timer); } struct rtadvd_timer * @@ -61,54 +60,57 @@ rtadvd_add_timer(struct rtadvd_timer *(*timeout)(void *), void (*update)(void *, struct timeval *), void *timeodata, void *updatedata) { - struct rtadvd_timer *newtimer; + struct rtadvd_timer *rat; - if ((newtimer = malloc(sizeof(*newtimer))) == NULL) { + if (timeout == NULL) { syslog(LOG_ERR, - "<%s> can't allocate memory", __func__); + "<%s> timeout function unspecified", __func__); exit(1); } - memset(newtimer, 0, sizeof(*newtimer)); - - if (timeout == NULL) { + rat = malloc(sizeof(*rat)); + if (rat == NULL) { syslog(LOG_ERR, - "<%s> timeout function unspecified", __func__); + "<%s> can't allocate memory", __func__); exit(1); } - newtimer->expire = timeout; - newtimer->update = update; - newtimer->expire_data = timeodata; - newtimer->update_data = updatedata; - newtimer->tm = tm_max; + memset(rat, 0, sizeof(*rat)); + + rat->rat_expire = timeout; + rat->rat_update = update; + rat->rat_expire_data = timeodata; + rat->rat_update_data = updatedata; + rat->rat_tm = tm_max; /* link into chain */ - insque(newtimer, &timer_head); + TAILQ_INSERT_TAIL(&ra_timer, rat, rat_next); - return(newtimer); + return (rat); } void -rtadvd_remove_timer(struct rtadvd_timer **timer) +rtadvd_remove_timer(struct rtadvd_timer *rat) { - remque(*timer); - free(*timer); - *timer = NULL; + + if (rat == NULL) + return; + + TAILQ_REMOVE(&ra_timer, rat, rat_next); + free(rat); } void -rtadvd_set_timer(struct timeval *tm, struct rtadvd_timer *timer) +rtadvd_set_timer(struct timeval *tm, struct rtadvd_timer *rat) { struct timeval now; /* reset the timer */ gettimeofday(&now, NULL); - - TIMEVAL_ADD(&now, tm, &timer->tm); + TIMEVAL_ADD(&now, tm, &rat->rat_tm); /* update the next expiration time */ - if (TIMEVAL_LT(timer->tm, timer_head.tm)) - timer_head.tm = timer->tm; + if (TIMEVAL_LT(&rat->rat_tm, &tm_max)) + tm_max = rat->rat_tm; return; } @@ -119,58 +121,52 @@ rtadvd_set_timer(struct timeval *tm, struct rtadvd_timer *timer) * Return the next interval for select() call. */ struct timeval * -rtadvd_check_timer() +rtadvd_check_timer(void) { static struct timeval returnval; struct timeval now; - struct rtadvd_timer *tm = timer_head.next, *tm_next; + struct rtadvd_timer *rat; gettimeofday(&now, NULL); - - timer_head.tm = tm_max; - - for (tm = timer_head.next; tm != &timer_head; tm = tm_next) { - tm_next = tm->next; - - if (TIMEVAL_LEQ(tm->tm, now)) { - if (((*tm->expire)(tm->expire_data) == NULL)) + tm_max = tm_limit; + TAILQ_FOREACH(rat, &ra_timer, rat_next) { + if (TIMEVAL_LEQ(&rat->rat_tm, &now)) { + if (((*rat->rat_expire)(rat->rat_expire_data) == NULL)) continue; /* the timer was removed */ - if (tm->update) - (*tm->update)(tm->update_data, &tm->tm); - TIMEVAL_ADD(&tm->tm, &now, &tm->tm); + if (rat->rat_update) + (*rat->rat_update)(rat->rat_update_data, &rat->rat_tm); + TIMEVAL_ADD(&rat->rat_tm, &now, &rat->rat_tm); } - - if (TIMEVAL_LT(tm->tm, timer_head.tm)) - timer_head.tm = tm->tm; + if (TIMEVAL_LT(&rat->rat_tm, &tm_max)) + tm_max = rat->rat_tm; } - - if (TIMEVAL_EQUAL(&tm_max, &timer_head.tm)) { + if (TIMEVAL_EQUAL(&tm_max, &tm_limit)) { /* no need to timeout */ - return(NULL); - } else if (TIMEVAL_LT(timer_head.tm, now)) { + return (NULL); + } else if (TIMEVAL_LT(&tm_max, &now)) { /* this may occur when the interval is too small */ returnval.tv_sec = returnval.tv_usec = 0; } else - TIMEVAL_SUB(&timer_head.tm, &now, &returnval); - return(&returnval); + TIMEVAL_SUB(&tm_max, &now, &returnval); + return (&returnval); } struct timeval * -rtadvd_timer_rest(struct rtadvd_timer *timer) +rtadvd_timer_rest(struct rtadvd_timer *rat) { static struct timeval returnval, now; gettimeofday(&now, NULL); - if (TIMEVAL_LEQ(timer->tm, now)) { + if (TIMEVAL_LEQ(&rat->rat_tm, &now)) { syslog(LOG_DEBUG, - "<%s> a timer must be expired, but not yet", - __func__); + "<%s> a timer must be expired, but not yet", + __func__); returnval.tv_sec = returnval.tv_usec = 0; } else - TIMEVAL_SUB(&timer->tm, &now, &returnval); + TIMEVAL_SUB(&rat->rat_tm, &now, &returnval); - return(&returnval); + return (&returnval); } /* result = a + b */ diff --git a/usr.sbin/rtadvd/timer.h b/usr.sbin/rtadvd/timer.h index 4526103..e2e0c65 100644 --- a/usr.sbin/rtadvd/timer.h +++ b/usr.sbin/rtadvd/timer.h @@ -4,7 +4,7 @@ /* * Copyright (C) 1998 WIDE Project. * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -16,7 +16,7 @@ * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -31,35 +31,42 @@ */ /* a < b */ -#define TIMEVAL_LT(a, b) (((a).tv_sec < (b).tv_sec) ||\ - (((a).tv_sec == (b).tv_sec) && \ - ((a).tv_usec < (b).tv_usec))) +#define TIMEVAL_LT(a, b) \ + (((a)->tv_sec < (b)->tv_sec) || \ + (((a)->tv_sec == (b)->tv_sec) && \ + ((a)->tv_usec < (b)->tv_usec))) /* a <= b */ -#define TIMEVAL_LEQ(a, b) (((a).tv_sec < (b).tv_sec) ||\ - (((a).tv_sec == (b).tv_sec) &&\ - ((a).tv_usec <= (b).tv_usec))) +#define TIMEVAL_LEQ(a, b) \ + (((a)->tv_sec < (b)->tv_sec) || \ + (((a)->tv_sec == (b)->tv_sec) && \ + ((a)->tv_usec <= (b)->tv_usec))) +#define TIMEVAL_EQUAL(a,b) \ + (((a)->tv_sec == (b)->tv_sec) && \ + ((a)->tv_usec == (b)->tv_usec)) + +extern TAILQ_HEAD(rtadvd_timer_head_t, rtadvd_timer) ra_timer; struct rtadvd_timer { - struct rtadvd_timer *next; - struct rtadvd_timer *prev; - struct rainfo *rai; - struct timeval tm; + TAILQ_ENTRY(rtadvd_timer) rat_next; - struct rtadvd_timer *(*expire)(void *); /* expiration function */ - void *expire_data; - void (*update)(void *, struct timeval *); /* update function */ - void *update_data; + struct rainfo *rat_rai; + struct timeval rat_tm; + struct rtadvd_timer *(*rat_expire)(void *); + void *rat_expire_data; + void (*rat_update)(void *, struct timeval *); + void *rat_update_data; }; -void rtadvd_timer_init(void); -struct rtadvd_timer *rtadvd_add_timer(struct rtadvd_timer *(*)(void *), - void (*)(void *, struct timeval *), void *, void *); -void rtadvd_set_timer(struct timeval *, struct rtadvd_timer *); -void rtadvd_remove_timer(struct rtadvd_timer **); -struct timeval * rtadvd_check_timer(void); -struct timeval * rtadvd_timer_rest(struct rtadvd_timer *); -void TIMEVAL_ADD(struct timeval *, struct timeval *, - struct timeval *); -void TIMEVAL_SUB(struct timeval *, struct timeval *, - struct timeval *); +void rtadvd_timer_init(void); +struct rtadvd_timer *rtadvd_add_timer(struct rtadvd_timer *(*)(void *), + void (*)(void *, struct timeval *), void *, void *); +void rtadvd_set_timer(struct timeval *, + struct rtadvd_timer *); +void rtadvd_remove_timer(struct rtadvd_timer *); +struct timeval *rtadvd_check_timer(void); +struct timeval *rtadvd_timer_rest(struct rtadvd_timer *); +void TIMEVAL_ADD(struct timeval *, struct timeval *, + struct timeval *); +void TIMEVAL_SUB(struct timeval *, struct timeval *, + struct timeval *); |