Subject: Re: Take #3 - final proposed patch for ipsec/bpf/ipfilter integration
To: None <avalon@caligula.anu.edu.au>
From: YAMAMOTO Takashi <yamt@mwd.biglobe.ne.jp>
List: tech-net
Date: 05/17/2003 03:59:06
--NextPart-20030517034345-0149101
Content-Type: Text/Plain; charset=us-ascii
> > if bpf interface isn't insufficient,
> > why not improve/hack it to be able to have multiple tap points
>
> Because bpf has a different role to pfil and I think your patch
> is wrong for joining the two together but that's just my opinion.
>
> BPF is primarily aimed at providing copies of "raw packet data"
> from data received by a network device (in this case the result
> of decrypting packets) or copies of what's about to be sent via
> one.
>
> pfil is generally concered with providing the means for controlling
> packets being accepted as part of a protocol's processing.
while i don't want strongly to join them,
i don't see any big reason to keep them separate.
tapping packets is a kind of filtering
and single hook for them is fine, IMO.
> > like attached (incomplete) patch or invent a new packet tapping interface?
>
> A net packet tapping interface...hmmm. like netgraph in FreeBSD that
> almost nothing presently uses ?
i don't know about netgraph so much and i'm not sure if it's better for us
to have it or not.
however, i think it's too complicated if all we want is just tapping
decoded packets.
> > > Yes, you need to be able to distinguish how the rules are applied.
> >
> > because ipfilter must knows which pfil_head it added hooks in,
> > i think that it can distinguish them, of course.
>
> Actually, ipfilter has no clue about which pfil_head it is being
> called from. This may need to change or maybe not.
>
> Now, even if ipfilter knew which pfil_head it was being called from,
> that needs to be reflected back in a rule, somehow.
yes. i don't care about syntax of ipf rule sets.
> Can you spend some more time working on your idea and post the patch?
"tcpdump -i esp@wi0" worked with attached patch.
it's still very incomplete (ipv4, esp, tranport mode only, no ipf patch)
but i think it's enough for testing a method.
> I'm also concerned that this patch creates an interdependency between
> what are two otherwise completely separate subsystems. Currently it
> is possible to use BPF without PFIL_HOOKS and vice versa. I see this
> as being a mandatory requirement.
why mandatory? i even think that bpf_mtap can be a wrapper of pfil hook.
YAMAMOTO Takashi
--NextPart-20030517034345-0149101
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="bpf.pfil2.diff"
Index: net/bpf.c
===================================================================
--- net/bpf.c (revision 1)
+++ net/bpf.c (working copy)
@@ -46,6 +46,7 @@
__KERNEL_RCSID(0, "$NetBSD: bpf.c,v 1.78 2003/03/13 10:18:35 dsl Exp $");
#include "bpfilter.h"
+#include "opt_pfil_hooks.h"
#include <sys/param.h>
#include <sys/systm.h>
@@ -93,6 +94,7 @@
* The default read buffer size is patchable.
*/
int bpf_bufsize = BPF_BUFSIZE;
+u_long bpf_nullfitted[2] = {0,0};
/*
* bpf_iflist is the list of interfaces; each corresponds to an ifnet
@@ -118,6 +120,16 @@
static int bpf_getdltlist __P((struct bpf_d *, struct bpf_dltlist *));
static int bpf_setdlt __P((struct bpf_d *, u_int));
+static void bpf_nullmtap_prep __P((caddr_t, struct mbuf *, sa_family_t,
+ void (*callback)(caddr_t, struct mbuf *)));
+#ifdef PFIL_HOOKS
+static int bpf_pfilhook __P((void *, struct mbuf **, struct ifnet *, int));
+static void bpf_mtap_single __P((caddr_t, struct mbuf *));
+#define D_PFIL(d) ((d)->bd_pfil != NULL)
+#else /* PFIL_HOOKS */
+#define D_PFIL(d) 0
+#endif /* PFIL_HOOKS */
+
dev_type_open(bpfopen);
dev_type_close(bpfclose);
dev_type_read(bpfread);
@@ -270,10 +282,15 @@
* it will divert packets to bpf.
*/
d->bd_bif = bp;
- d->bd_next = bp->bif_dlist;
- bp->bif_dlist = d;
-
- *bp->bif_driverp = bp;
+ if (!D_PFIL(d)) {
+ d->bd_next = bp->bif_dlist;
+ bp->bif_dlist = d;
+
+ *bp->bif_driverp = bp;
+ } else {
+ d->bd_next = bp->bif_dlist_pfil;
+ bp->bif_dlist_pfil = d;
+ }
}
/*
@@ -307,14 +324,17 @@
panic("bpf: ifpromisc failed");
}
/* Remove d from the interface's descriptor list. */
- p = &bp->bif_dlist;
+ if (!D_PFIL(d))
+ p = &bp->bif_dlist;
+ else
+ p = &bp->bif_dlist_pfil;
while (*p != d) {
p = &(*p)->bd_next;
if (*p == 0)
panic("bpf_detachd: descriptor not in list");
}
*p = (*p)->bd_next;
- if (bp->bif_dlist == 0)
+ if (!D_PFIL(d) && bp->bif_dlist == 0)
/*
* Let the driver know that there are no more listeners.
*/
@@ -396,6 +416,10 @@
int s;
s = splnet();
+#ifdef PFIL_HOOKS
+ if (D_PFIL(d))
+ pfil_remove_hook(bpf_pfilhook, d, PFIL_IN|PFIL_OUT, d->bd_pfil);
+#endif /* PFIL_HOOKS */
if (d->bd_bif)
bpf_detachd(d);
splx(s);
@@ -751,7 +775,9 @@
* Get device parameters.
*/
case BIOCGDLT:
- if (d->bd_bif == 0)
+ if (D_PFIL(d))
+ *(u_int *)addr = DLT_NULL;
+ else if (d->bd_bif == 0)
error = EINVAL;
else
*(u_int *)addr = d->bd_bif->bif_dlt;
@@ -771,7 +797,9 @@
* Set device parameters.
*/
case BIOCSDLT:
- if (d->bd_bif == 0)
+ if (D_PFIL(d))
+ error = EINVAL;
+ else if (d->bd_bif == 0)
error = EINVAL;
else
error = bpf_setdlt(d, *(u_int *)addr);
@@ -948,7 +976,7 @@
struct ifreq *ifr;
{
struct bpf_if *bp;
- char *cp;
+ char *cp, *ifname, *prname;
int unit_seen, i, s, error;
/*
@@ -957,14 +985,30 @@
* XXX This is ugly ... do this differently?
*/
unit_seen = 0;
- cp = ifr->ifr_name;
- cp[sizeof(ifr->ifr_name) - 1] = '\0'; /* sanity */
- while (*cp++)
- if (*cp >= '0' && *cp <= '9')
+ ifname = ifr->ifr_name;
+ ifname[sizeof(ifr->ifr_name) - 1] = '\0'; /* sanity */
+
+ /*
+ * ifr_name can be either "prname@ifname" or "ifname".
+ */
+ cp = strrchr(ifname, '@');
+ if (cp == NULL) {
+ prname = NULL;
+ } else {
+ *(cp++) = 0;
+ prname = ifname;
+ ifname = cp;
+ }
+
+ cp = ifname;
+ while (*cp++) {
+ if (*cp >= '0' && *cp <= '9') {
unit_seen = 1;
+ }
+ }
if (!unit_seen) {
/* Make sure to leave room for the '\0'. */
- for (i = 0; i < (IFNAMSIZ - 1); ++i) {
+ for (i = ifname - ifr->ifr_name; i < (IFNAMSIZ - 1); ++i) {
if ((ifr->ifr_name[i] >= 'a' &&
ifr->ifr_name[i] <= 'z') ||
(ifr->ifr_name[i] >= 'A' &&
@@ -979,9 +1023,10 @@
*/
for (bp = bpf_iflist; bp != 0; bp = bp->bif_next) {
struct ifnet *ifp = bp->bif_ifp;
+ struct pfil_head *pfilp;
if (ifp == 0 ||
- strcmp(ifp->if_xname, ifr->ifr_name) != 0)
+ strcmp(ifp->if_xname, ifname) != 0)
continue;
/* skip additional entry */
if (bp->bif_driverp != (struct bpf_if **)&ifp->if_bpf)
@@ -996,6 +1041,27 @@
if ((ifp->if_flags & IFF_UP) == 0)
return (ENETDOWN);
+ /*
+ *
+ */
+ if (prname) {
+#ifdef PFIL_HOOKS
+ pfilp = pfil_head_get(PFIL_TYPE_PROTOCOL,
+ (u_long)prname);
+ if (pfilp == NULL)
+ return (ENXIO);
+
+ error = pfil_add_hook(bpf_pfilhook, d,
+ PFIL_IN|PFIL_OUT|PFIL_WAITOK, pfilp);
+ if (error)
+ return (error);
+
+ d->bd_pfil = pfilp; /* XXX */
+#else /* PFIL_HOOKS */
+ return (ENXIO);
+#endif /* PFIL_HOOKS */
+ }
+
if (d->bd_sbuf == 0) {
error = bpf_allocbufs(d);
if (error != 0)
@@ -1200,6 +1266,66 @@
}
/*
+ * Incoming linkage from DLT_NULL device drivers.
+ */
+void
+bpf_nullmtap(arg, m, family)
+ caddr_t arg;
+ struct mbuf *m;
+ sa_family_t family;
+{
+
+ bpf_nullmtap_prep(arg, m, family, bpf_mtap);
+}
+
+/*
+ * Prepend the address family before mbuf and pass it callback.
+ */
+static void
+bpf_nullmtap_prep(arg, m, family, callback)
+ caddr_t arg;
+ struct mbuf *m;
+ sa_family_t family;
+ void (*callback) __P((caddr_t, struct mbuf *));
+{
+ u_int32_t mfamily = family;
+ struct mbuf m0;
+
+ /*
+ * We need to prepend the address family as a four byte field.
+ * Cons up a dummy header to pacify bpf. This is safe because bpf
+ * will only read from the mbuf (i.e., it won't try to free it or
+ * keep a pointer to it). If possible, prepend the family before
+ * the header, in the same mbuf, for better BPF performance.
+ */
+
+ if (M_LEADINGSPACE(m) >= sizeof(sa_family_t)) {
+ bpf_nullfitted[0]++;
+ m->m_data -= sizeof(mfamily);
+ bcopy(&family, mtod(m, char *), sizeof(mfamily));
+ m->m_len += sizeof(mfamily);
+ m->m_pkthdr.len += sizeof(mfamily);
+
+ callback(arg, m);
+
+ m->m_pkthdr.len -= sizeof(mfamily);
+ m->m_len -= sizeof(mfamily);
+ m->m_data += sizeof(mfamily);
+ } else {
+ bpf_nullfitted[1]++;
+ M_COPY_PKTHDR(&m0, m);
+ m0.m_next = m;
+ m0.m_len = sizeof(mfamily);
+ m0.m_data = (char *)&mfamily;
+ m0.m_pkthdr.len += m0.m_len;
+
+ callback(arg, &m0);
+ }
+
+}
+
+
+/*
* Move the packet data from interface memory (pkt) into the
* store buffer. Return 1 if it's time to wakeup a listener (buffer full),
* otherwise 0. "copy" is the routine called to do the actual data
@@ -1387,6 +1513,12 @@
* It will be free'ed later by close routine.
*/
s = splnet();
+#ifdef PFIL_HOOKS
+ if (D_PFIL(d)) {
+ pfil_remove_hook(bpf_pfilhook, d,
+ PFIL_IN|PFIL_OUT, d->bd_pfil);
+ }
+#endif
d->bd_promisc = 0; /* we can't touch device. */
bpf_detachd(d);
splx(s);
@@ -1500,3 +1632,52 @@
splx(s);
return 0;
}
+
+#ifdef PFIL_HOOKS
+/*
+ * bpf_mtap for a single bpf device.
+ */
+static void
+bpf_mtap_single(arg, m)
+ caddr_t arg;
+ struct mbuf *m;
+{
+ struct bpf_d *d = (struct bpf_d *)arg;
+ u_int pktlen, slen;
+ struct mbuf *m0;
+
+ pktlen = 0;
+ for (m0 = m; m0 != 0; m0 = m0->m_next)
+ pktlen += m0->m_len;
+
+ ++d->bd_rcount;
+ slen = bpf_filter(d->bd_filter, (u_char *)m, pktlen, 0);
+ if (slen != 0)
+ catchpacket(d, (u_char *)m, pktlen, slen, bpf_mcpy);
+}
+
+/*
+ * kick bpf using pfil.
+ */
+static int
+bpf_pfilhook(arg, mp, ifp, dir)
+ void *arg;
+ struct mbuf **mp;
+ struct ifnet *ifp;
+ int dir;
+{
+ struct bpf_d *d = arg;
+ /*
+ * XXX pfil_run_hooks and pfil callback function prototype
+ * XXX should be changed so that af can be passed here?
+ * XXX assume AF_INET for now
+ */
+ sa_family_t af = AF_INET;
+
+ if (ifp == d->bd_bif->bif_ifp)
+ bpf_nullmtap_prep(arg, *mp, af, bpf_mtap_single);
+
+ return 0;
+}
+#endif /* PFIL_HOOKS */
+
Index: net/bpfdesc.h
===================================================================
--- net/bpfdesc.h (revision 1)
+++ net/bpfdesc.h (working copy)
@@ -89,6 +89,9 @@
u_char bd_pad; /* explicit alignment */
struct selinfo bd_sel; /* bsd select info */
#endif
+#ifdef _KERNEL /* XXX */
+ void /*struct pfil_head*/ *bd_pfil;
+#endif
};
/*
@@ -101,6 +104,7 @@
u_int bif_dlt; /* link layer type */
u_int bif_hdrlen; /* length of header (with padding) */
struct ifnet *bif_ifp; /* correspoding interface */
+ struct bpf_d *bif_dlist_pfil; /* list of descriptors using pfil */
};
#ifdef _KERNEL
Index: net/bpf.h
===================================================================
--- net/bpf.h (revision 1)
+++ net/bpf.h (working copy)
@@ -240,6 +240,7 @@
int bpf_validate __P((struct bpf_insn *, int));
void bpf_tap __P((caddr_t, u_char *, u_int));
void bpf_mtap __P((caddr_t, struct mbuf *));
+void bpf_nullmtap __P((caddr_t, struct mbuf *, sa_family_t));
void bpfattach __P((struct ifnet *, u_int, u_int));
void bpfattach2 __P((struct ifnet *, u_int, u_int, caddr_t *));
void bpfdetach __P((struct ifnet *));
Index: net/bpf_filter.c
===================================================================
--- net/bpf_filter.c (revision 1)
+++ net/bpf_filter.c (working copy)
@@ -52,6 +52,7 @@
#include <sys/param.h>
#include <sys/time.h>
+#include <sys/socket.h>
#if !defined(UNALIGNED_ACCESS)
#define BPF_ALIGN
Index: net/pfil.c
===================================================================
--- net/pfil.c (revision 1)
+++ net/pfil.c (working copy)
@@ -83,14 +83,9 @@
int
pfil_head_register(struct pfil_head *ph)
{
- struct pfil_head *lph;
- for (lph = LIST_FIRST(&pfil_head_list); lph != NULL;
- lph = LIST_NEXT(lph, ph_list)) {
- if (ph->ph_type == lph->ph_type &&
- ph->ph_un.phu_val == lph->ph_un.phu_val)
- return EEXIST;
- }
+ if (pfil_head_get(ph->ph_type, ph->ph_un.phu_val))
+ return EEXIST;
TAILQ_INIT(&ph->ph_in);
TAILQ_INIT(&ph->ph_out);
@@ -122,9 +117,15 @@
for (ph = LIST_FIRST(&pfil_head_list); ph != NULL;
ph = LIST_NEXT(ph, ph_list)) {
- if (ph->ph_type == type &&
- ph->ph_un.phu_val == val)
- break;
+ if (ph->ph_type == type) {
+ if (PFIL_IS_STRING(type)) {
+ if (!strcmp(ph->ph_string, (char *)val))
+ break;
+ } else {
+ if (ph->ph_un.phu_val == val)
+ break;
+ }
+ }
}
return (ph);
Index: net/pfil.h
===================================================================
--- net/pfil.h (revision 1)
+++ net/pfil.h (working copy)
@@ -56,19 +56,25 @@
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 */
+#define PFIL_TYPE_STRING 0x8000 /* key is a pointer to string */
+#define PFIL_TYPE_AF (1) /* key is AF_* type */
+#define PFIL_TYPE_IFNET (2) /* key is ifnet pointer */
+#define PFIL_TYPE_PROTOCOL (3|PFIL_TYPE_STRING) /* key is protocol name */
+#define PFIL_IS_STRING(type) ((type & PFIL_TYPE_STRING) != 0)
struct pfil_head {
pfil_list_t ph_in;
pfil_list_t ph_out;
int ph_type;
+ intptr_t ph_private; /* ph_type private data */
union {
u_long phu_val;
void *phu_ptr;
+ const char *phu_string;
} ph_un;
#define ph_af ph_un.phu_val
#define ph_ifnet ph_un.phu_ptr
+#define ph_string ph_un.phu_string
LIST_ENTRY(pfil_head) ph_list;
};
typedef struct pfil_head pfil_head_t;
Index: netinet/ip_output.c
===================================================================
--- netinet/ip_output.c (revision 1)
+++ netinet/ip_output.c (working copy)
@@ -520,6 +520,7 @@
m->m_pkthdr.csum_flags &= ~(M_CSUM_TCPv4|M_CSUM_UDPv4);
}
+ m->m_pkthdr.rcvif = ifp; /* XXX abusing */
error = ipsec4_output(&state, sp, flags);
m = state.m;
Index: netinet/ip_input.c
===================================================================
--- netinet/ip_input.c (revision 29)
+++ netinet/ip_input.c (working copy)
@@ -226,6 +226,9 @@
#ifdef PFIL_HOOKS
struct pfil_head inet_pfil_hook;
+#ifdef IPSEC
+struct pfil_head inet_esp_pfil_hook;
+#endif
#endif
struct ipqhead ipq;
@@ -371,6 +374,14 @@
if (i != 0)
printf("ip_init: WARNING: unable to register pfil hook, "
"error %d\n", i);
+#ifdef IPSEC
+ inet_esp_pfil_hook.ph_type = PFIL_TYPE_PROTOCOL;
+ inet_esp_pfil_hook.ph_string = "esp";
+ i = pfil_head_register(&inet_esp_pfil_hook);
+ if (i != 0)
+ printf("ip_init: WARNING: unable to register pfil hook "
+ "for ESP, error %d\n", i);
+#endif
#endif /* PFIL_HOOKS */
#ifdef INET_CSUM_COUNTERS
@@ -570,19 +581,16 @@
* Note that filters must _never_ set this flag, as another filter
* in the list may have previously cleared it.
*/
- /*
- * let ipfilter look at packet on the wire,
- * not the decapsulated packet.
- */
-#ifdef IPSEC
- if (!ipsec_getnhist(m))
-#else
- if (1)
-#endif
{
- if (pfil_run_hooks(&inet_pfil_hook, &m, m->m_pkthdr.rcvif,
- PFIL_IN) != 0)
- return;
+ struct pfil_head *pfilp;
+#ifdef IPSEC
+ if (ipsec_getnhist(m))
+ pfilp = &inet_esp_pfil_hook;
+ else
+#endif /* IPSEC */
+ pfilp = &inet_pfil_hook;
+ if (pfil_run_hooks(pfilp, &m, m->m_pkthdr.rcvif, PFIL_IN) != 0)
+ return;
if (m == NULL)
return;
ip = mtod(m, struct ip *);
Index: netinet6/ipsec.c
===================================================================
--- netinet6/ipsec.c (revision 1)
+++ netinet6/ipsec.c (working copy)
@@ -39,6 +39,7 @@
#include "opt_inet.h"
#include "opt_ipsec.h"
+#include "opt_pfil_hooks.h"
#include <sys/param.h>
#include <sys/systm.h>
@@ -106,6 +107,11 @@
int ip4_ah_net_deflev = IPSEC_LEVEL_USE;
struct secpolicy *ip4_def_policy;
int ip4_ipsec_ecn = 0; /* ECN ignore(-1)/forbidden(0)/allowed(1) */
+#ifdef PFIL_HOOKS
+#ifdef IPSEC_ESP
+extern struct pfil_head inet_esp_pfil_hook; /* XXX */
+#endif /* IPSEC_ESP */
+#endif /* PFIL_HOOKS */
static int sp_cachegen = 1; /* cache generation # */
@@ -2541,6 +2547,9 @@
int s;
int error;
struct sockaddr_in *dst4;
+#ifdef PFIL_HOOKS
+ struct ifnet *ifp = state->m->m_pkthdr.rcvif; /* XXX abusing */
+#endif /* PFIL_HOOKS */
if (!state)
panic("state == NULL in ipsec4_output");
@@ -2660,7 +2669,9 @@
error = EHOSTUNREACH;
goto bad;
}
-
+#ifdef PFIL_HOOKS
+ ifp = state->ro->ro_rt->rt_ifp;
+#endif
/* adjust state->dst if tunnel endpoint is offlink */
if (state->ro->ro_rt->rt_flags & RTF_GATEWAY) {
state->dst = (struct sockaddr *)state->ro->ro_rt->rt_gateway;
@@ -2671,6 +2682,23 @@
} else
splx(s);
+#ifdef PFIL_HOOKS
+ /*
+ * XXX XXX should filter before encapsulating for tunnel mode.
+ */
+ switch (isr->saidx.proto) {
+#ifdef IPSEC_ESP
+ case IPPROTO_ESP:
+ error = pfil_run_hooks(&inet_esp_pfil_hook, &state->m,
+ ifp, PFIL_OUT);
+ if (error || state->m == NULL)
+ goto bad;
+ break;
+#endif /* IPSEC_ESP */
+ default:
+ break;
+ }
+#endif /* PFIL_HOOKS */
state->m = ipsec4_splithdr(state->m);
if (!state->m) {
error = ENOMEM;
Index: netinet6/esp_input.c
===================================================================
--- netinet6/esp_input.c (revision 1)
+++ netinet6/esp_input.c (working copy)
@@ -38,6 +38,7 @@
__KERNEL_RCSID(0, "$NetBSD: esp_input.c,v 1.28 2003/01/20 00:39:30 simonb Exp $");
#include "opt_inet.h"
+#include "opt_pfil_hooks.h"
#include <sys/param.h>
#include <sys/systm.h>
@@ -89,6 +90,10 @@
? sizeof(struct newesp) : sizeof(struct esp))
#ifdef INET
+#ifdef PFIL_HOOKS
+extern struct pfil_head inet_esp_pfil_hook; /* XXX */
+#endif /* PFIL_HOOKS */
+
void
#if __STDC__
esp4_input(struct mbuf *m, ...)
@@ -393,6 +398,15 @@
splx(s);
goto bad;
}
+
+#ifdef PFIL_HOOKS
+ if (pfil_run_hooks(&inet_esp_pfil_hook, &m, m->m_pkthdr.rcvif,
+ PFIL_IN) != 0 || m == NULL) {
+ splx(s);
+ goto bad;
+ }
+#endif /* PFIL_HOOKS */
+
IF_ENQUEUE(&ipintrq, m);
m = NULL;
schednetisr(NETISR_IP); /* can be skipped but to make sure */
@@ -428,6 +442,13 @@
goto bad;
}
+#ifdef PFIL_HOOKS
+ if (pfil_run_hooks(&inet_esp_pfil_hook, &m, m->m_pkthdr.rcvif,
+ PFIL_IN) != 0 || m == NULL) {
+ goto bad;
+ }
+#endif /* PFIL_HOOKS */
+
if (nxt != IPPROTO_DONE) {
if ((inetsw[ip_protox[nxt]].pr_flags & PR_LASTHDR) != 0 &&
ipsec4_in_reject(m, NULL)) {
@@ -516,6 +537,10 @@
#endif /* INET */
#ifdef INET6
+#ifdef PFIL_HOOKS
+extern struct pfil_head inet6_esp_pfil_hook; /* XXX */
+#endif /* PFIL_HOOKS */
+
int
esp6_input(mp, offp, proto)
struct mbuf **mp;
@@ -814,6 +839,15 @@
splx(s);
goto bad;
}
+
+#ifdef PFIL_HOOKS
+ if (pfil_run_hooks(&inet6_esp_pfil_hook, &m, m->m_pkthdr.rcvif,
+ PFIL_IN) != 0 || m == NULL) {
+ splx(s);
+ goto bad;
+ }
+#endif /* PFIL_HOOKS */
+
IF_ENQUEUE(&ip6intrq, m);
m = NULL;
schednetisr(NETISR_IPV6); /* can be skipped but to make sure */
@@ -914,6 +948,13 @@
ipsec6stat.in_nomem++;
goto bad;
}
+
+#ifdef PFIL_HOOKS
+ if (pfil_run_hooks(&inet6_esp_pfil_hook, &m, m->m_pkthdr.rcvif,
+ PFIL_IN) != 0 || m == NULL) {
+ goto bad;
+ }
+#endif /* PFIL_HOOKS */
}
*offp = off;
Index: netinet6/ip6_input.c
===================================================================
--- netinet6/ip6_input.c (revision 1)
+++ netinet6/ip6_input.c (working copy)
@@ -142,6 +142,9 @@
#ifdef PFIL_HOOKS
struct pfil_head inet6_pfil_hook;
+#ifdef IPSEC
+struct pfil_head inet6_esp_pfil_hook;
+#endif
#endif
struct ip6stat ip6stat;
@@ -185,6 +188,14 @@
if (i != 0)
printf("ip6_init: WARNING: unable to register pfil hook, "
"error %d\n", i);
+#ifdef IPSEC
+ inet6_esp_pfil_hook.ph_type = PFIL_TYPE_PROTOCOL;
+ inet6_esp_pfil_hook.ph_string = "esp6";
+ i = pfil_head_register(&inet6_esp_pfil_hook);
+ if (i != 0)
+ printf("ip6_init: WARNING: unable to register pfil hook "
+ "for ESP, error %d\n", i);
+#endif
#endif /* PFIL_HOOKS */
}
@@ -309,16 +320,15 @@
* Note that filters must _never_ set this flag, as another filter
* in the list may have previously cleared it.
*/
- /*
- * let ipfilter look at packet on the wire,
- * not the decapsulated packet.
- */
+ {
+ struct pfil_head *pfilp;
#ifdef IPSEC
- if (!ipsec_getnhist(m))
-#else
- if (1)
+ if (!ipsec_getnhist(m))
+ pfilp = &inet6_esp_pfil_hook;
+ else
#endif
- {
+ pfilp = &inet6_pfil_hook;
+
if (pfil_run_hooks(&inet6_pfil_hook, &m, m->m_pkthdr.rcvif,
PFIL_IN) != 0)
return;
--NextPart-20030517034345-0149101--