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.