svn commit: r339929 - in head: sbin/ifconfig sys/net sys/netinet sys/netinet6 usr.sbin/ndp usr.sbin/rtadvd

Bjoern A. Zeeb bz at FreeBSD.org
Tue Oct 30 20:08:52 UTC 2018


Author: bz
Date: Tue Oct 30 20:08:48 2018
New Revision: 339929
URL: https://svnweb.freebsd.org/changeset/base/339929

Log:
  Initial implementation of draft-ietf-6man-ipv6only-flag.
  
  This change defines the RA "6" (IPv6-Only) flag which routers
  may advertise, kernel logic to check if all routers on a link
  have the flag set and accordingly update a per-interface flag.
  
  If all routers agree that it is an IPv6-only link, ether_output_frame(),
  based on the interface flag, will filter out all ETHERTYPE_IP/ARP
  frames, drop them, and return EAFNOSUPPORT to upper layers.
  
  The change also updates ndp to show the "6" flag, ifconfig to
  display the IPV6_ONLY nd6 flag if set, and rtadvd to allow
  announcing the flag.
  
  Further changes to tcpdump (contrib code) are availble and will
  be upstreamed.
  
  Tested the code (slightly earlier version) with 2 FreeBSD
  IPv6 routers, a FreeBSD laptop on ethernet as well as wifi,
  and with Win10 and OSX clients (which did not fall over with
  the "6" flag set but not understood).
  
  We may also want to (a) implement and RX filter, and (b) over
  time enahnce user space to, say, stop dhclient from running
  when the interface flag is set.  Also we might want to start
  IPv6 before IPv4 in the future.
  
  All the code is hidden under the EXPERIMENTAL option and not
  compiled by default as the draft is a work-in-progress and
  we cannot rely on the fact that IANA will assign the bits
  as requested by the draft and hence they may change.
  
  Dear 6man, you have running code.
  
  Discussed with:	Bob Hinden, Brian E Carpenter

Modified:
  head/sbin/ifconfig/Makefile
  head/sbin/ifconfig/af_nd6.c
  head/sys/net/if_ethersubr.c
  head/sys/netinet/icmp6.h
  head/sys/netinet6/nd6.h
  head/sys/netinet6/nd6_rtr.c
  head/usr.sbin/ndp/Makefile
  head/usr.sbin/ndp/ndp.c
  head/usr.sbin/rtadvd/Makefile
  head/usr.sbin/rtadvd/config.c
  head/usr.sbin/rtadvd/rtadvd.c
  head/usr.sbin/rtadvd/rtadvd.h

Modified: head/sbin/ifconfig/Makefile
==============================================================================
--- head/sbin/ifconfig/Makefile	Tue Oct 30 19:10:41 2018	(r339928)
+++ head/sbin/ifconfig/Makefile	Tue Oct 30 20:08:48 2018	(r339929)
@@ -51,6 +51,9 @@ SRCS+=	ifpfsync.c		# pfsync(4) support
 SRCS+=	ifbridge.c		# bridge support
 SRCS+=	iflagg.c		# lagg support
 
+.if ${MK_EXPERIMENTAL} != "no"
+CFLAGS+= -DDRAFT_IETF_6MAN_IPV6ONLY_FLAG
+.endif
 .if ${MK_INET6_SUPPORT} != "no"
 CFLAGS+= -DINET6
 .endif

Modified: head/sbin/ifconfig/af_nd6.c
==============================================================================
--- head/sbin/ifconfig/af_nd6.c	Tue Oct 30 19:10:41 2018	(r339928)
+++ head/sbin/ifconfig/af_nd6.c	Tue Oct 30 20:08:48 2018	(r339929)
@@ -57,9 +57,17 @@ static const char rcsid[] =
 #include "ifconfig.h"
 
 #define	MAX_SYSCTL_TRY	5
+#ifdef DRAFT_IETF_6MAN_IPV6ONLY_FLAG
 #define	ND6BITS	"\020\001PERFORMNUD\002ACCEPT_RTADV\003PREFER_SOURCE" \
 		"\004IFDISABLED\005DONT_SET_IFROUTE\006AUTO_LINKLOCAL" \
+		"\007NO_RADR\010NO_PREFER_IFACE\011NO_DAD" \
+		"\012IPV6_ONLY" \
+		"\020DEFAULTIF"
+#else
+#define	ND6BITS	"\020\001PERFORMNUD\002ACCEPT_RTADV\003PREFER_SOURCE" \
+		"\004IFDISABLED\005DONT_SET_IFROUTE\006AUTO_LINKLOCAL" \
 		"\007NO_RADR\010NO_PREFER_IFACE\011NO_DAD\020DEFAULTIF"
