summaryrefslogtreecommitdiffstats
path: root/sys/net
diff options
context:
space:
mode:
authormelifaro <melifaro@FreeBSD.org>2012-09-04 19:43:26 +0000
committermelifaro <melifaro@FreeBSD.org>2012-09-04 19:43:26 +0000
commit1fbae66b6e67117d899f9c10f12c000c4584d32c (patch)
treea8022a21cc0401215271f1f78d4f500650942824 /sys/net
parent599115bdcb3939cdc5164a09fd18ccfe4c310ab1 (diff)
downloadFreeBSD-src-1fbae66b6e67117d899f9c10f12c000c4584d32c.zip
FreeBSD-src-1fbae66b6e67117d899f9c10f12c000c4584d32c.tar.gz
Introduce new link-layer PFIL hook V_link_pfil_hook.
Merge ether_ipfw_chk() and part of bridge_pfil() into unified ipfw_check_frame() function called by PFIL. This change was suggested by rwatson? @ DevSummit. Remove ipfw headers from ether/bridge code since they are unneeded now. Note this thange introduce some (temporary) performance penalty since PFIL read lock has to be acquired for every link-level packet. MFC after: 3 weeks
Diffstat (limited to 'sys/net')
-rw-r--r--sys/net/if_bridge.c71
-rw-r--r--sys/net/if_ethersubr.c194
-rw-r--r--sys/net/if_var.h3
3 files changed, 62 insertions, 206 deletions
diff --git a/sys/net/if_bridge.c b/sys/net/if_bridge.c
index f2117a3..69ff541 100644
--- a/sys/net/if_bridge.c
+++ b/sys/net/if_bridge.c
@@ -100,7 +100,6 @@ __FBSDID("$FreeBSD$");
#include <sys/proc.h>
#include <sys/lock.h>
#include <sys/mutex.h>
-#include <sys/rwlock.h>
#include <net/bpf.h>
#include <net/if.h>
@@ -131,8 +130,6 @@ __FBSDID("$FreeBSD$");
#include <net/if_vlan_var.h>
#include <net/route.h>
-#include <netinet/ip_fw.h>
-#include <netinet/ipfw/ip_fw_private.h>
/*
* Size of the route hash table. Must be a power of two.
@@ -2981,7 +2978,6 @@ bridge_pfil(struct mbuf **mp, struct ifnet *bifp, struct ifnet *ifp, int dir)
{
int snap, error, i, hlen;
struct ether_header *eh1, eh2;
- struct ip_fw_args args;
struct ip *ip;
struct llc llc1;
u_int16_t ether_type;
@@ -3055,6 +3051,16 @@ bridge_pfil(struct mbuf **mp, struct ifnet *bifp, struct ifnet *ifp, int dir)
goto bad;
}
+ /* Run the packet through pfil before stripping link headers */
+ if (PFIL_HOOKED(&V_link_pfil_hook) && pfil_ipfw != 0 &&
+ dir == PFIL_OUT && ifp != NULL) {
+
+ error = pfil_run_hooks(&V_link_pfil_hook, mp, ifp, dir, NULL);
+
+ if (*mp == NULL || error != 0) /* packet consumed by filter */
+ return (error);
+ }
+
/* Strip off the Ethernet header and keep a copy. */
m_copydata(*mp, 0, ETHER_HDR_LEN, (caddr_t) &eh2);
m_adj(*mp, ETHER_HDR_LEN);
@@ -3085,63 +3091,6 @@ bridge_pfil(struct mbuf **mp, struct ifnet *bifp, struct ifnet *ifp, int dir)
goto bad;
}
- /* XXX this section is also in if_ethersubr.c */
- // XXX PFIL_OUT or DIR_OUT ?
- if (V_ip_fw_chk_ptr && pfil_ipfw != 0 &&
- dir == PFIL_OUT && ifp != NULL) {
- struct m_tag *mtag;
-
- error = -1;
- /* fetch the start point from existing tags, if any */
- mtag = m_tag_locate(*mp, MTAG_IPFW_RULE, 0, NULL);
- if (mtag == NULL) {
- args.rule.slot = 0;
- } else {
- struct ipfw_rule_ref *r;
-
- /* XXX can we free the tag after use ? */
- mtag->m_tag_id = PACKET_TAG_NONE;
- r = (struct ipfw_rule_ref *)(mtag + 1);
- /* packet already partially processed ? */
- if (r->info & IPFW_ONEPASS)
- goto ipfwpass;
- args.rule = *r;
- }
-
- args.m = *mp;
- args.oif = ifp;
- args.next_hop = NULL;
- args.next_hop6 = NULL;
- args.eh = &eh2;
- args.inp = NULL; /* used by ipfw uid/gid/jail rules */
- i = V_ip_fw_chk_ptr(&args);
- *mp = args.m;
-
- if (*mp == NULL)
- return (error);
-
- if (ip_dn_io_ptr && (i == IP_FW_DUMMYNET)) {
-
- /* put the Ethernet header back on */
- M_PREPEND(*mp, ETHER_HDR_LEN, M_DONTWAIT);
- if (*mp == NULL)
- return (error);
- bcopy(&eh2, mtod(*mp, caddr_t), ETHER_HDR_LEN);
-
- /*
- * Pass the pkt to dummynet, which consumes it. The
- * packet will return to us via bridge_dummynet().
- */
- args.oif = ifp;
- ip_dn_io_ptr(mp, DIR_FWD | PROTO_IFB, &args);
- return (error);
- }
-
- if (i != IP_FW_PASS) /* drop */
- goto bad;
- }
-
-ipfwpass:
error = 0;
/*
diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c
index 7c62e55..ba47194 100644
--- a/sys/net/if_ethersubr.c
+++ b/sys/net/if_ethersubr.c
@@ -45,7 +45,6 @@
#include <sys/module.h>
#include <sys/mbuf.h>
#include <sys/random.h>
-#include <sys/rwlock.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#include <sys/sysctl.h>
@@ -63,6 +62,7 @@
#include <net/if_vlan_var.h>
#include <net/if_llatbl.h>
#include <net/pf_mtag.h>
+#include <net/pfil.h>
#include <net/vnet.h>
#if defined(INET) || defined(INET6)
@@ -71,8 +71,6 @@
#include <netinet/if_ether.h>
#include <netinet/ip_carp.h>
#include <netinet/ip_var.h>
-#include <netinet/ip_fw.h>
-#include <netinet/ipfw/ip_fw_private.h>
#endif
#ifdef INET6
#include <netinet6/nd6.h>
@@ -106,6 +104,8 @@ CTASSERT(sizeof (struct ether_header) == ETHER_ADDR_LEN * 2 + 2);
CTASSERT(sizeof (struct ether_addr) == ETHER_ADDR_LEN);
#endif
+VNET_DEFINE(struct pfil_head, link_pfil_hook); /* Packet filter hooks */
+
/* netgraph node hooks for ng_ether(4) */
void (*ng_ether_input_p)(struct ifnet *ifp, struct mbuf **mp);
void (*ng_ether_input_orphan_p)(struct ifnet *ifp, struct mbuf *m);
@@ -141,14 +141,6 @@ static MALLOC_DEFINE(M_ARPCOM, "arpcom", "802.* interface internals");
#define senderr(e) do { error = (e); goto bad;} while (0)
-#if defined(INET) || defined(INET6)
-int
-ether_ipfw_chk(struct mbuf **m0, struct ifnet *dst, int shared);
-static VNET_DEFINE(int, ether_ipfw);
-#define V_ether_ipfw VNET(ether_ipfw)
-#endif
-
-
/*
* Ethernet output routine.
* Encapsulate a packet of type family for the local net.
@@ -427,18 +419,17 @@ bad: if (m != NULL)
int
ether_output_frame(struct ifnet *ifp, struct mbuf *m)
{
-#if defined(INET) || defined(INET6)
+ int i;
- if (V_ip_fw_chk_ptr && V_ether_ipfw != 0) {
- if (ether_ipfw_chk(&m, ifp, 0) == 0) {
- if (m) {
- m_freem(m);
- return EACCES; /* pkt dropped */
- } else
- return 0; /* consumed e.g. in a pipe */
- }
+ if (PFIL_HOOKED(&V_link_pfil_hook)) {
+ i = pfil_run_hooks(&V_link_pfil_hook, &m, ifp, PFIL_OUT, NULL);
+
+ if (i != 0)
+ return (EACCES);
+
+ if (m == NULL)
+ return (0);
}
-#endif
/*
* Queue message on interface, update output statistics if
@@ -448,113 +439,6 @@ ether_output_frame(struct ifnet *ifp, struct mbuf *m)
}
#if defined(INET) || defined(INET6)
-/*
- * ipfw processing for ethernet packets (in and out).
- * The second parameter is NULL from ether_demux, and ifp from
- * ether_output_frame.
- */
-int
-ether_ipfw_chk(struct mbuf **m0, struct ifnet *dst, int shared)
-{
- struct ether_header *eh;
- struct ether_header save_eh;
- struct mbuf *m;
- int i;
- struct ip_fw_args args;
- struct m_tag *mtag;
-
- /* fetch start point from rule, if any */
- mtag = m_tag_locate(*m0, MTAG_IPFW_RULE, 0, NULL);
- if (mtag == NULL) {
- args.rule.slot = 0;
- } else {
- /* dummynet packet, already partially processed */
- struct ipfw_rule_ref *r;
-
- /* XXX can we free it after use ? */
- mtag->m_tag_id = PACKET_TAG_NONE;
- r = (struct ipfw_rule_ref *)(mtag + 1);
- if (r->info & IPFW_ONEPASS)
- return (1);
- args.rule = *r;
- }
-
- /*
- * I need some amt of data to be contiguous, and in case others need
- * the packet (shared==1) also better be in the first mbuf.
- */
- m = *m0;
- i = min( m->m_pkthdr.len, max_protohdr);
- if ( shared || m->m_len < i) {
- m = m_pullup(m, i);
- if (m == NULL) {
- *m0 = m;
- return 0;
- }
- }
- eh = mtod(m, struct ether_header *);
- save_eh = *eh; /* save copy for restore below */
- m_adj(m, ETHER_HDR_LEN); /* strip ethernet header */
-
- args.m = m; /* the packet we are looking at */
- args.oif = dst; /* destination, if any */
- args.next_hop = NULL; /* we do not support forward yet */
- args.next_hop6 = NULL; /* we do not support forward yet */
- args.eh = &save_eh; /* MAC header for bridged/MAC packets */
- args.inp = NULL; /* used by ipfw uid/gid/jail rules */
- i = V_ip_fw_chk_ptr(&args);
- m = args.m;
- if (m != NULL) {
- /*
- * Restore Ethernet header, as needed, in case the
- * mbuf chain was replaced by ipfw.
- */
- M_PREPEND(m, ETHER_HDR_LEN, M_DONTWAIT);
- if (m == NULL) {
- *m0 = m;
- return 0;
- }
- if (eh != mtod(m, struct ether_header *))
- bcopy(&save_eh, mtod(m, struct ether_header *),
- ETHER_HDR_LEN);
- }
- *m0 = m;
-
- if (i == IP_FW_DENY) /* drop */
- return 0;
-
- KASSERT(m != NULL, ("ether_ipfw_chk: m is NULL"));
-
- if (i == IP_FW_PASS) /* a PASS rule. */
- return 1;
-
- if (ip_dn_io_ptr && (i == IP_FW_DUMMYNET)) {
- int dir;
- /*
- * Pass the pkt to dummynet, which consumes it.
- * If shared, make a copy and keep the original.
- */
- if (shared) {
- m = m_copypacket(m, M_DONTWAIT);
- if (m == NULL)
- return 0;
- } else {
- /*
- * Pass the original to dummynet and
- * nothing back to the caller
- */
- *m0 = NULL ;
- }
- dir = PROTO_LAYER2 | (dst ? DIR_OUT : DIR_IN);
- ip_dn_io_ptr(&m, dir, &args);
- return 0;
- }
- /*
- * XXX at some point add support for divert/forward actions.
- * If none of the above matches, we have to drop the pkt.
- */
- return 0;
-}
#endif
/*
@@ -788,6 +672,35 @@ ether_init(__unused void *arg)
SYSINIT(ether, SI_SUB_INIT_IF, SI_ORDER_ANY, ether_init, NULL);
static void
+vnet_ether_init(__unused void *arg)
+{
+ int i;
+
+ /* Initialize packet filter hooks. */
+ V_link_pfil_hook.ph_type = PFIL_TYPE_AF;
+ V_link_pfil_hook.ph_af = AF_LINK;
+ if ((i = pfil_head_register(&V_link_pfil_hook)) != 0)
+ printf("%s: WARNING: unable to register pfil link hook, "
+ "error %d\n", __func__, i);
+}
+VNET_SYSINIT(vnet_ether_init, SI_SUB_PROTO_IF, SI_ORDER_ANY,
+ vnet_ether_init, NULL);
+
+static void
+vnet_ether_destroy(__unused void *arg)
+{
+ int i;
+
+ if ((i = pfil_head_unregister(&V_link_pfil_hook)) != 0)
+ printf("%s: WARNING: unable to unregister pfil link hook, "
+ "error %d\n", __func__, i);
+}
+VNET_SYSUNINIT(vnet_ether_uninit, SI_SUB_PROTO_IF, SI_ORDER_ANY,
+ vnet_ether_destroy, NULL);
+
+
+
+static void
ether_input(struct ifnet *ifp, struct mbuf *m)
{
@@ -807,7 +720,7 @@ void
ether_demux(struct ifnet *ifp, struct mbuf *m)
{
struct ether_header *eh;
- int isr;
+ int i, isr;
u_short ether_type;
#if defined(NETATALK)
struct llc *l;
@@ -815,19 +728,14 @@ ether_demux(struct ifnet *ifp, struct mbuf *m)
KASSERT(ifp != NULL, ("%s: NULL interface pointer", __func__));
-#if defined(INET) || defined(INET6)
- /*
- * Allow dummynet and/or ipfw to claim the frame.
- * Do not do this for PROMISC frames in case we are re-entered.
- */
- if (V_ip_fw_chk_ptr && V_ether_ipfw != 0 && !(m->m_flags & M_PROMISC)) {
- if (ether_ipfw_chk(&m, NULL, 0) == 0) {
- if (m)
- m_freem(m); /* dropped; free mbuf chain */
- return; /* consumed */
- }
+ /* Do not grab PROMISC frames in case we are re-entered. */
+ if (PFIL_HOOKED(&V_link_pfil_hook) && !(m->m_flags & M_PROMISC)) {
+ i = pfil_run_hooks(&V_link_pfil_hook, &m, ifp, PFIL_IN, NULL);
+
+ if (i != 0 || m == NULL)
+ return;
}
-#endif
+
eh = mtod(m, struct ether_header *);
ether_type = ntohs(eh->ether_type);
@@ -1056,10 +964,6 @@ ether_reassign(struct ifnet *ifp, struct vnet *new_vnet, char *unused __unused)
SYSCTL_DECL(_net_link);
SYSCTL_NODE(_net_link, IFT_ETHER, ether, CTLFLAG_RW, 0, "Ethernet");
-#if defined(INET) || defined(INET6)
-SYSCTL_VNET_INT(_net_link_ether, OID_AUTO, ipfw, CTLFLAG_RW,
- &VNET_NAME(ether_ipfw), 0, "Pass ether pkts through firewall");
-#endif
#if 0
/*
diff --git a/sys/net/if_var.h b/sys/net/if_var.h
index a244359..74491c6 100644
--- a/sys/net/if_var.h
+++ b/sys/net/if_var.h
@@ -99,6 +99,9 @@ TAILQ_HEAD(ifaddrhead, ifaddr); /* instantiation is preserved in the list */
TAILQ_HEAD(ifmultihead, ifmultiaddr);
TAILQ_HEAD(ifgrouphead, ifg_group);
+VNET_DECLARE(struct pfil_head, link_pfil_hook); /* packet filter hooks */
+#define V_link_pfil_hook VNET(link_pfil_hook)
+
/*
* Structure defining a queue for a network interface.
*/
OpenPOWER on IntegriCloud