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
This commit is contained in:
parent
9978bd996b
commit
201100c58b
@ -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
|
||||
|
@ -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 *);
|
||||
|
@ -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.
|
||||
|
@ -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 */
|
||||
|
@ -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) \
|
||||
|
@ -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);
|
||||
|
@ -13,6 +13,8 @@
|
||||
# A PARTICULAR PURPOSE.
|
||||
# $FreeBSD$
|
||||
|
||||
.include <src.opts.mk>
|
||||
|
||||
.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 <bsd.prog.mk>
|
||||
|
@ -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]);
|
||||
|
||||
|
@ -14,11 +14,18 @@
|
||||
#
|
||||
# $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
|
||||
|
||||
WARNS?= 1
|
||||
|
@ -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);
|
||||
|
@ -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 &&
|
||||
|
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user