+#endif
 
 static int isnd6defif(int);
 void setnd6flags(const char *, int, int, const struct afswtch *);

Modified: head/sys/net/if_ethersubr.c
==============================================================================
--- head/sys/net/if_ethersubr.c	Tue Oct 30 19:10:41 2018	(r339928)
+++ head/sys/net/if_ethersubr.c	Tue Oct 30 20:08:48 2018	(r339929)
@@ -475,6 +475,26 @@ ether_output_frame(struct ifnet *ifp, struct mbuf *m)
 			return (0);
 	}
 
+#ifdef EXPERIMENTAL
+#if defined(INET6) && defined(INET)
+	/* draft-ietf-6man-ipv6only-flag */
+	/* Catch ETHERTYPE_IP, and ETHERTYPE_ARP if we are v6-only. */
+	if ((ND_IFINFO(ifp)->flags & ND6_IFF_IPV6_ONLY) != 0) {
+		struct ether_header *eh;
+
+		eh = mtod(m, struct ether_header *);
+		switch (ntohs(eh->ether_type)) {
+		case ETHERTYPE_IP:
+		case ETHERTYPE_ARP:
+			m_freem(m);
+			return (EAFNOSUPPORT);
+			/* NOTREACHED */
+			break;
+		};
+	}
+#endif
+#endif
+
 	/*
 	 * Queue message on interface, update output statistics if
 	 * successful, and start output if interface not yet active.

Modified: head/sys/netinet/icmp6.h
==============================================================================
--- head/sys/netinet/icmp6.h	Tue Oct 30 19:10:41 2018	(r339928)
+++ head/sys/netinet/icmp6.h	Tue Oct 30 20:08:48 2018	(r339929)
@@ -244,6 +244,10 @@ struct nd_router_advert {	/* router advertisement */
 #define ND_RA_FLAG_RTPREF_LOW	0x18 /* 00011000 */
 #define ND_RA_FLAG_RTPREF_RSV	0x10 /* 00010000 */
 
