diff options
author | hrs <hrs@FreeBSD.org> | 2011-06-05 11:20:19 +0000 |
---|---|---|
committer | hrs <hrs@FreeBSD.org> | 2011-06-05 11:20:19 +0000 |
commit | de63a2bf8335e2fed512c4f01d0eddd2f2cc80d9 (patch) | |
tree | 654d1d414fd6a9db326a5caa83f1087058b3a99f | |
parent | ba519ba6ac678da65d1e741ea85e13f187cb0eee (diff) | |
download | FreeBSD-src-de63a2bf8335e2fed512c4f01d0eddd2f2cc80d9.zip FreeBSD-src-de63a2bf8335e2fed512c4f01d0eddd2f2cc80d9.tar.gz |
Specify requirements for RA sending/receiving based on lifetime,
IFF_ND6_ACCEPT_RTADV, and net.inet6.ip6.forwarding.
ra_output:
(lifetime == 0) = output
(lifetime != 0 && (ACCEPT_RTADV || !ip6.forwarding) = no output
ra_input:
ACCEPT_RTADV = input
!ACCEPT_RTADV = no input
Note that the current implementation sends RAs with zero-lifetime even if
ip6.forwarding == 0. This behavior is derived from KAME and different from
RFC 4861.
-rw-r--r-- | usr.sbin/rtadvd/config.c | 44 | ||||
-rw-r--r-- | usr.sbin/rtadvd/rtadvd.c | 108 |
2 files changed, 108 insertions, 44 deletions
diff --git a/usr.sbin/rtadvd/config.c b/usr.sbin/rtadvd/config.c index ef2680b..4c870b9 100644 --- a/usr.sbin/rtadvd/config.c +++ b/usr.sbin/rtadvd/config.c @@ -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> @@ -76,7 +75,6 @@ static time_t prefix_timo = (60 * 120); /* 2 hours. static struct rtadvd_timer *prefix_timeout(void *); static void makeentry(char *, size_t, int, const char *); -static int getinet6sysctl(int); static size_t dname_labelenc(char *, const char *); /* Encode domain name label encoding in RFC 1035 Section 3.1 */ @@ -215,7 +213,6 @@ getconfig(int idx) char *bp = buf; char *addr, *flagstr; char intface[IFNAMSIZ]; - static int forwarding = -1; if (if_indextoname(idx, intface) == NULL) { syslog(LOG_ERR, "<%s> invalid index number (%d)", @@ -247,11 +244,6 @@ getconfig(int idx) 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; @@ -355,22 +347,6 @@ getconfig(int idx) MAXROUTERLIFETIME); return (-1); } - /* - * 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) - */ - 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); - return (-1); - } rai->rai_lifetime = val & 0xffff; MAYHAVE(val, "rtime", DEF_ADVREACHABLETIME); @@ -1312,23 +1288,3 @@ make_packet(struct rainfo *rai) } return; } - -static int -getinet6sysctl(int code) -{ - int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, 0 }; - int value; - size_t size; - - mib[3] = code; - size = sizeof(value); - if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), &value, &size, NULL, 0) - < 0) { - syslog(LOG_ERR, "<%s>: failed to get ip6 sysctl(%d): %s", - __func__, code, - strerror(errno)); - return (-1); - } - else - return (value); -} diff --git a/usr.sbin/rtadvd/rtadvd.c b/usr.sbin/rtadvd/rtadvd.c index bd31f49..614d109 100644 --- a/usr.sbin/rtadvd/rtadvd.c +++ b/usr.sbin/rtadvd/rtadvd.c @@ -31,10 +31,12 @@ */ #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> @@ -47,6 +49,10 @@ #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> @@ -174,6 +180,8 @@ 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(int argc, char *argv[]) @@ -1030,6 +1038,61 @@ set_short_delay(struct rainfo *rai) 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 *nra, struct in6_pktinfo *pi, struct sockaddr_in6 *from) @@ -1047,6 +1110,16 @@ ra_input(int len, struct nd_router_advert *nra, 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; + } + /* ND option check */ memset(&ndopts, 0, sizeof(ndopts)); error = nd6_options((struct nd_opt_hdr *)(nra + 1), @@ -1639,6 +1712,41 @@ ra_output(struct rainfo *rai) return; } + /* + * 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_linklocal_allnodes; |