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 */

Reply via email to