o update PFIL_HOOKS support to current API used by netbsd
o revamp IPv4+IPv6+bridge usage to match API changes o remove pfil_head instances from protosw entries (no longer used) o add locking o bump FreeBSD version for 3rd party modules Heavy lifting by: "Max Laier" <max@love2party.net> Supported by: FreeBSD Foundation Obtained from: NetBSD (bits of pfil.h and pfil.c)
This commit is contained in:
parent
6c7aa7fe1b
commit
134ea22494
@ -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>
|
||||
|
@ -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.
|
||||
|
360
sys/net/pfil.c
360
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 int pfil_list_remove(pfil_list_t *,
|
||||
int (*)(void *, int, struct ifnet *, int, struct mbuf **));
|
||||
static struct mtx pfil_global_lock;
|
||||
|
||||
static void
|
||||
pfil_init(ph)
|
||||
struct pfil_head *ph;
|
||||
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 *, 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);
|
||||
}
|
||||
|
||||
#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);
|
||||
|
||||
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;
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
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;
|
||||
/* Lock */
|
||||
if (flags & PFIL_WAITOK)
|
||||
PFIL_WLOCK(ph);
|
||||
else {
|
||||
err = PFIL_TRY_WLOCK(ph);
|
||||
if (err)
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
/* XXX */
|
||||
#if defined(_KERNEL) && !defined(KLD_MODULE)
|
||||
#include "opt_ipfilter.h"
|
||||
#endif
|
||||
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 *);
|
||||
|
||||
#if IPFILTER > 0
|
||||
#ifdef PFIL_HOOKS
|
||||
#undef PFIL_HOOKS
|
||||
#endif
|
||||
#define PFIL_HOOKS
|
||||
#endif /* IPFILTER */
|
||||
int pfil_head_register(struct pfil_head *);
|
||||
int pfil_head_unregister(struct pfil_head *);
|
||||
|
||||
struct pfil_head *pfil_head_get(int, u_long);
|
||||
|
||||
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_ */
|
||||
|
@ -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 @@ ip_input(struct mbuf *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, &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) {
|
||||
|
@ -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 @@ ip_output(struct mbuf *m0, struct mbuf *opt, struct route *ro,
|
||||
/*
|
||||
* 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 */
|
||||
|
||||
/*
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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]++;
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
||||
|
@ -71,11 +71,6 @@
|
||||
#ifndef _NETINET6_IP6PROTOSW_H_
|
||||
#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
|
||||
|
@ -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
|
||||
|
@ -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*/
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user