Hello there,
Here is my patch that adds support for creating IPv6-only or
IPv4-only bridges. This is different from simply blocking one of the
protocols via PF - it allows you to create a setup where IPv4 is routed
and IPv6 is bridged (or vice versa). Both of them being filtered by the
same set of PF rules. It adds two new bridge port options to ifconfig -
BLOCKIPV4 and BLOCKIPV6. BLOCKIPV4 also stops ARPs requests from
"leaking" across the bridge - something I couldn't accomplish by PF alone.
The patch breaks the binary compatibility of ifconfig - it must be
rebuilt with the new kernel.
I don't know if anyone will find any use for it. For sure it is
very useful with the second-biggest FTTH/ADSL operator in France who
offers consumer-grade IPv6 access with an indivisible /64 network that
must be bridged for firewalling (and a single IPv4/32 address that must
be NATted).
Patch is against -current, any comments are welcome.
Index: sbin/ifconfig/brconfig.c
===================================================================
RCS file: /cvs/src/sbin/ifconfig/brconfig.c,v
retrieving revision 1.9
diff -u -p -u -r1.9 brconfig.c
--- sbin/ifconfig/brconfig.c 18 Jul 2015 06:50:24 -0000 1.9
+++ sbin/ifconfig/brconfig.c 16 Mar 2016 19:37:44 -0000
@@ -59,7 +59,7 @@ void bridge_showrule(struct ifbrlreq *);
#define IFBAFBITS "\020\1STATIC"
#define IFBIFBITS \
-"\020\1LEARNING\2DISCOVER\3BLOCKNONIP\4STP\5EDGE\6AUTOEDGE\7PTP\10AUTOPTP\11SPAN"
+"\020\1LEARNING\2DISCOVER\3BLOCKNONIP\4STP\5EDGE\6AUTOEDGE\7PTP\10AUTOPTP\11BLOCKIPV4\12BLOCKIPV6\15SPAN"
#define PV2ID(pv, epri, eaddr) do { \
epri = pv >> 48; \
@@ -93,102 +93,28 @@ char *stproles[] = {
};
-void
-setdiscover(const char *val, int d)
-{
- bridge_ifsetflag(val, IFBIF_DISCOVER);
-}
-
-void
-unsetdiscover(const char *val, int d)
-{
- bridge_ifclrflag(val, IFBIF_DISCOVER);
-}
-
-void
-setblocknonip(const char *val, int d)
-{
- bridge_ifsetflag(val, IFBIF_BLOCKNONIP);
-}
-
-void
-unsetblocknonip(const char *val, int d)
-{
- bridge_ifclrflag(val, IFBIF_BLOCKNONIP);
-}
-
-void
-setlearn(const char *val, int d)
-{
- bridge_ifsetflag(val, IFBIF_LEARNING);
-}
-
-void
-unsetlearn(const char *val, int d)
-{
- bridge_ifclrflag(val, IFBIF_LEARNING);
-}
-
-void
-setstp(const char *val, int d)
-{
- bridge_ifsetflag(val, IFBIF_STP);
-}
-
-void
-unsetstp(const char *val, int d)
-{
- bridge_ifclrflag(val, IFBIF_STP);
-}
-
-void
-setedge(const char *val, int d)
-{
- bridge_ifsetflag(val, IFBIF_BSTP_EDGE);
-}
-
-void
-unsetedge(const char *val, int d)
-{
- bridge_ifclrflag(val, IFBIF_BSTP_EDGE);
-}
-
-void
-setautoedge(const char *val, int d)
-{
- bridge_ifsetflag(val, IFBIF_BSTP_AUTOEDGE);
-}
-
-void
-unsetautoedge(const char *val, int d)
-{
- bridge_ifclrflag(val, IFBIF_BSTP_AUTOEDGE);
-}
-
-void
-setptp(const char *val, int d)
-{
- bridge_ifsetflag(val, IFBIF_BSTP_PTP);
-}
-
-void
-unsetptp(const char *val, int d)
-{
- bridge_ifclrflag(val, IFBIF_BSTP_PTP);
-}
-
-void
-setautoptp(const char *val, int d)
-{
- bridge_ifsetflag(val, IFBIF_BSTP_AUTOPTP);
-}
-
-void
-unsetautoptp(const char *val, int d)
-{
- bridge_ifclrflag(val, IFBIF_BSTP_AUTOPTP);
-}
-
+#define IFBIF_SETUNSET(NAME,FLAG) \
+ void \
+ set ## NAME (const char *val, int d) \
+ { \
+ bridge_ifsetflag(val, FLAG); \
+ } \
+ void \
+ unset ## NAME (const char *val, int d) \
+ { \
+ bridge_ifclrflag(val, FLAG); \
+ }
+
+IFBIF_SETUNSET(discover,IFBIF_DISCOVER)
+IFBIF_SETUNSET(blocknonip,IFBIF_BLOCKNONIP)
+IFBIF_SETUNSET(blockipv4,IFBIF_BLOCKIPV4)
+IFBIF_SETUNSET(blockipv6,IFBIF_BLOCKIPV6)
+IFBIF_SETUNSET(learn,IFBIF_LEARNING)
+IFBIF_SETUNSET(stp,IFBIF_STP)
+IFBIF_SETUNSET(edge,IFBIF_BSTP_EDGE)
+IFBIF_SETUNSET(autoedge,IFBIF_BSTP_AUTOEDGE)
+IFBIF_SETUNSET(ptp,IFBIF_BSTP_PTP)
+IFBIF_SETUNSET(autoptp,IFBIF_BSTP_AUTOPTP)
void
bridge_ifsetflag(const char *ifsname, u_int32_t flag)
Index: sbin/ifconfig/brconfig.h
===================================================================
RCS file: /cvs/src/sbin/ifconfig/brconfig.h,v
retrieving revision 1.9
diff -u -p -u -r1.9 brconfig.h
--- sbin/ifconfig/brconfig.h 7 Jan 2016 15:33:56 -0000 1.9
+++ sbin/ifconfig/brconfig.h 16 Mar 2016 19:37:44 -0000
@@ -25,6 +25,10 @@ void setdiscover(const char *, int);
void unsetdiscover(const char *, int);
void setblocknonip(const char *, int);
void unsetblocknonip(const char *, int);
+void setblockipv4(const char *, int);
+void unsetblockipv4(const char *, int);
+void setblockipv6(const char *, int);
+void unsetblockipv6(const char *, int);
void setlearn(const char *, int);
void unsetlearn(const char *, int);
void setstp(const char *, int);
Index: sbin/ifconfig/ifconfig.8
===================================================================
RCS file: /cvs/src/sbin/ifconfig/ifconfig.8,v
retrieving revision 1.266
diff -u -p -u -r1.266 ifconfig.8
--- sbin/ifconfig/ifconfig.8 28 Feb 2016 21:55:36 -0000 1.266
+++ sbin/ifconfig/ifconfig.8 16 Mar 2016 19:37:44 -0000
@@ -564,6 +564,24 @@ bridge member interfaces.
.It Cm -blocknonip Ar interface
Allow non-IPv4, IPv6, ARP, or Reverse ARP packets through
.Ar interface .
+.It Cm blockipv4 Ar interface
+Mark
+.Ar interface
+so that no IPv4 or ARP
+packets are accepted from it or forwarded to it from other
+bridge member interfaces. Allows the creation of IPv6-only bridges
+.It Cm -blockipv4 Ar interface
+Allow IPv4 or ARP packets through
+.Ar interface .
+.It Cm blockipv6 Ar interface
+Mark
+.Ar interface
+so that no IPv6
+packets are accepted from it or forwarded to it from other
+bridge member interfaces. Allows the creation of IPv4-only bridges
+.It Cm -blockipv6 Ar interface
+Allow IPv6 packets through
+.Ar interface .
.It Cm del Ar interface
Remove
.Ar interface
Index: sbin/ifconfig/ifconfig.c
===================================================================
RCS file: /cvs/src/sbin/ifconfig/ifconfig.c,v
retrieving revision 1.317
diff -u -p -u -r1.317 ifconfig.c
--- sbin/ifconfig/ifconfig.c 2 Mar 2016 19:45:10 -0000 1.317
+++ sbin/ifconfig/ifconfig.c 16 Mar 2016 19:37:44 -0000
@@ -450,6 +450,10 @@ const struct cmd {
{ "-discover", NEXTARG, 0, unsetdiscover },
{ "blocknonip", NEXTARG, 0, setblocknonip },
{ "-blocknonip",NEXTARG, 0, unsetblocknonip },
+ { "blockipv4", NEXTARG, 0, setblockipv4 },
+ { "-blockipv4", NEXTARG, 0, unsetblockipv4 },
+ { "blockipv6", NEXTARG, 0, setblockipv6 },
+ { "-blockipv6", NEXTARG, 0, unsetblockipv6 },
{ "learn", NEXTARG, 0, setlearn },
{ "-learn", NEXTARG, 0, unsetlearn },
{ "stp", NEXTARG, 0, setstp },
Index: sys/net/if_bridge.c
===================================================================
RCS file: /cvs/src/sys/net/if_bridge.c,v
retrieving revision 1.276
diff -u -p -u -r1.276 if_bridge.c
--- sys/net/if_bridge.c 8 Mar 2016 09:09:43 -0000 1.276
+++ sys/net/if_bridge.c 16 Mar 2016 19:37:44 -0000
@@ -122,7 +122,7 @@ void bridge_stop(struct bridge_softc *);
void bridge_init(struct bridge_softc *);
int bridge_bifconf(struct bridge_softc *, struct ifbifconf *);
-int bridge_blocknonip(struct ether_header *, struct mbuf *);
+int bridge_blockiptype(struct ether_header *, struct mbuf *, u_int32_t);
struct mbuf *bridge_ip(struct bridge_softc *, int, struct ifnet *,
struct ether_header *, struct mbuf *m);
int bridge_ifenqueue(struct bridge_softc *, struct ifnet *, struct
mbuf *);
@@ -783,6 +783,14 @@ bridge_output(struct ifnet *ifp, struct
(p->bif_flags & IFBIF_STP) &&
(p->bif_state == BSTP_IFSTATE_DISCARDING))
continue;
+
+ /* If we are blocking protocol types
+ * send this packet only if this was the
+ * original output interface
+ */
+ if (dst_if != ifp
+ && bridge_blockiptype(eh, m, p->bif_flags))
+ continue;
#if NMPW > 0
/*
* Split horizon: avoid broadcasting messages from
@@ -960,7 +968,7 @@ bridgeintr_frame(struct bridge_softc *sc
}
}
- if (ifl->bif_flags & IFBIF_BLOCKNONIP && bridge_blocknonip(&eh, m)) {
+ if (bridge_blockiptype(&eh, m, ifl->bif_flags)) {
m_freem(m);
return;
}
@@ -1196,9 +1204,8 @@ bridge_broadcast(struct bridge_softc *sc
(m->m_flags & (M_BCAST | M_MCAST)) == 0)
continue;
- /* Drop non-IP frames if the appropriate flag is set. */
- if (p->bif_flags & IFBIF_BLOCKNONIP &&
- bridge_blocknonip(eh, m))
+ /* Drop frames if the appropriate flag is set. */
+ if (bridge_blockiptype(eh, m, p->bif_flags))
continue;
if (bridge_filterrule(&p->bif_brlout, eh, m) == BRL_ACTION_BLOCK)
@@ -1317,20 +1324,25 @@ bridge_span(struct bridge_softc *sc, str
}
/*
- * Block non-ip frames:
- * Returns 0 if frame is ip, and 1 if it should be dropped.
+ * Block frames by type : non-IP, IPv4 or IPv6 :
+ * Returns 0 if frame is the right type, and 1 if it should be dropped.
*/
int
-bridge_blocknonip(struct ether_header *eh, struct mbuf *m)
+bridge_blockiptype(struct ether_header *eh, struct mbuf *m, u_int32_t
flags)
{
struct llc llc;
u_int16_t etype;
- if (m->m_pkthdr.len < ETHER_HDR_LEN)
- return (1);
+ if (m->m_pkthdr.len < ETHER_HDR_LEN) {
+ if ((flags & IFBIF_BLOCKNONIP) == IFBIF_BLOCKNONIP)
+ return (1);
+ return (0);
+ }
#if NVLAN > 0
- if (m->m_flags & M_VLANTAG)
+ /* TODO: Should VLAN-tagged packets be considered non-IP? */
+ if ((m->m_flags & M_VLANTAG) &&
+ (flags & IFBIF_BLOCKNONIP) == IFBIF_BLOCKNONIP)
return (1);
#endif
@@ -1339,16 +1351,25 @@ bridge_blocknonip(struct ether_header *e
case ETHERTYPE_ARP:
case ETHERTYPE_REVARP:
case ETHERTYPE_IP:
+ if ((flags & IFBIF_BLOCKIPV4) == IFBIF_BLOCKIPV4)
+ return 1;
+ return 0;
case ETHERTYPE_IPV6:
+ if ((flags & IFBIF_BLOCKIPV6) == IFBIF_BLOCKIPV6)
+ return 1;
return (0);
}
- if (etype > ETHERMTU)
+ if ((etype > ETHERMTU) &&
+ (flags & IFBIF_BLOCKNONIP) == IFBIF_BLOCKNONIP)
return (1);
if (m->m_pkthdr.len <
- (ETHER_HDR_LEN + LLC_SNAPFRAMELEN))
- return (1);
+ (ETHER_HDR_LEN + LLC_SNAPFRAMELEN)) {
+ if ((flags & IFBIF_BLOCKNONIP) == IFBIF_BLOCKNONIP)
+ return (1);
+ return (0);
+ }
m_copydata(m, ETHER_HDR_LEN, LLC_SNAPFRAMELEN,
(caddr_t)&llc);
@@ -1359,13 +1380,23 @@ bridge_blocknonip(struct ether_header *e
llc.llc_control == LLC_UI &&
llc.llc_snap.org_code[0] == 0 &&
llc.llc_snap.org_code[1] == 0 &&
- llc.llc_snap.org_code[2] == 0 &&
- (etype == ETHERTYPE_ARP || etype == ETHERTYPE_REVARP ||
- etype == ETHERTYPE_IP || etype == ETHERTYPE_IPV6)) {
+ llc.llc_snap.org_code[2] == 0) {
+ if (etype == ETHERTYPE_IPV6 &&
+ (flags & IFBIF_BLOCKIPV6) == IFBIF_BLOCKIPV6)
+ return 1;
+ if ((etype == ETHERTYPE_IP ||
+ etype == ETHERTYPE_ARP ||
+ etype == ETHERTYPE_REVARP) &&
+ (flags & IFBIF_BLOCKIPV4) == IFBIF_BLOCKIPV4)
+ return 1;
+ if ((flags & IFBIF_BLOCKNONIP) == IFBIF_BLOCKNONIP)
+ return (1);
return (0);
}
- return (1);
+ if ((flags & IFBIF_BLOCKNONIP) == IFBIF_BLOCKNONIP)
+ return (1);
+ return (0);
}
#ifdef IPSEC
Index: sys/net/if_bridge.h
===================================================================
RCS file: /cvs/src/sys/net/if_bridge.h,v
retrieving revision 1.48
diff -u -p -u -r1.48 if_bridge.h
--- sys/net/if_bridge.h 1 Dec 2015 18:28:29 -0000 1.48
+++ sys/net/if_bridge.h 16 Mar 2016 19:37:44 -0000
@@ -70,8 +70,10 @@ struct ifbreq {
#define IFBIF_BSTP_AUTOEDGE 0x0020 /* member stp autoedge enabled */
#define IFBIF_BSTP_PTP 0x0040 /* member stp ptp */
#define IFBIF_BSTP_AUTOPTP 0x0080 /* member stp autoptp enabled */
-#define IFBIF_SPAN 0x0100 /* ifs is a span port (ro) */
-#define IFBIF_RO_MASK 0xff00 /* read only bits */
+#define IFBIF_BLOCKIPV4 0x0100 /* ifs blocks IPv4 in/out */
+#define IFBIF_BLOCKIPV6 0x0200 /* ifs blocks IPv6 in/out */
+#define IFBIF_SPAN 0x1000 /* ifs is a span port (ro) */
+#define IFBIF_RO_MASK 0xf000 /* read only bits */
/* SIOCBRDGFLUSH */
#define IFBF_FLUSHDYN 0x0 /* flush dynamic addresses only */