Subject: Re: patch for pre/post-IPSEC traffic with IPv4
To: None <itojun@iijlab.net>
From: Darren Reed <avalon@caligula.anu.edu.au>
List: tech-net
Date: 05/05/2003 12:16:27
After some further discussion with Itojun on how and where to
"correctly" try and patch the networking code for tcpdump/ipfilter
hooks, I've arrived at the following set of patches.
Feedback welcome.
Darren
--- usr/src/sys/net/if.h.orig 2003-04-29 09:16:25.000000000 +1000
+++ usr/src/sys/net/if.h 2003-04-30 19:38:30.000000000 +1000
@@ -290,6 +290,7 @@
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
--- usr/src/sys/net/if.c.orig 2003-02-01 17:23:46.000000000 +1100
+++ usr/src/sys/net/if.c 2003-04-30 20:06:22.000000000 +1000
@@ -109,7 +109,9 @@
#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,6 +144,12 @@
#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,6 +162,9 @@
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,7 +476,42 @@
/* 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_RAW, 0);
+# endif
+ pifp->if_ipsec = ifp;
}
+#endif
void
if_attachdomain()
@@ -570,6 +616,16 @@
#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);
@@ -1157,6 +1213,10 @@
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,6 +1244,10 @@
#ifdef INET6
in6_if_up(ifp);
#endif
+#ifdef IPSEC
+ if (ifp->if_ipsec != NULL)
+ ifp->if_ipsec->if_flags &= ~IFF_UP;
+#endif
}
/*
@@ -1294,12 +1358,24 @@
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, name) == 0)
+ if (strcmp(ifp->if_xname, cp) == 0) {
+#ifdef IPSEC
+ if (cp != name)
+ return ifp->if_ipsec;
+#endif
return (ifp);
+ }
}
return (NULL);
}
--- usr/src/sys/netinet6/ipsec.c.orig 2003-01-17 19:11:57.000000000 +1100
+++ usr/src/sys/netinet6/ipsec.c 2003-05-01 17:54:02.000000000 +1000
@@ -39,6 +39,8 @@
#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,6 +58,12 @@
#include <net/if.h>
#include <net/route.h>
+#if NBPFILTER > 0
+#include <net/bpf.h>
+#endif
+#ifdef PFIL_HOOKS
+#include <net/pfil.h>
+#endif
#include <netinet/in.h>
#include <netinet/in_systm.h>
@@ -90,6 +98,15 @@
#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
@@ -1992,6 +2009,9 @@
struct ip *ip;
size_t hlen;
size_t plen;
+#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
@@ -2034,6 +2054,24 @@
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_mtap(ifp->if_bpf, m);
+#endif /* NBPFILTER > 0 */
+#ifdef PFIL_HOOKS
+ if (pfil_run_hooks(&inet_pfil_hook, &m, ifp, PFIL_OUT) != 0)
+ return EHOSTUNREACH;
+ if (m == NULL)
+ return EHOSTUNREACH;
+#endif /* PFIL_HOOKS */
+
/*
* grow the mbuf to accomodate the new IPv4 header.
* NOTE: IPv4 options will never be copied.
@@ -2110,6 +2148,9 @@
struct ip6_hdr *oip6;
struct ip6_hdr *ip6;
size_t plen;
+#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
@@ -2128,6 +2169,24 @@
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_mtap(ifp->if_bpf, m);
+#endif /* NBPFILTER > 0 */
+#ifdef PFIL_HOOKS
+ if (pfil_run_hooks(&inet6_pfil_hook, &m, ifp, PFIL_OUT) != 0)
+ return EHOSTUNREACH;
+ if (m == NULL)
+ return EHOSTUNREACH;
+#endif /* PFIL_HOOKS */
+
/*
* grow the mbuf to accomodate the new IPv6 header.
*/
@@ -2541,6 +2600,9 @@
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");
@@ -2668,14 +2730,35 @@
}
state->encap++;
- } else
+ } 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_mtap(ifp->if_bpf, state->m);
+#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 /* PFIL_HOOKS */
+ }
+
state->m = ipsec4_splithdr(state->m);
if (!state->m) {
error = ENOMEM;
goto bad;
}
+
switch (isr->saidx.proto) {
case IPPROTO_ESP:
#ifdef IPSEC_ESP
@@ -2798,6 +2881,10 @@
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;
@@ -2879,6 +2966,26 @@
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_mtap(ifp->if_bpf, m);
+#endif /* NBPFILTER > 0 */
+#ifdef PFIL_HOOKS
+ if (pfil_run_hooks(&inet6_pfil_hook, &m, ifp, PFIL_OUT) != 0)
+ goto bad;
+ if (m == NULL)
+ goto bad;
+ state->m = m;
+#endif /* PFIL_HOOKS */
+
switch (isr->saidx.proto) {
case IPPROTO_ESP:
#ifdef IPSEC_ESP
@@ -3031,6 +3138,7 @@
error = ENOMEM;
goto bad;
}
+
error = ipsec6_encapsulate(state->m, isr->sav);
splx(s);
if (error) {
--- usr/src/sys/netinet/ip_input.c.orig 2003-04-12 05:41:37.000000000 +1000
+++ usr/src/sys/netinet/ip_input.c 2003-05-04 14:45:08.000000000 +1000
@@ -417,6 +417,7 @@
{
struct ip *ip = NULL;
struct ipq *fp;
+ struct ifnet *ifp;
struct in_ifaddr *ia;
struct ifaddr *ifa;
struct ipqent *ipqe;
@@ -570,24 +571,17 @@
* 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.
- */
+ ifp = m->m_pkthdr.rcvif;
#ifdef IPSEC
- if (!ipsec_getnhist(m))
-#else
- if (1)
+ if (ipsec_getnhist(m))
+ ifp = ifp->if_ipsec;
#endif
- {
- if (pfil_run_hooks(&inet_pfil_hook, &m, m->m_pkthdr.rcvif,
- PFIL_IN) != 0)
+ 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;
- }
+ if (m == NULL)
+ return;
+ ip = mtod(m, struct ip *);
+ hlen = ip->ip_hl << 2;
#endif /* PFIL_HOOKS */
#ifdef ALTQ
--- usr/src/sys/netinet/ip_output.c.orig 2003-02-26 17:31:15.000000000 +1100
+++ usr/src/sys/netinet/ip_output.c 2003-05-04 14:47:12.000000000 +1000
@@ -490,6 +490,8 @@
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.
--- usr/src/sys/net/esp_input.c.orig 2003-01-20 11:39:30.000000000 +1100
+++ usr/src/sys/net/esp_input.c 2003-05-01 15:43:45.000000000 +1000
@@ -38,6 +38,8 @@
__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,6 +84,20 @@
#include <net/net_osdep.h>
+#if NBPFILTER > 0
+#include <net/bpf.h>
+#endif
+#ifdef PFIL_HOOKS
+#include <net/pfil.h>
+
+#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,6 +114,7 @@
va_dcl
#endif
{
+ struct ifnet *ifp;
struct ip *ip;
struct esp *esp;
struct esptail esptail;
@@ -393,6 +410,23 @@
splx(s);
goto bad;
}
+
+ ifp = m->m_pkthdr.rcvif->if_ipsec;
+#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_mtap(ifp->if_bpf, m);
+#endif /* NBPFILTER > 0 */
+#ifdef PFIL_HOOKS
+ if (pfil_run_hooks(&inet_pfil_hook, &m, ifp, PFIL_IN) != 0)
+ return;
+ if (m == NULL)
+ return;
+#endif /* PFIL_HOOKS */
+
IF_ENQUEUE(&ipintrq, m);
m = NULL;
schednetisr(NETISR_IP); /* can be skipped but to make sure */
@@ -521,6 +555,7 @@
struct mbuf **mp;
int *offp, proto;
{
+ struct ifnet *ifp;
struct mbuf *m = *mp;
int off = *offp;
struct ip6_hdr *ip6;
@@ -814,6 +849,23 @@
splx(s);
goto bad;
}
+
+ ifp = m->m_pkthdr.rcvif->if_ipsec;
+#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_mtap(ifp->if_bpf, m);
+#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 /* PFIL_HOOKS */
+
IF_ENQUEUE(&ip6intrq, m);
m = NULL;
schednetisr(NETISR_IPV6); /* can be skipped but to make sure */
--- usr/src/sys/net/ah_input.c.orig 2003-05-04 14:58:04.000000000 +1000
+++ usr/src/sys/net/ah_input.c 2003-05-01 15:39:00.000000000 +1000
@@ -38,6 +38,8 @@
__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,6 +84,20 @@
#include <net/net_osdep.h>
+#if NBPFILTER > 0
+#include <net/bpf.h>
+#endif
+#ifdef PFIL_HOOKS
+#include <net/pfil.h>
+
+#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,6 +110,7 @@
va_dcl
#endif
{
+ struct ifnet *ifp;
struct ip *ip;
struct ah *ah;
u_int32_t spi;
@@ -458,6 +475,23 @@
splx(s);
goto fail;
}
+
+ ifp = m->m_pkthdr.rcvif->if_ipsec;
+#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_mtap(ifp->if_bpf, m);
+#endif /* NBPFILTER > 0 */
+#ifdef PFIL_HOOKS
+ if (pfil_run_hooks(&inet6_pfil_hook, &m, ifp, PFIL_IN) != 0)
+ return;
+ if (m == NULL)
+ return;
+#endif /* PFIL_HOOKS */
+
IF_ENQUEUE(&ipintrq, m);
m = NULL;
schednetisr(NETISR_IP); /* can be skipped but to make sure */
@@ -621,6 +655,7 @@
struct mbuf **mp;
int *offp, proto;
{
+ struct ifnet *ifp;
struct mbuf *m = *mp;
int off = *offp;
struct ip6_hdr *ip6;
@@ -910,6 +945,23 @@
splx(s);
goto fail;
}
+
+ ifp = m->m_pkthdr.rcvif->if_ipsec;
+#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_mtap(ifp->if_bpf, m);
+#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 /* PFIL_HOOKS */
+
IF_ENQUEUE(&ip6intrq, m);
m = NULL;
schednetisr(NETISR_IPV6); /* can be skipped but to make sure */