summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/modules/bridge/Makefile10
-rw-r--r--sys/net/bridge.c42
-rw-r--r--sys/net/pfil.c356
-rw-r--r--sys/net/pfil.h68
-rw-r--r--sys/netinet/ip_input.c41
-rw-r--r--sys/netinet/ip_output.c27
-rw-r--r--sys/netinet/ip_var.h4
-rw-r--r--sys/netinet6/ip6_forward.c28
-rw-r--r--sys/netinet6/ip6_input.c39
-rw-r--r--sys/netinet6/ip6_output.c26
-rw-r--r--sys/netinet6/ip6_var.h4
-rw-r--r--sys/netinet6/ip6protosw.h6
-rw-r--r--sys/sys/param.h2
-rw-r--r--sys/sys/protosw.h6
14 files changed, 425 insertions, 234 deletions
diff --git a/sys/modules/bridge/Makefile b/sys/modules/bridge/Makefile
index d2c1e32..70f6b40 100644
--- a/sys/modules/bridge/Makefile
+++ b/sys/modules/bridge/Makefile
@@ -3,5 +3,15 @@
.PATH: ${.CURDIR}/../../net
KMOD= bridge
SRCS= bridge.c
+SRCS+= opt_pfil_hooks.h
+
+#
+# By default don't enable pfil hooks support. This means you
+# cannot use ipfilter together with the bridge. To enable it
+# uncomment the line below
+#
+opt_pfil_hooks.h:
+# echo "#define PFIL_HOOKS 1" > opt_pfil_hooks.h
+ touch opt_pfil_hooks.h
.include <bsd.kmod.mk>
diff --git a/sys/net/bridge.c b/sys/net/bridge.c
index fa9b504..d0fa2d9 100644
--- a/sys/net/bridge.c
+++ b/sys/net/bridge.c
@@ -87,6 +87,7 @@
* - be very careful when bridging VLANs
* - loop detection is still not very robust.
*/
+#include "opt_pfil_hooks.h"
#include <sys/param.h>
#include <sys/mbuf.h>
@@ -98,7 +99,6 @@
#include <sys/kernel.h>
#include <sys/sysctl.h>
-#include <net/pfil.h> /* for ipfilter */
#include <net/if.h>
#include <net/if_types.h>
#include <net/if_var.h>
@@ -109,6 +109,11 @@
#include <netinet/ip.h>
#include <netinet/if_ether.h> /* for struct arpcom */
+#ifdef PFIL_HOOKS
+#include <net/pfil.h>
+#include <netinet/ip_var.h>
+#endif
+
#include <net/route.h>
#include <netinet/ip_fw.h>
#include <netinet/ip_dummynet.h>
@@ -160,7 +165,6 @@ struct cluster_softc {
extern struct protosw inetsw[]; /* from netinet/ip_input.c */
-extern u_char ip_protox[]; /* from netinet/ip_input.c */
static int n_clusters; /* number of clusters */
static struct cluster_softc *clusters;
@@ -715,6 +719,7 @@ bridge_dst_lookup(struct ether_header *eh, struct cluster_softc *c)
* Lookup local addresses in case one matches. We optimize
* for the common case of two interfaces.
*/
+ KASSERT(c->ports != 0, ("lookup with no ports!"));
switch (c->ports) {
int i;
default:
@@ -914,10 +919,6 @@ bdg_forward(struct mbuf *m0, struct ifnet *dst)
int shared = bdg_copy; /* someone else is using the mbuf */
struct ifnet *real_dst = dst; /* real dst from ether_output */
struct ip_fw_args args;
-#ifdef PFIL_HOOKS
- struct packet_filter_hook *pfh;
- int rv;
-#endif /* PFIL_HOOKS */
struct ether_header save_eh;
struct mbuf *m;
@@ -969,7 +970,7 @@ bdg_forward(struct mbuf *m0, struct ifnet *dst)
*/
if (src != NULL && (
#ifdef PFIL_HOOKS
- ((pfh = pfil_hook_get(PFIL_IN, &inetsw[ip_protox[IPPROTO_IP]].pr_pfh)) != NULL && bdg_ipf !=0) ||
+ (inet_pfil_hook.ph_busy_count >= 0 && bdg_ipf != 0) ||
#endif
(IPFW_LOADED && bdg_ipfw != 0))) {
@@ -1006,8 +1007,9 @@ bdg_forward(struct mbuf *m0, struct ifnet *dst)
* NetBSD-style generic packet filter, pfil(9), hooks.
* Enables ipf(8) in bridging.
*/
- if (pfh != NULL && m0->m_pkthdr.len >= sizeof(struct ip) &&
- ntohs(save_eh.ether_type) == ETHERTYPE_IP) {
+ if (inet_pfil_hook.ph_busy_count >= 0 &&
+ m0->m_pkthdr.len >= sizeof(struct ip) &&
+ ntohs(save_eh.ether_type) == ETHERTYPE_IP) {
/*
* before calling the firewall, swap fields the same as IP does.
* here we assume the pkt is an IP one and the header is contiguous
@@ -1017,20 +1019,14 @@ bdg_forward(struct mbuf *m0, struct ifnet *dst)
ip->ip_len = ntohs(ip->ip_len);
ip->ip_off = ntohs(ip->ip_off);
- do {
- if (pfh->pfil_func) {
- rv = pfh->pfil_func(ip, ip->ip_hl << 2, src, 0, &m0);
- if (m0 == NULL) {
- bdg_dropped++;
- return NULL;
- }
- if (rv != 0) {
- EH_RESTORE(m0); /* restore Ethernet header */
- return m0;
- }
- ip = mtod(m0, struct ip *);
- }
- } while ((pfh = TAILQ_NEXT(pfh, pfil_link)) != NULL);
+ if (pfil_run_hooks(&inet_pfil_hook, &m0, src, PFIL_IN) != 0) {
+ EH_RESTORE(m0); /* restore Ethernet header */
+ return m0;
+ }
+ if (m0 == NULL) {
+ bdg_dropped++;
+ return NULL;
+ }
/*
* If we get here, the firewall has passed the pkt, but the mbuf
* pointer might have changed. Restore ip and the fields ntohs()'d.
diff --git a/sys/net/pfil.c b/sys/net/pfil.c
index 2ed40b2..c995ec2 100644
--- a/sys/net/pfil.c
+++ b/sys/net/pfil.c
@@ -1,4 +1,5 @@
-/* $FreeBSD$ */
+/* $FreeBSD$ */
+/* $NetBSD: pfil.c,v 1.20 2001/11/12 23:49:46 lukem Exp $ */
/*
* Copyright (c) 1996 Matthew R. Green
@@ -29,30 +30,198 @@
*/
#include <sys/param.h>
+#include <sys/kernel.h>
#include <sys/errno.h>
#include <sys/malloc.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/systm.h>
+#include <sys/condvar.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/proc.h>
#include <sys/queue.h>
#include <net/if.h>
#include <net/pfil.h>
-static void pfil_init(struct pfil_head *);
-static int pfil_list_add(pfil_list_t *,
- int (*)(void *, int, struct ifnet *, int, struct mbuf **), int);
+static struct mtx pfil_global_lock;
+
+MTX_SYSINIT(pfil_heads_lock, &pfil_global_lock, "pfil_head_list lock", MTX_DEF);
+
+static int pfil_list_add(pfil_list_t *, struct packet_filter_hook *, int);
+
static int pfil_list_remove(pfil_list_t *,
- int (*)(void *, int, struct ifnet *, int, struct mbuf **));
+ int (*)(void *, struct mbuf **, struct ifnet *, int), void *);
+
+LIST_HEAD(, pfil_head) pfil_head_list =
+ LIST_HEAD_INITIALIZER(&pfil_head_list);
+
+static __inline void
+PFIL_RLOCK(struct pfil_head *ph)
+{
+ mtx_lock(&ph->ph_mtx);
+ ph->ph_busy_count++;
+ mtx_unlock(&ph->ph_mtx);
+}
+
+static __inline void
+PFIL_RUNLOCK(struct pfil_head *ph)
+{
+ mtx_lock(&ph->ph_mtx);
+ ph->ph_busy_count--;
+ if (ph->ph_busy_count == 0 && ph->ph_want_write)
+ cv_signal(&ph->ph_cv);
+ mtx_unlock(&ph->ph_mtx);
+}
+
+static __inline void
+PFIL_WLOCK(struct pfil_head *ph)
+{
+ mtx_lock(&ph->ph_mtx);
+ ph->ph_want_write = 1;
+ while (ph->ph_busy_count > 0)
+ cv_wait(&ph->ph_cv, &ph->ph_mtx);
+}
+
+static __inline int
+PFIL_TRY_WLOCK(struct pfil_head *ph)
+{
+ mtx_lock(&ph->ph_mtx);
+ ph->ph_want_write = 1;
+ if (ph->ph_busy_count > 0) {
+ ph->ph_want_write = 0;
+ mtx_unlock(&ph->ph_mtx);
+ return EBUSY;
+ }
+ return 0;
+}
+
+static __inline void
+PFIL_WUNLOCK(struct pfil_head *ph)
+{
+ ph->ph_want_write = 0; \
+ mtx_unlock(&ph->ph_mtx);
+ cv_signal(&ph->ph_cv);
+}
-static void
-pfil_init(ph)
- struct pfil_head *ph;
+#define PFIL_LIST_LOCK() mtx_lock(&pfil_global_lock)
+#define PFIL_LIST_UNLOCK() mtx_unlock(&pfil_global_lock)
+
+/*
+ * pfil_run_hooks() runs the specified packet filter hooks.
+ */
+int
+pfil_run_hooks(struct pfil_head *ph, struct mbuf **mp, struct ifnet *ifp,
+ int dir)
{
+ struct packet_filter_hook *pfh;
+ struct mbuf *m = *mp;
+ int rv = 0;
+
+ if (ph->ph_busy_count == -1 || ph->ph_want_write)
+ return (0);
+
+ PFIL_RLOCK(ph);
+ for (pfh = pfil_hook_get(dir, ph); pfh != NULL;
+ pfh = TAILQ_NEXT(pfh, pfil_link)) {
+ if (pfh->pfil_func != NULL) {
+ rv = (*pfh->pfil_func)(pfh->pfil_arg, &m, ifp, dir);
+ if (rv != 0 || m == NULL)
+ break;
+ }
+ }
+ PFIL_RUNLOCK(ph);
+
+ *mp = m;
+ return (rv);
+}
+
+/*
+ * pfil_head_register() registers a pfil_head with the packet filter
+ * hook mechanism.
+ */
+int
+pfil_head_register(struct pfil_head *ph)
+{
+ struct pfil_head *lph;
+
+ PFIL_LIST_LOCK();
+ LIST_FOREACH(lph, &pfil_head_list, ph_list)
+ if (ph->ph_type == lph->ph_type &&
+ ph->ph_un.phu_val == lph->ph_un.phu_val) {
+ PFIL_LIST_UNLOCK();
+ return EEXIST;
+ }
+ PFIL_LIST_UNLOCK();
+
+ if (mtx_initialized(&ph->ph_mtx)) { /* should not happen */
+ KASSERT((0), ("%s: allready initialized!", __func__));
+ return EBUSY;
+ } else {
+ ph->ph_busy_count = -1;
+ ph->ph_want_write = 1;
+ mtx_init(&ph->ph_mtx, "pfil_head_mtx", NULL, MTX_DEF);
+ cv_init(&ph->ph_cv, "pfil_head_cv");
+ mtx_lock(&ph->ph_mtx); /* XXX: race? */
+ }
TAILQ_INIT(&ph->ph_in);
TAILQ_INIT(&ph->ph_out);
- ph->ph_init = 1;
+
+ PFIL_LIST_LOCK();
+ LIST_INSERT_HEAD(&pfil_head_list, ph, ph_list);
+ PFIL_LIST_UNLOCK();
+
+ PFIL_WUNLOCK(ph);
+
+ return (0);
+}
+
+/*
+ * pfil_head_unregister() removes a pfil_head from the packet filter
+ * hook mechanism.
+ */
+int
+pfil_head_unregister(struct pfil_head *ph)
+{
+ struct packet_filter_hook *pfh, *pfnext;
+
+ PFIL_LIST_LOCK();
+ /*
+ * LIST_REMOVE is safe for unlocked pfil_heads in ph_list.
+ * No need to WLOCK all of them.
+ */
+ LIST_REMOVE(ph, ph_list);
+ PFIL_LIST_UNLOCK();
+
+ PFIL_WLOCK(ph); /* XXX: may sleep (cv_wait)! */
+
+ TAILQ_FOREACH_SAFE(pfh, &ph->ph_in, pfil_link, pfnext)
+ free(pfh, M_IFADDR);
+ TAILQ_FOREACH_SAFE(pfh, &ph->ph_out, pfil_link, pfnext)
+ free(pfh, M_IFADDR);
+ cv_destroy(&ph->ph_cv);
+ mtx_destroy(&ph->ph_mtx);
+
+ return (0);
+}
+
+/*
+ * pfil_head_get() returns the pfil_head for a given key/dlt.
+ */
+struct pfil_head *
+pfil_head_get(int type, u_long val)
+{
+ struct pfil_head *ph;
+
+ PFIL_LIST_LOCK();
+ LIST_FOREACH(ph, &pfil_head_list, ph_list)
+ if (ph->ph_type == type && ph->ph_un.phu_val == val)
+ break;
+ PFIL_LIST_UNLOCK();
+
+ return (ph);
}
/*
@@ -64,53 +233,71 @@ pfil_init(ph)
* PFIL_WAITOK OK to call malloc with M_WAITOK.
*/
int
-pfil_add_hook(func, flags, ph)
- int (*func)(void *, int, struct ifnet *, int, struct mbuf **);
- int flags;
- struct pfil_head *ph;
+pfil_add_hook(int (*func)(void *, struct mbuf **, struct ifnet *, int),
+ void *arg, int flags, struct pfil_head *ph)
{
- int err = 0;
+ struct packet_filter_hook *pfh1 = NULL;
+ struct packet_filter_hook *pfh2 = NULL;
+ int err;
- if (ph->ph_init == 0)
- pfil_init(ph);
+ /* Get memory */
+ if (flags & PFIL_IN) {
+ pfh1 = (struct packet_filter_hook *)malloc(sizeof(*pfh1),
+ M_IFADDR, (flags & PFIL_WAITOK) ? M_WAITOK : M_NOWAIT);
+ if (pfh1 == NULL) {
+ err = ENOMEM;
+ goto error;
+ }
+ }
+ if (flags & PFIL_OUT) {
+ pfh2 = (struct packet_filter_hook *)malloc(sizeof(*pfh1),
+ M_IFADDR, (flags & PFIL_WAITOK) ? M_WAITOK : M_NOWAIT);
+ if (pfh2 == NULL) {
+ err = ENOMEM;
+ goto error;
+ }
+ }
- if (flags & PFIL_IN)
- err = pfil_list_add(&ph->ph_in, func, flags & ~PFIL_OUT);
- if (err)
- return err;
- if (flags & PFIL_OUT)
- err = pfil_list_add(&ph->ph_out, func, flags & ~PFIL_IN);
- if (err) {
- if (flags & PFIL_IN)
- pfil_list_remove(&ph->ph_in, func);
- return err;
+ /* Lock */
+ if (flags & PFIL_WAITOK)
+ PFIL_WLOCK(ph);
+ else {
+ err = PFIL_TRY_WLOCK(ph);
+ if (err)
+ goto error;
}
- return 0;
-}
-static int
-pfil_list_add(list, func, flags)
- pfil_list_t *list;
- int (*func)(void *, int, struct ifnet *, int, struct mbuf **);
- int flags;
-{
- struct packet_filter_hook *pfh;
+ /* Add */
+ if (flags & PFIL_IN) {
+ pfh1->pfil_func = func;
+ pfh1->pfil_arg = arg;
+ err = pfil_list_add(&ph->ph_in, pfh1, flags & ~PFIL_OUT);
+ if (err)
+ goto done;
+ }
+ if (flags & PFIL_OUT) {
+ pfh2->pfil_func = func;
+ pfh2->pfil_arg = arg;
+ err = pfil_list_add(&ph->ph_out, pfh2, flags & ~PFIL_IN);
+ if (err) {
+ if (flags & PFIL_IN)
+ pfil_list_remove(&ph->ph_in, func, arg);
+ goto done;
+ }
+ }
+
+ ph->ph_busy_count = 0;
+ PFIL_WUNLOCK(ph);
- pfh = (struct packet_filter_hook *)malloc(sizeof(*pfh), M_IFADDR,
- flags & PFIL_WAITOK ? M_WAITOK : M_NOWAIT);
- if (pfh == NULL)
- return ENOMEM;
- pfh->pfil_func = func;
- /*
- * insert the input list in reverse order of the output list
- * so that the same path is followed in or out of the kernel.
- */
-
- if (flags & PFIL_IN)
- TAILQ_INSERT_HEAD(list, pfh, pfil_link);
- else
- TAILQ_INSERT_TAIL(list, pfh, pfil_link);
return 0;
+done:
+ PFIL_WUNLOCK(ph);
+error:
+ if (pfh1 != NULL)
+ free(pfh1, M_IFADDR);
+ if (pfh2 != NULL)
+ free(pfh2, M_IFADDR);
+ return err;
}
/*
@@ -118,54 +305,71 @@ pfil_list_add(list, func, flags)
* hook list.
*/
int
-pfil_remove_hook(func, flags, ph)
- int (*func)(void *, int, struct ifnet *, int, struct mbuf **);
- int flags;
- struct pfil_head *ph;
+pfil_remove_hook(int (*func)(void *, struct mbuf **, struct ifnet *, int),
+ void *arg, int flags, struct pfil_head *ph)
{
int err = 0;
- if (ph->ph_init == 0)
- pfil_init(ph);
+ if (flags & PFIL_WAITOK)
+ PFIL_WLOCK(ph);
+ else {
+ err = PFIL_TRY_WLOCK(ph);
+ if (err)
+ return err;
+ }
if (flags & PFIL_IN)
- err = pfil_list_remove(&ph->ph_in, func);
+ err = pfil_list_remove(&ph->ph_in, func, arg);
if ((err == 0) && (flags & PFIL_OUT))
- err = pfil_list_remove(&ph->ph_out, func);
+ err = pfil_list_remove(&ph->ph_out, func, arg);
+
+ if (TAILQ_EMPTY(&ph->ph_in) && TAILQ_EMPTY(&ph->ph_out))
+ ph->ph_busy_count = -1;
+
+ PFIL_WUNLOCK(ph);
+
return err;
}
+static int
+pfil_list_add(pfil_list_t *list, struct packet_filter_hook *pfh1, int flags)
+{
+ struct packet_filter_hook *pfh;
+
+ /*
+ * First make sure the hook is not already there.
+ */
+ TAILQ_FOREACH(pfh, list, pfil_link)
+ if (pfh->pfil_func == pfh1->pfil_func &&
+ pfh->pfil_arg == pfh1->pfil_arg)
+ return EEXIST;
+ /*
+ * insert the input list in reverse order of the output list
+ * so that the same path is followed in or out of the kernel.
+ */
+ if (flags & PFIL_IN)
+ TAILQ_INSERT_HEAD(list, pfh1, pfil_link);
+ else
+ TAILQ_INSERT_TAIL(list, pfh1, pfil_link);
+
+ return 0;
+}
+
/*
* pfil_list_remove is an internal function that takes a function off the
* specified list.
*/
static int
-pfil_list_remove(list, func)
- pfil_list_t *list;
- int (*func)(void *, int, struct ifnet *, int, struct mbuf **);
+pfil_list_remove(pfil_list_t *list,
+ int (*func)(void *, struct mbuf **, struct ifnet *, int), void *arg)
{
struct packet_filter_hook *pfh;
TAILQ_FOREACH(pfh, list, pfil_link)
- if (pfh->pfil_func == func) {
+ if (pfh->pfil_func == func && pfh->pfil_arg == arg) {
TAILQ_REMOVE(list, pfh, pfil_link);
free(pfh, M_IFADDR);
return 0;
}
return ENOENT;
}
-
-struct packet_filter_hook *
-pfil_hook_get(flag, ph)
- int flag;
- struct pfil_head *ph;
-{
- if (ph->ph_init != 0)
- switch (flag) {
- case PFIL_IN:
- return (TAILQ_FIRST(&ph->ph_in));
- case PFIL_OUT:
- return (TAILQ_FIRST(&ph->ph_out));
- }
- return NULL;
-}
diff --git a/sys/net/pfil.h b/sys/net/pfil.h
index 057a531..b1f29ae 100644
--- a/sys/net/pfil.h
+++ b/sys/net/pfil.h
@@ -1,4 +1,5 @@
-/* $FreeBSD$ */
+/* $FreeBSD$ */
+/* $NetBSD: pfil.h,v 1.22 2003/06/23 12:57:08 martin Exp $ */
/*
* Copyright (c) 1996 Matthew R. Green
@@ -31,6 +32,10 @@
#ifndef _NET_PFIL_H_
#define _NET_PFIL_H_
+#include <sys/systm.h>
+#include <sys/_lock.h>
+#include <sys/_mutex.h>
+#include <sys/condvar.h> /* XXX */
#include <sys/queue.h>
struct mbuf;
@@ -42,7 +47,8 @@ struct ifnet;
*/
struct packet_filter_hook {
TAILQ_ENTRY(packet_filter_hook) pfil_link;
- int (*pfil_func)(void *, int, struct ifnet *, int, struct mbuf **);
+ int (*pfil_func)(void *, struct mbuf **, struct ifnet *, int);
+ void *pfil_arg;
int pfil_flags;
};
@@ -53,28 +59,54 @@ struct packet_filter_hook {
typedef TAILQ_HEAD(pfil_list, packet_filter_hook) pfil_list_t;
+#define PFIL_TYPE_AF 1 /* key is AF_* type */
+#define PFIL_TYPE_IFNET 2 /* key is ifnet pointer */
+
struct pfil_head {
pfil_list_t ph_in;
pfil_list_t ph_out;
- int ph_init;
+ int ph_type;
+ /*
+ * Locking: use a busycounter per pfil_head.
+ * Use ph_busy_count = -1 to indicate pfil_head is empty.
+ */
+ int ph_busy_count; /* count of threads with read lock */
+ int ph_want_write; /* want write lock flag */
+ struct cv ph_cv; /* for waking up writers */
+ struct mtx ph_mtx; /* mutex on locking state */
+ union {
+ u_long phu_val;
+ void *phu_ptr;
+ } ph_un;
+#define ph_af ph_un.phu_val
+#define ph_ifnet ph_un.phu_ptr
+ LIST_ENTRY(pfil_head) ph_list;
};
-struct packet_filter_hook *pfil_hook_get(int, struct pfil_head *);
-int pfil_add_hook(int (*func)(void *, int,
- struct ifnet *, int, struct mbuf **), int, struct pfil_head *);
-int pfil_remove_hook(int (*func)(void *, int,
- struct ifnet *, int, struct mbuf **), int, struct pfil_head *);
+int pfil_run_hooks(struct pfil_head *, struct mbuf **, struct ifnet *,
+ int);
+
+int pfil_add_hook(int (*func)(void *, struct mbuf **,
+ struct ifnet *, int), void *, int, struct pfil_head *);
+int pfil_remove_hook(int (*func)(void *, struct mbuf **,
+ struct ifnet *, int), void *, int, struct pfil_head *);
+
+int pfil_head_register(struct pfil_head *);
+int pfil_head_unregister(struct pfil_head *);
-/* XXX */
-#if defined(_KERNEL) && !defined(KLD_MODULE)
-#include "opt_ipfilter.h"
-#endif
+struct pfil_head *pfil_head_get(int, u_long);
-#if IPFILTER > 0
-#ifdef PFIL_HOOKS
-#undef PFIL_HOOKS
-#endif
-#define PFIL_HOOKS
-#endif /* IPFILTER */
+static __inline struct packet_filter_hook *
+pfil_hook_get(int dir, struct pfil_head *ph)
+{
+ KASSERT(ph->ph_busy_count > 0,
+ ("pfil_hook_get: called on unbusy pfil_head"));
+ if (dir == PFIL_IN)
+ return (TAILQ_FIRST(&ph->ph_in));
+ else if (dir == PFIL_OUT)
+ return (TAILQ_FIRST(&ph->ph_out));
+ else
+ return (NULL);
+}
#endif /* _NET_PFIL_H_ */
diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c
index eefe26f..38b26e0 100644
--- a/sys/netinet/ip_input.c
+++ b/sys/netinet/ip_input.c
@@ -154,6 +154,9 @@ SYSCTL_INT(_net_inet_ip, OID_AUTO, check_interface, CTLFLAG_RW,
#ifdef DIAGNOSTIC
static int ipprintfs = 0;
#endif
+#ifdef PFIL_HOOKS
+struct pfil_head inet_pfil_hook;
+#endif
static struct ifqueue ipintrq;
static int ipqmaxlen = IFQ_MAXLEN;
@@ -263,6 +266,14 @@ ip_init()
pr->pr_protocol && pr->pr_protocol != IPPROTO_RAW)
ip_protox[pr->pr_protocol] = pr - inetsw;
+#ifdef PFIL_HOOKS
+ inet_pfil_hook.ph_type = PFIL_TYPE_AF;
+ inet_pfil_hook.ph_af = AF_INET;
+ if ((i = pfil_head_register(&inet_pfil_hook)) != 0)
+ printf("%s: WARNING: unable to register pfil hook, "
+ "error %d\n", __func__, i);
+#endif /* PFIL_HOOKS */
+
IPQ_LOCK_INIT();
for (i = 0; i < IPREASS_NHASH; i++)
TAILQ_INIT(&ipq[i]);
@@ -301,11 +312,6 @@ ip_input(struct mbuf *m)
struct in_addr pkt_dst;
u_int32_t divert_info = 0; /* packet divert/tee info */
struct ip_fw_args args;
-#ifdef PFIL_HOOKS
- struct packet_filter_hook *pfh;
- struct mbuf *m0;
- int rv;
-#endif /* PFIL_HOOKS */
#ifdef FAST_IPSEC
struct m_tag *mtag;
struct tdb_ident *tdbi;
@@ -461,25 +467,14 @@ iphack:
#ifdef PFIL_HOOKS
/*
- * Run through list of hooks for input packets. If there are any
- * filters which require that additional packets in the flow are
- * not fast-forwarded, they must clear the M_CANFASTFWD flag.
- * Note that filters must _never_ set this flag, as another filter
- * in the list may have previously cleared it.
+ * Run through list of hooks for input packets.
*/
- m0 = m;
- pfh = pfil_hook_get(PFIL_IN, &inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
- for (; pfh; pfh = TAILQ_NEXT(pfh, pfil_link))
- if (pfh->pfil_func) {
- rv = pfh->pfil_func(ip, hlen,
- m->m_pkthdr.rcvif, 0, &m0);
- if (rv)
- return;
- m = m0;
- if (m == NULL)
- return;
- ip = mtod(m, struct ip *);
- }
+ if (pfil_run_hooks(&inet_pfil_hook, &m, m->m_pkthdr.rcvif,
+ PFIL_IN) != 0)
+ return;
+ if (m == NULL) /* consumed by filter */
+ return;
+ ip = mtod(m, struct ip *);
#endif /* PFIL_HOOKS */
if (fw_enable && IPFW_LOADED) {
diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c
index f6a70ef..41e0cc0 100644
--- a/sys/netinet/ip_output.c
+++ b/sys/netinet/ip_output.c
@@ -65,6 +65,10 @@
#include <netinet/in_var.h>
#include <netinet/ip_var.h>
+#ifdef PFIL_HOOKS
+#include <net/pfil.h>
+#endif
+
#include <machine/in_cksum.h>
static MALLOC_DEFINE(M_IPMOPTS, "ip_moptions", "internet multicast options");
@@ -149,11 +153,6 @@ ip_output(struct mbuf *m0, struct mbuf *opt, struct route *ro,
#endif /* FAST_IPSEC */
struct ip_fw_args args;
int src_was_INADDR_ANY = 0; /* as the name says... */
-#ifdef PFIL_HOOKS
- struct packet_filter_hook *pfh;
- struct mbuf *m1;
- int rv;
-#endif /* PFIL_HOOKS */
args.eh = NULL;
args.rule = NULL;
@@ -741,20 +740,10 @@ spd_done:
/*
* Run through list of hooks for output packets.
*/
- m1 = m;
- pfh = pfil_hook_get(PFIL_OUT, &inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
- for (; pfh; pfh = TAILQ_NEXT(pfh, pfil_link))
- if (pfh->pfil_func) {
- rv = pfh->pfil_func(ip, hlen, ifp, 1, &m1);
- if (rv) {
- error = EHOSTUNREACH;
- goto done;
- }
- m = m1;
- if (m == NULL)
- goto done;
- ip = mtod(m, struct ip *);
- }
+ error = pfil_run_hooks(&inet_pfil_hook, &m, ifp, PFIL_OUT);
+ if (error != 0 || m == NULL)
+ goto done;
+ ip = mtod(m, struct ip *);
#endif /* PFIL_HOOKS */
/*
diff --git a/sys/netinet/ip_var.h b/sys/netinet/ip_var.h
index d0fde8e..40f36c1 100644
--- a/sys/netinet/ip_var.h
+++ b/sys/netinet/ip_var.h
@@ -207,6 +207,10 @@ void divert_packet(struct mbuf *m, int incoming, int port, int rule);
extern struct pr_usrreqs div_usrreqs;
#endif
+#ifdef PFIL_HOOKS
+extern struct pfil_head inet_pfil_hook;
+#endif
+
void in_delayed_cksum(struct mbuf *m);
#endif /* _KERNEL */
diff --git a/sys/netinet6/ip6_forward.c b/sys/netinet6/ip6_forward.c
index 1e6dde8..9233aba 100644
--- a/sys/netinet6/ip6_forward.c
+++ b/sys/netinet6/ip6_forward.c
@@ -34,6 +34,7 @@
#include "opt_inet.h"
#include "opt_inet6.h"
#include "opt_ipsec.h"
+#include "opt_pfil_hooks.h"
#include <sys/param.h>
#include <sys/systm.h>
@@ -113,11 +114,6 @@ ip6_forward(m, srcrt)
int error, type = 0, code = 0;
struct mbuf *mcopy = NULL;
struct ifnet *origifp; /* maybe unnecessary */
-#ifdef PFIL_HOOKS
- struct packet_filter_hook *pfh;
- struct mbuf *m1;
- int rv;
-#endif /* PFIL_HOOKS */
#ifdef IPSEC
struct secpolicy *sp = NULL;
#endif
@@ -526,21 +522,13 @@ ip6_forward(m, srcrt)
/*
* Run through list of hooks for output packets.
*/
- m1 = m;
- pfh = pfil_hook_get(PFIL_OUT, &inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh);
- for (; pfh; pfh = pfh->pfil_link.tqe_next)
- if (pfh->pfil_func) {
- rv = pfh->pfil_func(ip6, sizeof(*ip6),
- rt->rt_ifp, 1, &m1);
- if (rv) {
- error = EHOSTUNREACH;
- goto freecopy;
- }
- m = m1;
- if (m == NULL)
- goto freecopy;
- ip6 = mtod(m, struct ip6_hdr *);
- }
+ if (pfil_run_hooks(&inet6_pfil_hook, &m, rt->rt_ifp, PFIL_OUT) != 0) {
+ error = EHOSTUNREACH;
+ goto freecopy;
+ }
+ if (m == NULL)
+ goto freecopy;
+ ip6 = mtod(m, struct ip6_hdr *);
#endif /* PFIL_HOOKS */
error = nd6_output(rt->rt_ifp, origifp, m, dst, rt);
diff --git a/sys/netinet6/ip6_input.c b/sys/netinet6/ip6_input.c
index dcb74fb..9089071 100644
--- a/sys/netinet6/ip6_input.c
+++ b/sys/netinet6/ip6_input.c
@@ -143,6 +143,9 @@ int ip6_sourcecheck_interval; /* XXX */
int ip6_ours_check_algorithm;
+#ifdef PFIL_HOOKS
+struct pfil_head inet6_pfil_hook;
+#endif
/* firewall hooks */
ip6_fw_chk_t *ip6_fw_chk_ptr;
@@ -184,6 +187,13 @@ ip6_init()
if (pr->pr_domain->dom_family == PF_INET6 &&
pr->pr_protocol && pr->pr_protocol != IPPROTO_RAW)
ip6_protox[pr->pr_protocol] = pr - inet6sw;
+#ifdef PFIL_HOOKS
+ inet6_pfil_hook.ph_type = PFIL_TYPE_AF;
+ inet6_pfil_hook.ph_af = AF_INET6;
+ if ((i = pfil_head_register(&inet6_pfil_hook)) != 0)
+ printf("%s: WARNING: unable to register pfil hook, "
+ "error %d\n", __func__, i);
+#endif /* PFIL_HOOKS */
ip6intrq.ifq_maxlen = ip6qmaxlen;
mtx_init(&ip6intrq.ifq_mtx, "ip6_inq", NULL, MTX_DEF);
netisr_register(NETISR_IPV6, ip6_input, &ip6intrq);
@@ -241,11 +251,6 @@ ip6_input(m)
u_int32_t rtalert = ~0;
int nxt, ours = 0;
struct ifnet *deliverifp = NULL;
-#ifdef PFIL_HOOKS
- struct packet_filter_hook *pfh;
- struct mbuf *m0;
- int rv;
-#endif /* PFIL_HOOKS */
#ifdef IPSEC
/*
@@ -340,25 +345,13 @@ ip6_input(m)
#ifdef PFIL_HOOKS
/*
- * Run through list of hooks for input packets. If there are any
- * filters which require that additional packets in the flow are
- * not fast-forwarded, they must clear the M_CANFASTFWD flag.
- * Note that filters must _never_ set this flag, as another filter
- * in the list may have previously cleared it.
+ * Run through list of hooks for input packets.
*/
- m0 = m;
- pfh = pfil_hook_get(PFIL_IN, &inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh);
- for (; pfh; pfh = pfh->pfil_link.tqe_next)
- if (pfh->pfil_func) {
- rv = pfh->pfil_func(ip6, sizeof(*ip6),
- m->m_pkthdr.rcvif, 0, &m0);
- if (rv)
- return;
- m = m0;
- if (m == NULL)
- return;
- ip6 = mtod(m, struct ip6_hdr *);
- }
+ if (pfil_run_hooks(&inet6_pfil_hook, &m, m->m_pkthdr.rcvif, PFIL_IN))
+ return;
+ if (m == NULL) /* consumed by filter */
+ return;
+ ip6 = mtod(m, struct ip6_hdr *);
#endif /* PFIL_HOOKS */
ip6stat.ip6s_nxthist[ip6->ip6_nxt]++;
diff --git a/sys/netinet6/ip6_output.c b/sys/netinet6/ip6_output.c
index b18f9a7..7e81373 100644
--- a/sys/netinet6/ip6_output.c
+++ b/sys/netinet6/ip6_output.c
@@ -173,11 +173,6 @@ ip6_output(m0, opt, ro, flags, im6o, ifpp, inp)
struct route_in6 *ro_pmtu = NULL;
int hdrsplit = 0;
int needipsec = 0;
-#ifdef PFIL_HOOKS
- struct packet_filter_hook *pfh;
- struct mbuf *m1;
- int rv;
-#endif /* PFIL_HOOKS */
#ifdef IPSEC
int needipsectun = 0;
struct secpolicy *sp = NULL;
@@ -931,20 +926,13 @@ skip_ipsec2:;
/*
* Run through list of hooks for output packets.
*/
- m1 = m;
- pfh = pfil_hook_get(PFIL_OUT, &inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh);
- for (; pfh; pfh = pfh->pfil_link.tqe_next)
- if (pfh->pfil_func) {
- rv = pfh->pfil_func(ip6, sizeof(*ip6), ifp, 1, &m1);
- if (rv) {
- error = EHOSTUNREACH;
- goto done;
- }
- m = m1;
- if (m == NULL)
- goto done;
- ip6 = mtod(m, struct ip6_hdr *);
- }
+ if (pfil_run_hooks(&inet6_pfil_hook, &m, ifp, PFIL_OUT) != 0) {
+ error = EHOSTUNREACH;
+ goto done;
+ }
+ if (m == NULL)
+ goto done;
+ ip6 = mtod(m, struct ip6_hdr *);
#endif /* PFIL_HOOKS */
/*
* Send the packet to the outgoing interface.
diff --git a/sys/netinet6/ip6_var.h b/sys/netinet6/ip6_var.h
index 7ffdf1e..2f7e2a6 100644
--- a/sys/netinet6/ip6_var.h
+++ b/sys/netinet6/ip6_var.h
@@ -285,6 +285,10 @@ extern int ip6_lowportmax; /* maximum reserved port */
extern int ip6_use_tempaddr; /* whether to use temporary addresses. */
+#ifdef PFIL_HOOKS
+extern struct pfil_head inet6_pfil_hook;
+#endif
+
extern struct pr_usrreqs rip6_usrreqs;
struct sockopt;
diff --git a/sys/netinet6/ip6protosw.h b/sys/netinet6/ip6protosw.h
index 9730121..c6d4589 100644
--- a/sys/netinet6/ip6protosw.h
+++ b/sys/netinet6/ip6protosw.h
@@ -72,11 +72,6 @@
#define _NETINET6_IP6PROTOSW_H_
/*
- * For pfil_head structure.
- */
-#include <net/pfil.h>
-
-/*
* Protocol switch table for IPv6.
* All other definitions should refer to sys/protosw.h
*/
@@ -153,7 +148,6 @@ struct ip6protosw {
void (*pr_drain) /* flush any excess space possible */
__P((void));
struct pr_usrreqs *pr_usrreqs; /* supersedes pr_usrreq() */
- struct pfil_head pr_pfh;
};
#ifdef _KERNEL
diff --git a/sys/sys/param.h b/sys/sys/param.h
index f5a4e01..97d599c 100644
--- a/sys/sys/param.h
+++ b/sys/sys/param.h
@@ -57,7 +57,7 @@
* scheme is: <major><two digit minor><0 if release branch, otherwise 1>xx
*/
#undef __FreeBSD_version
-#define __FreeBSD_version 501107 /* Master, propagated to newvers */
+#define __FreeBSD_version 501108 /* Master, propagated to newvers */
#ifndef NULL
#define NULL 0
diff --git a/sys/sys/protosw.h b/sys/sys/protosw.h
index 01f3713..e065c77 100644
--- a/sys/sys/protosw.h
+++ b/sys/sys/protosw.h
@@ -37,11 +37,6 @@
#ifndef _SYS_PROTOSW_H_
#define _SYS_PROTOSW_H_
-/*
- * For pfil_head structure.
- */
-#include <net/pfil.h>
-
/* Forward declare these structures referenced from prototypes below. */
struct mbuf;
struct thread;
@@ -107,7 +102,6 @@ struct protosw {
pr_drain_t *pr_drain; /* flush any excess space possible */
struct pr_usrreqs *pr_usrreqs; /* supersedes pr_usrreq() */
- struct pfil_head pr_pfh;
};
/*#endif*/
OpenPOWER on IntegriCloud