From de63a2bf8335e2fed512c4f01d0eddd2f2cc80d9 Mon Sep 17 00:00:00 2001 From: hrs Date: Sun, 5 Jun 2011 11:20:19 +0000 Subject: 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. --- usr.sbin/rtadvd/config.c | 44 ------------------- 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 #include #include -#include #include #include @@ -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 +#include #include #include #include #include +#include #include #include @@ -47,6 +49,10 @@ #include +#include +#include +#include + #include #include #include @@ -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; -- cgit v1.1