Subject: patch for pre/post-IPSEC traffic with IPv4
To: None <tech-net@netbsd.org>
From: Darren Reed <avalon@caligula.anu.edu.au>
List: tech-net
Date: 05/01/2003 18:10:23
The patch below should create invisible interfaces named "ipsec_*"
for each real interface when you have a kernel compiled in with IPSEC
without impacting stability of the system at other times.
I haven't yet tested them with ipfilter but tcpdump shows me packets
before they get encrypted so I assume that is a good indication but
maybe not O:-) If further testing proves successful (ie no crashes :)
and there aren't any real problems with adding this kludge, I'd like
to commit it sometime over the weekend.
One thing I did notice was the packets did not seem to have correct
checksums. Have I picked the wrong place for intercepting IPv4 packets ?
Also, where on earth is the correct place in the KAME IPv6 code to add
similar hooks ? I had a look but it was not clear where to go..
Cheers,
Darren
*** /sys/net/if.h.orig Tue Apr 29 09:16:25 2003
--- /sys/net/if.h Wed Apr 30 19:38:30 2003
***************
*** 290,295 ****
--- 290,296 ----
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
*** /sys/net/if.c.orig Sat Feb 1 17:23:46 2003
--- /sys/net/if.c Wed Apr 30 20:06:22 2003
***************
*** 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_RAW, 0);
+ # 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);
***************
*** 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);
}
*** /sys/netinet/ip_input.c.orig Sat Apr 12 05:41:37 2003
--- /sys/netinet/ip_input.c Wed Apr 30 16:42:25 2003
***************
*** 109,114 ****
--- 109,115 ----
#include "opt_ipsec.h"
#include "opt_mrouting.h"
#include "opt_inet_csum.h"
+ #include "bpfilter.h"
#include <sys/param.h>
#include <sys/systm.h>
***************
*** 128,133 ****
--- 129,137 ----
#include <net/if_dl.h>
#include <net/route.h>
#include <net/pfil.h>
+ #if NBPFILTER > 0
+ #include <net/bpf.h>
+ #endif
#include <netinet/in.h>
#include <netinet/in_systm.h>
***************
*** 417,422 ****
--- 421,427 ----
{
struct ip *ip = NULL;
struct ipq *fp;
+ struct ifnet *ifp;
struct in_ifaddr *ia;
struct ifaddr *ifa;
struct ipqent *ipqe;
***************
*** 570,588 ****
* 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 *);
--- 575,597 ----
* 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;
! #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 */
! } else
#endif
{
! if (pfil_run_hooks(&inet_pfil_hook, &m, ifp, PFIL_IN) != 0)
! return;
if (m == NULL)
return;
ip = mtod(m, struct ip *);
*** /sys/netinet/ip_output.c.orig Wed Feb 26 17:31:15 2003
--- /sys/netinet/ip_output.c Wed Apr 30 20:55:47 2003
***************
*** 107,112 ****
--- 107,113 ----
#include "opt_pfil_hooks.h"
#include "opt_ipsec.h"
#include "opt_mrouting.h"
+ #include "bpfilter.h"
#include <sys/param.h>
#include <sys/malloc.h>
***************
*** 141,146 ****
--- 142,151 ----
#include <netkey/key_debug.h>
#endif /*IPSEC*/
+ #if NBPFILTER > 0
+ #include <net/bpf.h>
+ #endif
+
static struct mbuf *ip_insertoptions __P((struct mbuf *, struct mbuf *, int *));
static struct ifnet *ip_multicast_if __P((struct in_addr *, int *));
static void ip_mloopback
***************
*** 490,495 ****
--- 495,522 ----
printf("ip_output: Invalid policy found. %d\n", sp->policy);
}
+ #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_ipsec->if_bpf)
+ bpf_mtap(ifp->if_ipsec->if_bpf, m);
+ #endif /* NBPFILTER > 0 */
+
+ #ifdef PFIL_HOOKS
+ /*
+ * Run through list of hooks for output packets.
+ */
+ if ((error = pfil_run_hooks(&inet_pfil_hook, &m,
+ ifp->if_ipsec, PFIL_OUT)) != 0)
+ goto done;
+ if (m == NULL)
+ goto done;
+
+ ip = mtod(m, struct ip *);
+ #endif /* PFIL_HOOKS */
+
/*
* ipsec4_output() expects ip_len and ip_off in network
* order. They have been set to network order above.