Subject: Take #3 - final proposed patch for ipsec/bpf/ipfilter integration
To: None <tech-net@netbsd.org>
From: Darren Reed <avalon@caligula.anu.edu.au>
List: tech-net
Date: 05/11/2003 17:36:17
Hi All,
At this pass on the ipsec/tcpdump/ipfilter problem, I think I'm
approaching something very close to 100% working. I'd really
like some feedback from someone at KAME on the changes below as
well as from people who can test it or just review the patches.
I've also not yet tested IPv6, so if someone could give that a
go, it'd be most welcome.
There is one major outstanding problem: IP header checksums are
incorrect for inbound packets when picked up for transport mode
IPSEC processing. I suppose one solution is just to recalculate
it there and then as required but is that the only solution ?
I'd really like to get this patch out of the way and committed
within a week's time.
Anyone who has been busting to do firewalling (or NAT) on packets
before or after they go through an IPSec tunnel should give this
patch a go.
Oh, included in the patch is a new BPF routine - bpf_nullmtap().
When this set is committed, I plan to hunt around and covert all
of the "inline" versions of that to just call this function,
which should be able to provide better BPF performance for some
number of DLT_NULL packets.
Cheers,
Darren
# ipf -E
# ifconfig ipsec_pcn0 up
ipf -f -
pass out log from any to 192.168.1.254
pass in log from 192.168.1.254 to any
^D
# tcpdump -nvi ipsec_pcn0 &
tcpdump: WARNING: ipsec_pcn0: no IPv4 address assigned
tcpdump: listening on ipsec_pcn0
# ping -c 1 192.168.1.254
PING firewall.reed.wattle.id.au (192.168.1.254): 56 data bytes
64 bytes from 192.168.1.254: icmp_seq=0 ttl=255 time=3.891 ms
----firewall.reed.wattle.id.au PING Statistics----
1 packets transmitted, 1 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 3.891/3.891/3.891/0.000 ms
========== TRANSPORT MODE IPSEC OUTPUT ==========
04:36:11.061455 192.168.1.187 > 192.168.1.254: icmp: echo request seq 0 (ttl 255, id 1187, len 84, bad cksum 0 (->ffff03cf)!)
04:36:11.063675 192.168.1.254 > 192.168.1.187: icmp: echo reply seq 0 (ttl 255, id 8770, len 84, bad cksum 1408 (->ffffbf08)!)
# ipmon
12/05/2003 04:36:11.061959 ipsec_pcn0 @0:1 p 192.168.1.187 -> 192.168.1.254 PR icmp len 20 84 icmp echo/0 OUT
12/05/2003 04:36:11.062492 pcn0 @0:1 p 192.168.1.187 -> 192.168.1.254 PR esp len 20 (120) OUT
12/05/2003 04:36:11.063329 pcn0 @0:1 p 192.168.1.254 -> 192.168.1.187 PR esp len 20 (120) IN
12/05/2003 04:36:11.063803 ipsec_pcn0 @0:1 p 192.168.1.254 -> 192.168.1.187 PR icmp len 20 84 icmp echoreply/0 IN
========== TUNNEL MODE IPSEC OUTPUT ==========
04:39:14.735927 192.168.1.187 > 192.168.1.254: icmp: echo request seq 0 (ttl 255, id 2401, len 84)
04:39:14.739423 192.168.1.254 > 192.168.1.187: icmp: echo reply seq 0 (ttl 255, id 9046, len 84)
# ipmon
12/05/2003 04:39:14.736142 ipsec_pcn0 @0:1 p 192.168.1.187 -> 192.168.1.254 PR icmp len 20 84 icmp echo/0 OUT
12/05/2003 04:39:14.737429 pcn0 @0:1 p 192.168.1.187 -> 192.168.1.254 PR esp len 20 (136) OUT
12/05/2003 04:39:14.738377 pcn0 @0:1 p 192.168.1.254 -> 192.168.1.187 PR esp len 20 (136) IN
12/05/2003 04:39:14.739629 ipsec_pcn0 @0:1 p 192.168.1.254 -> 192.168.1.187 PR icmp len 20 84 icmp echoreply/0 IN
Index: sys/net/bpf.c
===================================================================
RCS file: /cvsroot/src/sys/net/bpf.c,v
retrieving revision 1.78
diff -c -r1.78 bpf.c
*** sys/net/bpf.c 2003/03/13 10:18:35 1.78
--- sys/net/bpf.c 2003/05/11 07:17:19
***************
*** 93,98 ****
--- 93,99 ----
* 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
***************
*** 1198,1203 ****
--- 1199,1250 ----
catchpacket(d, (u_char *)m, pktlen, slen, bpf_mcpy);
}
}
+
+ /*
+ * Incoming linkage from DLT_NULL device drivers.
+ */
+ void
+ bpf_nullmtap(arg, m, family)
+ caddr_t arg;
+ struct mbuf *m;
+ sa_family_t family;
+ {
+ 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);
+
+ bpf_mtap(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;
+
+ bpf_mtap(arg, &m0);
+ }
+
+ }
+
/*
* Move the packet data from interface memory (pkt) into the
Index: sys/net/bpf.h
===================================================================
RCS file: /cvsroot/src/sys/net/bpf.h,v
retrieving revision 1.31
diff -c -r1.31 bpf.h
*** sys/net/bpf.h 2002/09/21 17:02:46 1.31
--- sys/net/bpf.h 2003/05/11 07:17:20
***************
*** 240,245 ****
--- 240,246 ----
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: sys/net/bpf_filter.c
===================================================================
RCS file: /cvsroot/src/sys/net/bpf_filter.c,v
retrieving revision 1.19
diff -c -r1.19 bpf_filter.c
*** sys/net/bpf_filter.c 2001/11/15 09:48:25 1.19
--- sys/net/bpf_filter.c 2003/05/11 07:17:20
***************
*** 52,57 ****
--- 52,58 ----
#include <sys/param.h>
#include <sys/time.h>
+ #include <sys/socket.h>
#if !defined(UNALIGNED_ACCESS)
#define BPF_ALIGN
Index: sys/net/if.c
===================================================================
RCS file: /cvsroot/src/sys/net/if.c,v
retrieving revision 1.117
diff -c -r1.117 if.c
*** sys/net/if.c 2003/02/01 06:23:46 1.117
--- sys/net/if.c 2003/05/11 07:17:24
***************
*** 109,115 ****
--- 109,117 ----
#include "opt_compat_svr4.h"
#include "opt_compat_43.h"
#include "opt_atalk.h"
+ #include "opt_ipsec.h"
#include "opt_pfil_hooks.h"
+ #include "bpfilter.h"
#include <sys/param.h>
#include <sys/mbuf.h>
***************
*** 142,147 ****
--- 144,155 ----
#include <netinet6/nd6.h>
#endif
+ #if NBPFILTER > 0
+ #include <net/bpf.h>
+ #endif
+
+
+ MALLOC_DEFINE(M_IFNET, "ifnet", "interfaces");
MALLOC_DEFINE(M_IFADDR, "ifaddr", "interface address");
MALLOC_DEFINE(M_IFMADDR, "ether_multi", "link-level multicast address");
***************
*** 154,159 ****
--- 162,170 ----
struct if_clone *if_clone_lookup __P((const char *, int *));
int if_clone_list __P((struct if_clonereq *));
+ #ifdef IPSEC
+ void if_attachipsec __P((struct ifnet *));
+ #endif
LIST_HEAD(, if_clone) if_cloners = LIST_HEAD_INITIALIZER(if_cloners);
int if_cloners_count;
***************
*** 465,471 ****
--- 476,517 ----
/* Announce the interface. */
rt_ifannouncemsg(ifp, IFAN_ARRIVAL);
+
+ #ifdef IPSEC
+ if_attachipsec(ifp);
+ #endif
+ }
+
+
+ #ifdef IPSEC
+ void
+ if_attachipsec(struct ifnet *pifp)
+ {
+ struct ifnet *ifp;
+
+ ifp = (struct ifnet *)malloc(sizeof(*ifp), M_IFNET, M_WAITOK);
+ bzero((char *)ifp, sizeof(*ifp));
+ snprintf(ifp->if_xname, sizeof(ifp->if_xname),
+ "ipsec_%s", pifp->if_xname);
+
+ TAILQ_INIT(&ifp->if_addrlist);
+ ifp->if_link_state = LINK_STATE_UNKNOWN;
+ if_deactivate(ifp);
+
+ # ifdef PFIL_HOOKS
+ ifp->if_pfil.ph_type = PFIL_TYPE_IFNET;
+ ifp->if_pfil.ph_ifnet = ifp;
+ if (pfil_head_register(&ifp->if_pfil) != 0)
+ printf("%s: WARNING: unable to register pfil hook\n",
+ ifp->if_xname);
+ # endif
+
+ # if NBPFILTER > 0
+ bpfattach(ifp, DLT_NULL, sizeof(sa_family_t));
+ # endif
+ pifp->if_ipsec = ifp;
}
+ #endif
void
if_attachdomain()
***************
*** 570,575 ****
--- 616,631 ----
#ifdef PFIL_HOOKS
(void) pfil_head_unregister(&ifp->if_pfil);
#endif
+ #ifdef IPSEC
+ #ifdef PFIL_HOOKS
+ (void) pfil_head_unregister(&ifp->if_ipsec->if_pfil);
+ #endif
+ #if BPFILTER > 0
+ bpfdetach(ifp->if_ipsec);
+ #endif
+ free(ifp->if_ipsec, M_IFNET);
+ ifp->if_ipsec = NULL;
+ #endif
if_free_sadl(ifp);
***************
*** 608,614 ****
if (pr->pr_usrreq != NULL) {
(void) (*pr->pr_usrreq)(&so,
PRU_PURGEIF, NULL, NULL,
! (struct mbuf *) ifp, curproc);
purged = 1;
}
}
--- 664,670 ----
if (pr->pr_usrreq != NULL) {
(void) (*pr->pr_usrreq)(&so,
PRU_PURGEIF, NULL, NULL,
! (struct mbuf *) ifp, curlwp);
purged = 1;
}
}
***************
*** 1157,1162 ****
--- 1213,1222 ----
pfctlinput(PRC_IFDOWN, ifa->ifa_addr);
IFQ_PURGE(&ifp->if_snd);
rt_ifmsg(ifp);
+ #ifdef IPSEC
+ if (ifp->if_ipsec != NULL)
+ ifp->if_ipsec->if_flags &= ~IFF_UP;
+ #endif
}
/*
***************
*** 1184,1189 ****
--- 1244,1253 ----
#ifdef INET6
in6_if_up(ifp);
#endif
+ #ifdef IPSEC
+ if (ifp->if_ipsec != NULL)
+ ifp->if_ipsec->if_flags &= ~IFF_UP;
+ #endif
}
/*
***************
*** 1294,1305 ****
return (ifp);
}
for (ifp = TAILQ_FIRST(&ifnet); ifp != NULL;
ifp = TAILQ_NEXT(ifp, if_list)) {
if (ifp->if_output == if_nulloutput)
continue;
! if (strcmp(ifp->if_xname, name) == 0)
return (ifp);
}
return (NULL);
}
--- 1358,1381 ----
return (ifp);
}
+ #ifdef IPSEC
+ if (strncmp(name, "ipsec_", 6) == 0) {
+ cp = name + 6;
+ } else
+ #endif
+ cp = name;
+
for (ifp = TAILQ_FIRST(&ifnet); ifp != NULL;
ifp = TAILQ_NEXT(ifp, if_list)) {
if (ifp->if_output == if_nulloutput)
continue;
! if (strcmp(ifp->if_xname, cp) == 0) {
! #ifdef IPSEC
! if (cp != name)
! return ifp->if_ipsec;
! #endif
return (ifp);
+ }
}
return (NULL);
}
Index: sys/net/if.h
===================================================================
RCS file: /cvsroot/src/sys/net/if.h,v
retrieving revision 1.88
diff -c -r1.88 if.h
*** sys/net/if.h 2003/04/30 18:50:26 1.88
--- sys/net/if.h 2003/05/11 07:17:26
***************
*** 292,297 ****
--- 292,298 ----
void *if_afdata[AF_MAX];
struct mowner *if_mowner; /* who owns mbufs for this interface */
+ struct ifnet *if_ipsec;
};
#define if_mtu if_data.ifi_mtu
#define if_type if_data.ifi_type
Index: sys/netinet/ip_input.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/ip_input.c,v
retrieving revision 1.165
diff -c -r1.165 ip_input.c
*** sys/netinet/ip_input.c 2003/04/11 19:41:37 1.165
--- sys/netinet/ip_input.c 2003/05/11 07:17:45
***************
*** 415,420 ****
--- 415,423 ----
void
ip_input(struct mbuf *m)
{
+ #ifdef PFIL_HOOKS
+ struct ifnet *ifp;
+ #endif
struct ip *ip = NULL;
struct ipq *fp;
struct in_ifaddr *ia;
***************
*** 569,593 ****
* 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.
- */
- /*
- * 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;
! if (m == NULL)
! return;
! ip = mtod(m, struct ip *);
! hlen = ip->ip_hl << 2;
! }
#endif /* PFIL_HOOKS */
#ifdef ALTQ
--- 572,589 ----
* 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.
*/
+ ifp = m->m_pkthdr.rcvif;
#ifdef IPSEC
! if (ipsec_getnhist(m))
! ifp = ifp->if_ipsec;
#endif
! if (pfil_run_hooks(&inet_pfil_hook, &m, ifp, PFIL_IN) != 0)
return;
! if (m == NULL)
! return;
! ip = mtod(m, struct ip *);
! hlen = ip->ip_hl << 2;
#endif /* PFIL_HOOKS */
#ifdef ALTQ
Index: sys/netinet/ip_output.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/ip_output.c,v
retrieving revision 1.103
diff -c -r1.103 ip_output.c
*** sys/netinet/ip_output.c 2003/02/26 06:31:15 1.103
--- sys/netinet/ip_output.c 2003/05/11 07:17:48
***************
*** 490,495 ****
--- 490,497 ----
printf("ip_output: Invalid policy found. %d\n", sp->policy);
}
+ m->m_pkthdr.rcvif = ifp;
+
/*
* ipsec4_output() expects ip_len and ip_off in network
* order. They have been set to network order above.
Index: sys/netinet6/ah_input.c
===================================================================
RCS file: /cvsroot/src/sys/netinet6/ah_input.c,v
retrieving revision 1.37
diff -c -r1.37 ah_input.c
*** sys/netinet6/ah_input.c 2002/09/11 03:45:44 1.37
--- sys/netinet6/ah_input.c 2003/05/11 07:17:59
***************
*** 38,43 ****
--- 38,45 ----
__KERNEL_RCSID(0, "$NetBSD: ah_input.c,v 1.37 2002/09/11 03:45:44 itojun Exp $");
#include "opt_inet.h"
+ #include "bpfilter.h"
+ #include "opt_pfil_hooks.h"
#include <sys/param.h>
#include <sys/systm.h>
***************
*** 82,87 ****
--- 84,105 ----
#include <net/net_osdep.h>
+ #if NBPFILTER > 0
+ #include <net/bpf.h>
+ #endif
+ #ifdef PFIL_HOOKS
+ #include <net/pfil.h>
+ #endif
+
+ #ifdef PFIL_HOOKS
+ #ifdef INET
+ extern struct pfil_head inet_pfil_hook; /* XXX */
+ #endif
+ #ifdef INET6
+ extern struct pfil_head inet6_pfil_hook; /* XXX */
+ #endif
+ #endif
+
/*#define IPLEN_FLIPPED*/
#ifdef INET
***************
*** 94,99 ****
--- 112,120 ----
va_dcl
#endif
{
+ #if (NBPFILTER > 0) || defined(PFIL_HOOKS)
+ struct ifnet *ifp;
+ #endif
struct ip *ip;
struct ah *ah;
u_int32_t spi;
***************
*** 458,463 ****
--- 479,495 ----
splx(s);
goto fail;
}
+
+ #if NBPFILTER > 0
+ ifp = m->m_pkthdr.rcvif->if_ipsec;
+ /*
+ * Pass this up to any BPF listeners, but only
+ * pass if up the stack if it's for us.
+ */
+ if (ifp->if_bpf)
+ bpf_nullmtap(ifp->if_bpf, m, AF_INET);
+ #endif /* NBPFILTER > 0 */
+
IF_ENQUEUE(&ipintrq, m);
m = NULL;
schednetisr(NETISR_IP); /* can be skipped but to make sure */
***************
*** 530,535 ****
--- 562,586 ----
}
if (nxt != IPPROTO_DONE) {
+ #if (NBPFILTER > 0) || defined(PFIL_HOOKS)
+ ifp = m->m_pkthdr.rcvif->if_ipsec;
+ #endif
+ #if NBPFILTER > 0
+ /*
+ * Pass this up to any BPF listeners, but only
+ * pass if up the stack if it's for us.
+ */
+ if (ifp->if_bpf)
+ bpf_nullmtap(ifp->if_bpf, m, AF_INET);
+ #endif /* NBPFILTER > 0 */
+ #ifdef PFIL_HOOKS
+ if (pfil_run_hooks(&inet_pfil_hook, &m,
+ ifp, PFIL_IN) != 0)
+ goto fail;
+ if (m == NULL)
+ goto fail;
+ #endif
+
if ((inetsw[ip_protox[nxt]].pr_flags & PR_LASTHDR) != 0 &&
ipsec4_in_reject(m, NULL)) {
ipsecstat.in_polvio++;
***************
*** 621,626 ****
--- 672,680 ----
struct mbuf **mp;
int *offp, proto;
{
+ #if (NBPFILTER > 0) || defined(PFIL_HOOKS)
+ struct ifnet *ifp;
+ #endif
struct mbuf *m = *mp;
int off = *offp;
struct ip6_hdr *ip6;
***************
*** 910,915 ****
--- 964,980 ----
splx(s);
goto fail;
}
+
+ #if NBPFILTER > 0
+ ifp = m->m_pkthdr.rcvif->if_ipsec;
+ /*
+ * Pass this up to any BPF listeners, but only
+ * pass if up the stack if it's for us.
+ */
+ if (ifp->if_bpf)
+ bpf_nullmtap(ifp->if_bpf, m, AF_INET6);
+ #endif /* NBPFILTER > 0 */
+
IF_ENQUEUE(&ip6intrq, m);
m = NULL;
schednetisr(NETISR_IPV6); /* can be skipped but to make sure */
***************
*** 976,981 ****
--- 1041,1063 ----
ipsec6stat.in_nomem++;
goto fail;
}
+ #if (NBPFILTER > 0) || defined(PFIL_HOOKS)
+ ifp = m->m_pkthdr.rcvif->if_ipsec;
+ #endif
+ #if NBPFILTER > 0
+ /*
+ * Pass this up to any BPF listeners, but only
+ * pass if up the stack if it's for us.
+ */
+ if (ifp->if_bpf)
+ bpf_nullmtap(ifp->if_bpf, m, AF_INET6);
+ #endif /* NBPFILTER > 0 */
+ #ifdef PFIL_HOOKS
+ if (pfil_run_hooks(&inet6_pfil_hook, &m, ifp, PFIL_IN) != 0)
+ goto fail;
+ if (m == NULL)
+ goto fail;
+ #endif
}
*offp = off;
Index: sys/netinet6/esp_core.c
===================================================================
RCS file: /cvsroot/src/sys/netinet6/esp_core.c,v
retrieving revision 1.25
diff -c -r1.25 esp_core.c
*** sys/netinet6/esp_core.c 2002/09/11 03:45:45 1.25
--- sys/netinet6/esp_core.c 2003/05/11 07:18:01
***************
*** 967,972 ****
--- 967,975 ----
while (s && s->m_len == 0)
s = s->m_next;
+ if (s == NULL)
+ panic("esp_cbc_encrypt: out of mbufs");
+
while (soff < m->m_pkthdr.len) {
/* source */
if (sn + blocklen <= s->m_len) {
Index: sys/netinet6/esp_input.c
===================================================================
RCS file: /cvsroot/src/sys/netinet6/esp_input.c,v
retrieving revision 1.28
diff -c -r1.28 esp_input.c
*** sys/netinet6/esp_input.c 2003/01/20 00:39:30 1.28
--- sys/netinet6/esp_input.c 2003/05/11 07:18:03
***************
*** 38,43 ****
--- 38,45 ----
__KERNEL_RCSID(0, "$NetBSD: esp_input.c,v 1.28 2003/01/20 00:39:30 simonb Exp $");
#include "opt_inet.h"
+ #include "bpfilter.h"
+ #include "opt_pfil_hooks.h"
#include <sys/param.h>
#include <sys/systm.h>
***************
*** 82,87 ****
--- 84,105 ----
#include <net/net_osdep.h>
+ #if NBPFILTER > 0
+ #include <net/bpf.h>
+ #endif
+ #ifdef PFIL_HOOKS
+ #include <net/pfil.h>
+ #endif
+
+ #ifdef PFIL_HOOKS
+ #ifdef INET
+ extern struct pfil_head inet_pfil_hook; /* XXX */
+ #endif
+ #ifdef INET6
+ extern struct pfil_head inet6_pfil_hook; /* XXX */
+ #endif
+ #endif
+
/*#define IPLEN_FLIPPED*/
#define ESPMAXLEN \
***************
*** 98,103 ****
--- 116,124 ----
va_dcl
#endif
{
+ #if (NBPFILTER > 0) || defined(PFIL_HOOKS)
+ struct ifnet *ifp;
+ #endif
struct ip *ip;
struct esp *esp;
struct esptail esptail;
***************
*** 393,398 ****
--- 414,430 ----
splx(s);
goto bad;
}
+
+ #if NBPFILTER > 0
+ ifp = m->m_pkthdr.rcvif->if_ipsec;
+ /*
+ * Pass this up to any BPF listeners, but only
+ * pass if up the stack if it's for us.
+ */
+ if (ifp->if_bpf)
+ bpf_nullmtap(ifp->if_bpf, m, AF_INET);
+ #endif /* NBPFILTER > 0 */
+
IF_ENQUEUE(&ipintrq, m);
m = NULL;
schednetisr(NETISR_IP); /* can be skipped but to make sure */
***************
*** 429,434 ****
--- 461,485 ----
}
if (nxt != IPPROTO_DONE) {
+ #if (NBPFILTER > 0) || defined(PFIL_HOOKS)
+ ifp = m->m_pkthdr.rcvif->if_ipsec;
+ #endif
+ #if NBPFILTER > 0
+ /*
+ * Pass this up to any BPF listeners, but only
+ * pass if up the stack if it's for us.
+ */
+ if (ifp->if_bpf)
+ bpf_nullmtap(ifp->if_bpf, m, AF_INET);
+ #endif /* NBPFILTER > 0 */
+ #ifdef PFIL_HOOKS
+ if (pfil_run_hooks(&inet_pfil_hook, &m,
+ ifp, PFIL_IN) != 0)
+ goto bad;
+ if (m == NULL)
+ goto bad;
+ #endif
+
if ((inetsw[ip_protox[nxt]].pr_flags & PR_LASTHDR) != 0 &&
ipsec4_in_reject(m, NULL)) {
ipsecstat.in_polvio++;
***************
*** 521,526 ****
--- 572,580 ----
struct mbuf **mp;
int *offp, proto;
{
+ #if (NBPFILTER > 0) || defined(PFIL_HOOKS)
+ struct ifnet *ifp;
+ #endif
struct mbuf *m = *mp;
int off = *offp;
struct ip6_hdr *ip6;
***************
*** 814,819 ****
--- 868,884 ----
splx(s);
goto bad;
}
+
+ #if NBPFILTER > 0
+ ifp = m->m_pkthdr.rcvif->if_ipsec;
+ /*
+ * Pass this up to any BPF listeners, but only
+ * pass if up the stack if it's for us.
+ */
+ if (ifp->if_bpf)
+ bpf_nullmtap(ifp->if_bpf, m, AF_INET6);
+ #endif /* NBPFILTER > 0 */
+
IF_ENQUEUE(&ip6intrq, m);
m = NULL;
schednetisr(NETISR_IPV6); /* can be skipped but to make sure */
***************
*** 914,919 ****
--- 979,1001 ----
ipsec6stat.in_nomem++;
goto bad;
}
+ #if (NBPFILTER > 0) || defined(PFIL_HOOKS)
+ ifp = m->m_pkthdr.rcvif->if_ipsec;
+ #endif
+ #if NBPFILTER > 0
+ /*
+ * Pass this up to any BPF listeners, but only
+ * pass if up the stack if it's for us.
+ */
+ if (ifp->if_bpf)
+ bpf_nullmtap(ifp->if_bpf, m, AF_INET6);
+ #endif /* NBPFILTER > 0 */
+ #ifdef PFIL_HOOKS
+ if (pfil_run_hooks(&inet6_pfil_hook, &m, ifp, PFIL_IN) != 0)
+ goto bad;
+ if (m == NULL)
+ goto bad;
+ #endif
}
*offp = off;
Index: sys/netinet6/ip6_input.c
===================================================================
RCS file: /cvsroot/src/sys/netinet6/ip6_input.c,v
retrieving revision 1.60
diff -c -r1.60 ip6_input.c
*** sys/netinet6/ip6_input.c 2003/01/20 05:30:11 1.60
--- sys/netinet6/ip6_input.c 2003/05/11 07:18:06
***************
*** 229,234 ****
--- 229,237 ----
u_int32_t rtalert = ~0;
int nxt, ours = 0;
struct ifnet *deliverifp = NULL;
+ #ifdef PFIL_HOOKS
+ struct ifnet *ifp;
+ #endif
#ifdef IPSEC
/*
***************
*** 301,307 ****
goto bad;
}
- #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
--- 304,309 ----
***************
*** 313,331 ****
* 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(&inet6_pfil_hook, &m, m->m_pkthdr.rcvif,
! PFIL_IN) != 0)
! return;
! if (m == NULL)
! return;
! ip6 = mtod(m, struct ip6_hdr *);
! }
#endif /* PFIL_HOOKS */
ip6stat.ip6s_nxthist[ip6->ip6_nxt]++;
--- 315,331 ----
* let ipfilter look at packet on the wire,
* not the decapsulated packet.
*/
+ #ifdef PFIL_HOOKS
+ ifp = m->m_pkthdr.rcvif;
#ifdef IPSEC
! if (ipsec_getnhist(m))
! ifp = ifp->if_ipsec;
#endif
! if (pfil_run_hooks(&inet6_pfil_hook, &m, ifp, PFIL_IN) != 0)
! return;
! if (m == NULL)
! return;
! ip6 = mtod(m, struct ip6_hdr *);
#endif /* PFIL_HOOKS */
ip6stat.ip6s_nxthist[ip6->ip6_nxt]++;
Index: sys/netinet6/ipsec.c
===================================================================
RCS file: /cvsroot/src/sys/netinet6/ipsec.c,v
retrieving revision 1.70
diff -c -r1.70 ipsec.c
*** sys/netinet6/ipsec.c 2003/05/10 13:23:07 1.70
--- sys/netinet6/ipsec.c 2003/05/11 07:18:14
***************
*** 39,44 ****
--- 39,46 ----
#include "opt_inet.h"
#include "opt_ipsec.h"
+ #include "opt_pfil_hooks.h"
+ #include "bpfilter.h"
#include <sys/param.h>
#include <sys/systm.h>
***************
*** 56,61 ****
--- 58,66 ----
#include <net/if.h>
#include <net/route.h>
+ #if NBPFILTER > 0
+ #include <net/bpf.h>
+ #endif
#include <netinet/in.h>
#include <netinet/in_systm.h>
***************
*** 90,95 ****
--- 95,109 ----
#include <net/net_osdep.h>
+ #ifdef PFIL_HOOKS
+ #ifdef INET
+ extern struct pfil_head inet_pfil_hook; /* XXX */
+ #endif
+ #ifdef INET6
+ extern struct pfil_head inet6_pfil_hook; /* XXX */
+ #endif
+ #endif
+
#ifdef IPSEC_DEBUG
int ipsec_debug = 1;
#else
***************
*** 153,162 ****
static struct mbuf *ipsec6_splithdr __P((struct mbuf *));
#endif
#ifdef INET
! static int ipsec4_encapsulate __P((struct mbuf *, struct secasvar *));
#endif
#ifdef INET6
! static int ipsec6_encapsulate __P((struct mbuf *, struct secasvar *));
#endif
static struct m_tag *ipsec_addaux __P((struct mbuf *));
static struct m_tag *ipsec_findaux __P((struct mbuf *));
--- 167,176 ----
static struct mbuf *ipsec6_splithdr __P((struct mbuf *));
#endif
#ifdef INET
! static int ipsec4_encapsulate __P((struct mbuf **, struct secasvar *));
#endif
#ifdef INET6
! static int ipsec6_encapsulate __P((struct mbuf **, struct secasvar *));
#endif
static struct m_tag *ipsec_addaux __P((struct mbuf *));
static struct m_tag *ipsec_findaux __P((struct mbuf *));
***************
*** 1984,2015 ****
* ip->ip_src must be fixed later on.
*/
static int
! ipsec4_encapsulate(m, sav)
! struct mbuf *m;
struct secasvar *sav;
{
struct ip *oip;
struct ip *ip;
size_t hlen;
size_t plen;
/* can't tunnel between different AFs */
if (((struct sockaddr *)&sav->sah->saidx.src)->sa_family
!= ((struct sockaddr *)&sav->sah->saidx.dst)->sa_family
|| ((struct sockaddr *)&sav->sah->saidx.src)->sa_family != AF_INET) {
m_freem(m);
return EINVAL;
}
#if 0
/* XXX if the dst is myself, perform nothing. */
if (key_ismyaddr((struct sockaddr *)&sav->sah->saidx.dst)) {
m_freem(m);
return EINVAL;
}
#endif
! if (m->m_len < sizeof(*ip))
panic("ipsec4_encapsulate: assumption failed (first mbuf length)");
ip = mtod(m, struct ip *);
#ifdef _IP_VHL
--- 1998,2044 ----
* ip->ip_src must be fixed later on.
*/
static int
! ipsec4_encapsulate(mp, sav)
! struct mbuf **mp;
struct secasvar *sav;
{
struct ip *oip;
struct ip *ip;
size_t hlen;
size_t plen;
+ struct mbuf *m = *mp;
+ #if (NBPFILTER > 0) || defined(PFIL_HOOKS)
+ struct ifnet *ifp;
+ #endif
/* can't tunnel between different AFs */
if (((struct sockaddr *)&sav->sah->saidx.src)->sa_family
!= ((struct sockaddr *)&sav->sah->saidx.dst)->sa_family
|| ((struct sockaddr *)&sav->sah->saidx.src)->sa_family != AF_INET) {
m_freem(m);
+ *mp = NULL;
return EINVAL;
}
#if 0
/* XXX if the dst is myself, perform nothing. */
if (key_ismyaddr((struct sockaddr *)&sav->sah->saidx.dst)) {
m_freem(m);
+ *mp = NULL;
return EINVAL;
}
#endif
! if (m->m_len < sizeof(*ip)) {
! #ifdef DIAGNOSTIC
panic("ipsec4_encapsulate: assumption failed (first mbuf length)");
+ #else
+ ipseclog((LOG_ERR, "ipsec4_encapsulate: %s %d < 20",
+ "assumption failed (first mbuf length)", m->m_len));
+ m_freem(m);
+ *mp = NULL;
+ return EINVAL;
+ #endif
+ }
ip = mtod(m, struct ip *);
#ifdef _IP_VHL
***************
*** 2018,2026 ****
hlen = ip->ip_hl << 2;
#endif
- if (m->m_len != hlen)
- panic("ipsec4_encapsulate: assumption failed (first mbuf length)");
-
/* generate header checksum */
ip->ip_sum = 0;
#ifdef _IP_VHL
--- 2047,2052 ----
***************
*** 2034,2039 ****
--- 2060,2094 ----
plen = m->m_pkthdr.len;
+ #if (NBPFILTER > 0) || defined(PFIL_HOOKS)
+ ifp = m->m_pkthdr.rcvif->if_ipsec;
+ #endif
+ #if NBPFILTER > 0
+ /*
+ * Pass this up to any BPF listeners, but only
+ * pass if up the stack if it's for us.
+ */
+ if (ifp->if_bpf)
+ bpf_nullmtap(ifp->if_bpf, m, AF_INET);
+ #endif /* NBPFILTER > 0 */
+ #ifdef PFIL_HOOKS
+ {
+ int error;
+
+ if ((error = pfil_run_hooks(&inet_pfil_hook, mp, ifp, PFIL_OUT)) != 0)
+ return error;
+ m = *mp;
+ if (m == NULL)
+ return error;
+ plen = m->m_pkthdr.len;
+ }
+ #endif
+
+ *mp = ipsec4_splithdr(m);
+ m = *mp;
+ if (m == NULL)
+ return ENOMEM;
+
/*
* grow the mbuf to accomodate the new IPv4 header.
* NOTE: IPv4 options will never be copied.
***************
*** 2101,2113 ****
#ifdef INET6
static int
! ipsec6_encapsulate(m, sav)
! struct mbuf *m;
struct secasvar *sav;
{
struct ip6_hdr *oip6;
struct ip6_hdr *ip6;
size_t plen;
/* can't tunnel between different AFs */
if (((struct sockaddr *)&sav->sah->saidx.src)->sa_family
--- 2156,2172 ----
#ifdef INET6
static int
! ipsec6_encapsulate(mp, sav)
! struct mbuf **mp;
struct secasvar *sav;
{
struct ip6_hdr *oip6;
struct ip6_hdr *ip6;
size_t plen;
+ struct mbuf *m = *mp;
+ #if (NBPFILTER > 0) || defined(PFIL_HOOKS)
+ struct ifnet *ifp;
+ #endif
/* can't tunnel between different AFs */
if (((struct sockaddr *)&sav->sah->saidx.src)->sa_family
***************
*** 2126,2132 ****
--- 2185,2215 ----
plen = m->m_pkthdr.len;
+ #if (NBPFILTER > 0) || defined(PFIL_HOOKS)
+ ifp = m->m_pkthdr.rcvif->if_ipsec;
+ #endif
+ #if NBPFILTER > 0
/*
+ * Pass this up to any BPF listeners, but only
+ * pass if up the stack if it's for us.
+ */
+ if (ifp->if_bpf)
+ bpf_nullmtap(ifp->if_bpf, m, AF_INET6);
+ #endif /* NBPFILTER > 0 */
+ #ifdef PFIL_HOOKS
+ {
+ int error;
+
+ if ((error = pfil_run_hooks(&inet6_pfil_hook, mp, ifp, PFIL_OUT)) != 0)
+ return error;
+ m = *mp;
+ if (m == NULL)
+ return error;
+ ip6 = mtod(m, struct ip6_hdr *);
+ }
+ #endif
+
+ /*
* grow the mbuf to accomodate the new IPv6 header.
*/
if (m->m_len != sizeof(struct ip6_hdr))
***************
*** 2539,2544 ****
--- 2622,2630 ----
int s;
int error;
struct sockaddr_in *dst4;
+ #if (NBPFILTER > 0) || defined(PFIL_HOOKS)
+ struct ifnet *ifp;
+ #endif
if (!state)
panic("state == NULL in ipsec4_output");
***************
*** 2624,2636 ****
goto bad;
}
! state->m = ipsec4_splithdr(state->m);
! if (!state->m) {
! splx(s);
! error = ENOMEM;
! goto bad;
! }
! error = ipsec4_encapsulate(state->m, isr->sav);
splx(s);
if (error) {
state->m = NULL;
--- 2710,2716 ----
goto bad;
}
! error = ipsec4_encapsulate(&state->m, isr->sav);
splx(s);
if (error) {
state->m = NULL;
***************
*** 2666,2679 ****
}
state->encap++;
! } else
splx(s);
state->m = ipsec4_splithdr(state->m);
if (!state->m) {
error = ENOMEM;
goto bad;
}
switch (isr->saidx.proto) {
case IPPROTO_ESP:
#ifdef IPSEC_ESP
--- 2746,2781 ----
}
state->encap++;
! } else {
splx(s);
+ #if (NBPFILTER > 0) || defined(PFIL_HOOKS)
+ ifp = state->m->m_pkthdr.rcvif->if_ipsec;
+ #endif
+ #if NBPFILTER > 0
+ /*
+ * Pass this up to any BPF listeners, but only
+ * pass if up the stack if it's for us.
+ */
+ if (ifp->if_bpf)
+ bpf_nullmtap(ifp->if_bpf, state->m, AF_INET);
+ #endif /* NBPFILTER > 0 */
+ #ifdef PFIL_HOOKS
+ if (pfil_run_hooks(&inet_pfil_hook, &state->m,
+ ifp, PFIL_OUT) != 0)
+ goto bad;
+ if (state->m == NULL)
+ goto bad;
+ #endif
+
+ }
+
state->m = ipsec4_splithdr(state->m);
if (!state->m) {
error = ENOMEM;
goto bad;
}
+
switch (isr->saidx.proto) {
case IPPROTO_ESP:
#ifdef IPSEC_ESP
***************
*** 2796,2801 ****
--- 2898,2907 ----
int flags;
int *tun;
{
+ #if (NBPFILTER > 0) || defined(PFIL_HOOKS)
+ struct ifnet *ifp;
+ struct mbuf *m;
+ #endif
struct ip6_hdr *ip6;
struct ipsecrequest *isr = NULL;
int error = 0;
***************
*** 2877,2882 ****
--- 2983,3010 ----
goto bad;
}
+ #if (NBPFILTER > 0) || defined(PFIL_HOOKS)
+ m = state->m;
+ ifp = m->m_pkthdr.rcvif->if_ipsec;
+ #endif
+ #if NBPFILTER > 0
+ /*
+ * Pass this up to any BPF listeners, but only
+ * pass if up the stack if it's for us.
+ */
+ if (ifp->if_bpf)
+ bpf_nullmtap(ifp->if_bpf, m, AF_INET6);
+ #endif /* NBPFILTER > 0 */
+ #ifdef PFIL_HOOKS
+ if ((error = pfil_run_hooks(&inet6_pfil_hook, &m,
+ ifp, PFIL_OUT)) != 0)
+ goto bad;
+ if (m == NULL)
+ goto bad;
+ state->m = m;
+ ip6 = mtod(m, struct ip6_hdr *);
+ #endif
+
switch (isr->saidx.proto) {
case IPPROTO_ESP:
#ifdef IPSEC_ESP
***************
*** 3029,3035 ****
error = ENOMEM;
goto bad;
}
! error = ipsec6_encapsulate(state->m, isr->sav);
splx(s);
if (error) {
state->m = 0;
--- 3157,3164 ----
error = ENOMEM;
goto bad;
}
!
! error = ipsec6_encapsulate(&state->m, isr->sav);
splx(s);
if (error) {
state->m = 0;