+#ifdef EXPERIMENTAL
+#define	ND_RA_FLAG_IPV6_ONLY	0x02 /* draft-ietf-6man-ipv6only-flag */
+#endif
+
 #define nd_ra_router_lifetime	nd_ra_hdr.icmp6_data16[1]
 
 struct nd_neighbor_solicit {	/* neighbor solicitation */

Modified: head/sys/netinet6/nd6.h
==============================================================================
--- head/sys/netinet6/nd6.h	Tue Oct 30 19:10:41 2018	(r339928)
+++ head/sys/netinet6/nd6.h	Tue Oct 30 20:08:48 2018	(r339929)
@@ -90,6 +90,9 @@ struct nd_ifinfo {
 #define	ND6_IFF_NO_RADR		0x40
 #define ND6_IFF_NO_PREFER_IFACE	0x80 /* XXX: not related to ND. */
 #define ND6_IFF_NO_DAD		0x100
+#ifdef EXPERIMENTAL
+#define	ND6_IFF_IPV6_ONLY	0x200 /* draft-ietf-6man-ipv6only-flag */
+#endif
 
 #ifdef _KERNEL
 #define ND_IFINFO(ifp) \

Modified: head/sys/netinet6/nd6_rtr.c
==============================================================================
--- head/sys/netinet6/nd6_rtr.c	Tue Oct 30 19:10:41 2018	(r339928)
+++ head/sys/netinet6/nd6_rtr.c	Tue Oct 30 20:08:48 2018	(r339929)
@@ -204,7 +204,38 @@ nd6_rs_input(struct mbuf *m, int off, int icmp6len)
 	m_freem(m);
 }
 
+#ifdef EXPERIMENTAL
 /*
+ * An initial update routine for draft-ietf-6man-ipv6only-flag.
+ * We need to iterate over all default routers for the given
+ * interface to see whether they are all advertising the "6"
+ * (IPv6-Only) flag.  If they do set, otherwise unset, the
+ * interface flag we later use to filter on.
+ */
+static void
+defrtr_ipv6_only_ifp(struct ifnet *ifp)
+{
+	struct nd_defrouter *dr;
+	bool ipv6_only;
+
+	ipv6_only = true;
+	ND6_RLOCK();
+	TAILQ_FOREACH(dr, &V_nd_defrouter, dr_entry)
+		if (dr->ifp == ifp &&
+		    (dr->raflags & ND_RA_FLAG_IPV6_ONLY) == 0)
+			ipv6_only = false;
+	ND6_RUNLOCK();
+
+	IF_AFDATA_WLOCK(ifp);
+	if (ipv6_only)
+		ND_IFINFO(ifp)->flags |= ND6_IFF_IPV6_ONLY;
+	else
+		ND_IFINFO(ifp)->flags &= ~ND6_IFF_IPV6_ONLY;
+	IF_AFDATA_WUNLOCK(ifp);
+}
+#endif
+
+/*
  * Receive Router Advertisement Message.
  *
  * Based on RFC 2461
@@ -319,6 +350,9 @@ nd6_ra_input(struct mbuf *m, int off, int icmp6len)
 		}
 	}
 	dr = defrtrlist_update(&dr0);
+#ifdef EXPERIMENTAL
+	defrtr_ipv6_only_ifp(ifp);
+#endif
     }
 
 	/*
@@ -691,6 +725,10 @@ defrouter_del(struct nd_defrouter *dr)
 	 */
 	if (ND_IFINFO(dr->ifp)->flags & ND6_IFF_ACCEPT_RTADV)
 		rt6_flush(&dr->rtaddr, dr->ifp);
+
+#ifdef EXPERIMENTAL
+	defrtr_ipv6_only_ifp(dr->ifp);
+#endif
 
 	if (dr->installed) {
 		deldr = dr;

Modified: head/usr.sbin/ndp/Makefile
==============================================================================
--- head/usr.sbin/ndp/Makefile	Tue Oct 30 19:10:41 2018	(r339928)
+++ head/usr.sbin/ndp/Makefile	Tue Oct 30 20:08:48 2018	(r339929)
@@ -13,6 +13,8 @@
 # A PARTICULAR PURPOSE.
 # $FreeBSD$
 
+.include <src.opts.mk>
+
 .PATH: ${SRCTOP}/contrib/tcpdump
 
 PROG=	ndp
@@ -21,6 +23,11 @@ SRCS=	ndp.c gmt2local.c
 
 CFLAGS+= -I. -I${.CURDIR} -I${SRCTOP}/contrib/tcpdump
 CFLAGS+= -D_U_=""
+
+.if ${MK_EXPERIMENTAL} != "no"
+CFLAGS+=	-DEXPERIMENTAL
+CFLAGS+=	-DDRAFT_IETF_6MAN_IPV6ONLY_FLAG
+.endif
 
 WARNS?=	3
 

Modified: head/usr.sbin/ndp/ndp.c
==============================================================================
--- head/usr.sbin/ndp/ndp.c	Tue Oct 30 19:10:41 2018	(r339928)
+++ head/usr.sbin/ndp/ndp.c	Tue Oct 30 20:08:48 2018	(r339929)
@@ -1096,6 +1096,9 @@ rtrlist()
 		printf(", flags=%s%s",
 		    p->flags & ND_RA_FLAG_MANAGED ? "M" : "",
 		    p->flags & ND_RA_FLAG_OTHER   ? "O" : "");
+#ifdef DRAFT_IETF_6MAN_IPV6ONLY_FLAG
+		printf("%s", p->flags & ND_RA_FLAG_IPV6_ONLY ? "6" : "");
+#endif
 		rtpref = ((p->flags & ND_RA_FLAG_RTPREF_MASK) >> 3) & 0xff;
 		printf(", pref=%s", rtpref_str[rtpref]);
 

Modified: head/usr.sbin/rtadvd/Makefile
==============================================================================
--- head/usr.sbin/rtadvd/Makefile	Tue Oct 30 19:10:41 2018	(r339928)
+++ head/usr.sbin/rtadvd/Makefile	Tue Oct 30 20:08:48 2018	(r339929)
@@ -14,10 +14,17 @@
 #
 # $FreeBSD$
 
+.include <src.opts.mk>
+
 PROG=	rtadvd
 MAN=	rtadvd.conf.5 rtadvd.8
 SRCS=	rtadvd.c rrenum.c advcap.c if.c config.c timer.c timer_subr.c	\
 	control.c control_server.c
+
+.if ${MK_EXPERIMENTAL} != "no"
+CFLAGS+=	-DEXPERIMENTAL
+CFLAGS+=	-DDRAFT_IETF_6MAN_IPV6ONLY_FLAG
+.endif
 
 LIBADD=	util
 

Modified: head/usr.sbin/rtadvd/config.c
==============================================================================
--- head/usr.sbin/rtadvd/config.c	Tue Oct 30 19:10:41 2018	(r339928)
+++ head/usr.sbin/rtadvd/config.c	Tue Oct 30 20:08:48 2018	(r339929)
@@ -437,6 +437,10 @@ getconfig(struct ifinfo *ifi)
 			}
 			val |= ND_RA_FLAG_RTPREF_LOW;
 		}
