From 82116c339c553fcc2c07c2e6c9679ded51b19d64 Mon Sep 17 00:00:00 2001 From: Andrew Thompson Date: Tue, 7 Jun 2005 21:20:18 +0000 Subject: [PATCH] Bring in IPFW layer2 filtering from bridge.c, this allows Ethernet filtering using the layer2, mac and mac-type keywords. This is one of the last features that bridge.c has over if_bridge and gets us very close to a full functional replacement. Approved by: mlaier (mentor) --- share/man/man4/if_bridge.4 | 20 ++++++++++-- sys/net/if_bridge.c | 67 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 82 insertions(+), 5 deletions(-) diff --git a/share/man/man4/if_bridge.4 b/share/man/man4/if_bridge.4 index 54fa1aa021c7..2e079f56ae2b 100644 --- a/share/man/man4/if_bridge.4 +++ b/share/man/man4/if_bridge.4 @@ -81,7 +81,8 @@ Spanning Tree is used to detect and remove loops in a network topology. .Pp When filtering is enabled, bridged packets will pass through the filter inbound on the originating interface, on the bridge interface and outbound on -the appropriate interfaces. This behaviour can be controlled using +the appropriate interfaces. +Either stage can be disabled, this behaviour can be controlled using .Xr sysctl 8 : .Bl -tag -width ".Va net.link.bridge.pfil_member" .It Va net.link.bridge.pfil_member @@ -98,11 +99,24 @@ to enable enable filtering on the bridge interface, set to .Li 0 to disable it. +.It Va net.link.bridge.ipfw +Set to +.Li 1 +to enable enable layer2 filtering with +.Xr ipfirewall 4 +, set to +.Li 0 +to disable it. +When ipfw is enabled pfil_bridge and pfil_member will be disabled so that IPFW +is not run twice, these can be re-enabled if desired. .El .Pp ARP and REVARP packets are forwarded without being filtered and others -that are not IP nor IPv6 packets are not forwarded when filtering is -enabled. +that are not IP nor IPv6 packets are not forwarded when +.Xr pfil 9 +filtering is enabled. +IPFW can filter Ethernet types using 'mac-type' so all packets are passed to +the filter for processing. .Pp Note that packets to and from the bridging host will be seen by the filter on the interface with the appropriate address configured as well diff --git a/sys/net/if_bridge.c b/sys/net/if_bridge.c index d6825f3b3892..53bd302549f4 100644 --- a/sys/net/if_bridge.c +++ b/sys/net/if_bridge.c @@ -253,6 +253,7 @@ SYSCTL_NODE(_net_link, IFT_BRIDGE, bridge, CTLFLAG_RW, 0, "Bridge"); static int pfil_bridge = 1; /* run pfil hooks on the bridge interface */ static int pfil_member = 1; /* run pfil hooks on the member interface */ +static int pfil_ipfw = 0; /* layer2 filter with ipfw */ SYSCTL_INT(_net_link_bridge, OID_AUTO, pfil_bridge, CTLFLAG_RW, &pfil_bridge, 0, "Packet filter on the bridge interface"); SYSCTL_INT(_net_link_bridge, OID_AUTO, pfil_member, CTLFLAG_RW, @@ -376,6 +377,35 @@ static moduledata_t bridge_mod = { DECLARE_MODULE(if_bridge, bridge_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); +/* + * handler for net.link.bridge.pfil_ipfw + */ +static int +sysctl_pfil_ipfw(SYSCTL_HANDLER_ARGS) +{ + int enable = pfil_ipfw; + int error; + + error = sysctl_handle_int(oidp, &enable, 0, req); + enable = (enable) ? 1 : 0; + + if (enable != pfil_ipfw) { + pfil_ipfw = enable; + + /* + * Disable pfil so that ipfw doesnt run twice, if the user really wants + * both then they can re-enable pfil_bridge and/or pfil_member. + */ + if (pfil_ipfw) { + pfil_bridge = 0; + pfil_member = 0; + } + } + + return error; +} +SYSCTL_PROC(_net_link_bridge, OID_AUTO, ipfw, CTLTYPE_INT|CTLFLAG_RW, + &pfil_ipfw, 0, &sysctl_pfil_ipfw, "I", "Layer2 filter with IPFW"); /* * bridge_clone_create: @@ -2109,14 +2139,25 @@ bridge_rtnode_destroy(struct bridge_softc *sc, struct bridge_rtnode *brt) static int bridge_pfil(struct mbuf **mp, struct ifnet *bifp, struct ifnet *ifp, int dir) { - int snap, error; + int snap, error, i; struct ether_header *eh1, eh2; + struct ip_fw_args args; struct ip *ip; struct llc llc; u_int16_t ether_type; snap = 0; error = -1; /* Default error if not error == 0 */ + + i = min((*mp)->m_pkthdr.len, max_protohdr); + if ((*mp)->m_len < i) { + *mp = m_pullup(*mp, i); + if (*mp == NULL) { + printf("%s: m_pullup failed\n", __func__); + return -1; + } + } + eh1 = mtod(*mp, struct ether_header *); ether_type = ntohs(eh1->ether_type); @@ -2154,7 +2195,13 @@ static int bridge_pfil(struct mbuf **mp, struct ifnet *bifp, # endif /* INET6 */ break; default: - goto bad; + /* + * ipfw allows layer2 protocol filtering using + * 'mac-type' so we will let the packet past, if + * ipfw is disabled then drop it. + */ + if (!IPFW_LOADED || pfil_ipfw == 0) + goto bad; } /* Strip off the Ethernet header and keep a copy. */ @@ -2244,6 +2291,22 @@ static int bridge_pfil(struct mbuf **mp, struct ifnet *bifp, error = -1; + if (IPFW_LOADED && pfil_ipfw != 0) { + args.m = *mp; + args.oif = NULL; + args.next_hop = NULL; + args.rule = NULL; + args.eh = &eh2; + i = ip_fw_chk_ptr(&args); + *mp = args.m; + + if (*mp == NULL) + return error; + + if (i == IP_FW_DENY) /* drop */ + goto bad; + } + /* * Finally, put everything back the way it was and return */