summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorhrs <hrs@FreeBSD.org>2011-06-05 11:20:19 +0000
committerhrs <hrs@FreeBSD.org>2011-06-05 11:20:19 +0000
commitde63a2bf8335e2fed512c4f01d0eddd2f2cc80d9 (patch)
tree654d1d414fd6a9db326a5caa83f1087058b3a99f
parentba519ba6ac678da65d1e741ea85e13f187cb0eee (diff)
downloadFreeBSD-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.c44
-rw-r--r--usr.sbin/rtadvd/rtadvd.c108
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;
OpenPOWER on IntegriCloud