On Wed, Mar 16, 2016 at 08:54:22PM +0100, Momtchil Momtchev wrote:
> 
>     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.

Fwiw, i've tested it here on my macppc gateway with the said ISP, and it
works fine.

$cat /etc/hostname.bridge0
add axe0
add gem0
blockipv4 gem0
rtsol
up

$ifconfig bridge0
bridge0: flags=200041<UP,RUNNING,AUTOCONF6>
        groups: bridge
        priority 32768 hellotime 2 fwddelay 15 maxage 20 holdcnt 6 proto rstp
        designated: id 00:00:00:00:00:00 priority 0
        axe0 flags=3<LEARNING,DISCOVER>
                port 5 ifpriority 0 ifcost 0
        gem0 flags=103<LEARNING,DISCOVER,BLOCKIPV4>
                port 2 ifpriority 0 ifcost 0
        Addresses (max cache: 100, timeout: 240):
                00:24:d4:b9:3c:63 axe0 1 flags=0<>
                00:1e:4f:94:e1:78 gem0 1 flags=0<>

(gem0 is my LAN iface, axe0 is the ISP-side with my public v4)

On a v4-natted host on the LAN side, ifconfig em0 inet6 autoconf gets me
a pair of v6 address in the /64 netblock assigned by the ISP, and i can
ping6 outside of my gw. Of course, i can still ping outside via natted
v4 :) http://ipv6.whatismyv6.com/ gives me the correct v6 ip too.

Here's the unmangled diff without the set/unset* refactoring, manually
applied and hopefully fixed wrt style(9).

Thanks for your work on this !

Landry
Index: sbin/ifconfig/brconfig.c
===================================================================
RCS file: /cvs/src/sbin/ifconfig/brconfig.c,v
retrieving revision 1.9
diff -u -r1.9 brconfig.c
--- sbin/ifconfig/brconfig.c    18 Jul 2015 06:50:24 -0000      1.9
+++ sbin/ifconfig/brconfig.c    20 Mar 2016 09:05:48 -0000
@@ -59,7 +59,7 @@
 
 #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;                                            \
@@ -115,6 +115,30 @@
 unsetblocknonip(const char *val, int d)
 {
        bridge_ifclrflag(val, IFBIF_BLOCKNONIP);
+}
+
+void
+setblockipv4(const char *val, int d)
+{
+       bridge_ifsetflag(val, IFBIF_BLOCKIPV4);
+}
+
+void
+unsetblockipv4(const char *val, int d)
+{
+       bridge_ifclrflag(val, IFBIF_BLOCKIPV4);
+}
+
+void
+setblockipv6(const char *val, int d)
+{
+       bridge_ifsetflag(val, IFBIF_BLOCKIPV6);
+}
+
+void
+unsetblockipv6(const char *val, int d)
+{
+       bridge_ifclrflag(val, IFBIF_BLOCKIPV6);
 }
 
 void
Index: sbin/ifconfig/brconfig.h
===================================================================
RCS file: /cvs/src/sbin/ifconfig/brconfig.h,v
retrieving revision 1.9
diff -u -r1.9 brconfig.h
--- sbin/ifconfig/brconfig.h    7 Jan 2016 15:33:56 -0000       1.9
+++ sbin/ifconfig/brconfig.h    20 Mar 2016 09:05:48 -0000
@@ -25,6 +25,10 @@
 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 -r1.266 ifconfig.8
--- sbin/ifconfig/ifconfig.8    28 Feb 2016 21:55:36 -0000      1.266
+++ sbin/ifconfig/ifconfig.8    20 Mar 2016 09:05:49 -0000
@@ -564,6 +564,24 @@
 .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 -r1.317 ifconfig.c
--- sbin/ifconfig/ifconfig.c    2 Mar 2016 19:45:10 -0000       1.317
+++ sbin/ifconfig/ifconfig.c    20 Mar 2016 09:05:50 -0000
@@ -450,6 +450,10 @@
        { "-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 -r1.276 if_bridge.c
--- sys/net/if_bridge.c 8 Mar 2016 09:09:43 -0000       1.276
+++ sys/net/if_bridge.c 20 Mar 2016 09:05:50 -0000
@@ -122,7 +122,7 @@
 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 @@
                            (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 @@
                }
        }
 
-       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 @@
                    (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 @@
 }
 
 /*
- * 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 @@
        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 @@
            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 -r1.48 if_bridge.h
--- sys/net/if_bridge.h 1 Dec 2015 18:28:29 -0000       1.48
+++ sys/net/if_bridge.h 20 Mar 2016 09:05:51 -0000
@@ -70,8 +70,10 @@
 #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