+#ifdef DRAFT_IETF_6MAN_IPV6ONLY_FLAG
+		if (strchr(flagstr, '6'))
+			val |= ND_RA_FLAG_IPV6_ONLY;
+#endif
 	} else
 		MAYHAVE(val, "raflags", 0);
 
@@ -452,6 +456,9 @@ getconfig(struct ifinfo *ifi)
 		    __func__, rai->rai_rtpref, ifi->ifi_ifname);
 		goto getconfig_free_rai;
 	}
+#ifdef DRAFT_IETF_6MAN_IPV6ONLY_FLAG
+	rai->rai_ipv6onlyflg = val & ND_RA_FLAG_IPV6_ONLY;
+#endif
 
 	MAYHAVE(val, "rltime", rai->rai_maxinterval * 3);
 	if ((uint16_t)val && ((uint16_t)val < rai->rai_maxinterval ||
@@ -1406,6 +1413,10 @@ make_packet(struct rainfo *rai)
 		rai->rai_managedflg ? ND_RA_FLAG_MANAGED : 0;
 	ra->nd_ra_flags_reserved |=
 		rai->rai_otherflg ? ND_RA_FLAG_OTHER : 0;
+#ifdef DRAFT_IETF_6MAN_IPV6ONLY_FLAG
+	ra->nd_ra_flags_reserved |=
+		rai->rai_ipv6onlyflg ? ND_RA_FLAG_IPV6_ONLY : 0;
+#endif
 	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);

Modified: head/usr.sbin/rtadvd/rtadvd.c
==============================================================================
--- head/usr.sbin/rtadvd/rtadvd.c	Tue Oct 30 19:10:41 2018	(r339928)
+++ head/usr.sbin/rtadvd/rtadvd.c	Tue Oct 30 20:08:48 2018	(r339929)
@@ -1160,6 +1160,19 @@ ra_input(int len, struct nd_router_advert *nra,
 			sizeof(ntopbuf)), on_off[rai->rai_otherflg]);
 		inconsistent++;
 	}
+#ifdef DRAFT_IETF_6MAN_IPV6ONLY_FLAG
+	/* 6 flag */
+	if ((nra->nd_ra_flags_reserved & ND_RA_FLAG_IPV6_ONLY) !=
+	    rai->rai_ipv6onlyflg) {
+		syslog(LOG_NOTICE,
+		    "6 flag inconsistent on %s:"
+		    " %s from %s, %s from us",
+		    ifi->ifi_ifname, on_off[!rai->rai_ipv6onlyflg],
+		    inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf,
+			sizeof(ntopbuf)), on_off[rai->rai_ipv6onlyflg]);
+		inconsistent++;
+	}
+#endif
 	/* Reachable Time */
 	reachabletime = ntohl(nra->nd_ra_reachable);
 	if (reachabletime && rai->rai_reachabletime &&

Modified: head/usr.sbin/rtadvd/rtadvd.h
==============================================================================
--- head/usr.sbin/rtadvd/rtadvd.h	Tue Oct 30 19:10:41 2018	(r339928)
+++ head/usr.sbin/rtadvd/rtadvd.h	Tue Oct 30 20:08:48 2018	(r339929)
@@ -196,6 +196,9 @@ struct	rainfo {
 	uint16_t	rai_mininterval;	/* MinRtrAdvInterval */
 	int 	rai_managedflg;		/* AdvManagedFlag */
 	int	rai_otherflg;		/* AdvOtherConfigFlag */
+#ifdef DRAFT_IETF_6MAN_IPV6ONLY_FLAG
+	int	rai_ipv6onlyflg;	/* AdvIPv6OnlyFlag */
+#endif
 
 	int	rai_rtpref;		/* router preference */
 	uint32_t	rai_linkmtu;		/* AdvLinkMTU */


More information about the svn-src-head mailing list