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