diff --git a/sbin/ifconfig/Makefile b/sbin/ifconfig/Makefile index ae5b01682404..9e0f73bba245 100644 --- a/sbin/ifconfig/Makefile +++ b/sbin/ifconfig/Makefile @@ -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 diff --git a/sbin/ifconfig/af_nd6.c b/sbin/ifconfig/af_nd6.c index 8c576117e226..2ce97394c700 100644 --- a/sbin/ifconfig/af_nd6.c +++ b/sbin/ifconfig/af_nd6.c @@ -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 *); diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c index 28dac295e077..628e32b17642 100644 --- a/sys/net/if_ethersubr.c +++ b/sys/net/if_ethersubr.c @@ -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. diff --git a/sys/netinet/icmp6.h b/sys/netinet/icmp6.h index 310684b8b47d..d4da06d0ff5e 100644 --- a/sys/netinet/icmp6.h +++ b/sys/netinet/icmp6.h @@ -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 */ diff --git a/sys/netinet6/nd6.h b/sys/netinet6/nd6.h index cabfeec0dbac..7544d23c6660 100644 --- a/sys/netinet6/nd6.h +++ b/sys/netinet6/nd6.h @@ -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) \ diff --git a/sys/netinet6/nd6_rtr.c b/sys/netinet6/nd6_rtr.c index ec1aa13730ca..e00a0d857b5c 100644 --- a/sys/netinet6/nd6_rtr.c +++ b/sys/netinet6/nd6_rtr.c @@ -204,6 +204,37 @@ 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. * @@ -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 } /* @@ -692,6 +726,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; defrouter_delreq(dr); diff --git a/usr.sbin/ndp/Makefile b/usr.sbin/ndp/Makefile index c2ff3090b495..52d8304a436a 100644 --- a/usr.sbin/ndp/Makefile +++ b/usr.sbin/ndp/Makefile @@ -13,6 +13,8 @@ # A PARTICULAR PURPOSE. # $FreeBSD$ +.include + .PATH: ${SRCTOP}/contrib/tcpdump PROG= ndp @@ -22,6 +24,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 .include diff --git a/usr.sbin/ndp/ndp.c b/usr.sbin/ndp/ndp.c index 10e186d1d9f3..a006006aab3c 100644 --- a/usr.sbin/ndp/ndp.c +++ b/usr.sbin/ndp/ndp.c @@ -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]); diff --git a/usr.sbin/rtadvd/Makefile b/usr.sbin/rtadvd/Makefile index 5d627e55b265..920c6d966aff 100644 --- a/usr.sbin/rtadvd/Makefile +++ b/usr.sbin/rtadvd/Makefile @@ -14,11 +14,18 @@ # # $FreeBSD$ +.include + 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 WARNS?= 1 diff --git a/usr.sbin/rtadvd/config.c b/usr.sbin/rtadvd/config.c index cd7134cecae2..f537ace0c25f 100644 --- a/usr.sbin/rtadvd/config.c +++ b/usr.sbin/rtadvd/config.c @@ -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); diff --git a/usr.sbin/rtadvd/rtadvd.c b/usr.sbin/rtadvd/rtadvd.c index d46185876444..d7237f06c223 100644 --- a/usr.sbin/rtadvd/rtadvd.c +++ b/usr.sbin/rtadvd/rtadvd.c @@ -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 && diff --git a/usr.sbin/rtadvd/rtadvd.h b/usr.sbin/rtadvd/rtadvd.h index 005a42c2038a..885d2fbb3c80 100644 --- a/usr.sbin/rtadvd/rtadvd.h +++ b/usr.sbin/rtadvd/rtadvd.h @@ -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 */