Subject: kern/11844: patch for ipsec and ipfilter interaction
To: None <gnats-bugs@gnats.netbsd.org>
From: None <sdegler@degler.net>
List: netbsd-bugs
Date: 12/29/2000 20:23:19
>Number:         11844
>Category:       kern
>Synopsis:       patch for ipsec and ipfilter interaction
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    kern-bug-people
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Fri Dec 29 20:23:00 PST 2000
>Closed-Date:
>Last-Modified:
>Originator:     Stephen Degler
>Release:        1.5
>Organization:
Very Little, At Best.
>Environment:
	
System: NetBSD crusoe 1.5 NetBSD 1.5 (CRUSOE) #0: Fri Dec 29 00:31:11 EST 2000 root@crusoe:/vol2/src/sys/arch/sparc/compile/CRUSOE sparc


>Description:

Currently, there is an unplesant interaction with ipsec and ipfilter due to
the order in which they are processed.  This makes it difficult if not
impossible to set up a reasonable firewall which supports both ipsec and
traditional packet filtering.

The problem stems from the ipv4 code processing pfil hooks before ipsec processing on input and also for output.  The packet filter will see inbound packets encapsulated with ah/esp, but output packets (not forwarded) are seen as unencrypted.

The patch supplied changes ip_output() so that packets are procesed by ipsec
before they are passed to the pfil hooks.

current:
---> ip_input --> pfil_hooks ---> ipsec processing
---> ip_output --> pfil_hooks ---> ipsec processing
---> ip6_input --> pfil_hooks ---> ipsec processing
---> ip6_output ---> ipsec processing ---> pfil_hooks

after patch:
---> ip_input --> pfil_hooks ---> ipsec processing
---> ip_output --> ipsec processing ---> pfil_hooks
---> ip6_input --> pfil_hooks ---> ipsec processing
---> ip6_output ---> ipsec processing ---> pfil_hooks

I showed the patch to itojun who suggested I fill out this pr and also that
the following may be a better solution:

---> ip_input --> ipsec processing ---> pfil_hooks
---> ip_output --> pfil_hooks ---> ipsec processing
---> ip6_input ---> ipsec processing ---> pfil_hooks
---> ip6_output --> pfil_hooks ---> ipsec processing

This looks harder to implement, since packet filtering would then be sprinked
throughout various paths of networking code.

>How-To-Repeat:
	
	Set up an ipv4 firewall.
	Add ipsec.
	Attempt to write filter rules similar to the following:

	pass in quick on le0 proto esp from x to y
	pass out quick on le0 proto esp from y to x

	Observe them failing.  The patch supplied will fix this.
	Also note that it is not possible to write filter rules based on the
	encapsulated traffic either.  The patch does not fix this.

>Fix:
	Apply the following patch:
--- /usr/src/sys/netinet/ip_output.c.orig	Thu Dec 28 23:07:14 2000
+++ /usr/src/sys/netinet/ip_output.c	Thu Dec 28 23:10:29 2000
@@ -417,25 +417,6 @@
 		m->m_flags &= ~M_BCAST;
 
 sendit:
-#ifdef PFIL_HOOKS
-	/*
-	 * Run through list of hooks for output packets.
-	 */
-	m1 = m;
-	pfh = pfil_hook_get(PFIL_OUT, &inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
-	for (; pfh; pfh = pfh->pfil_link.tqe_next)
-		if (pfh->pfil_func) {
-		    	rv = pfh->pfil_func(ip, hlen, ifp, 1, &m1);
-			if (rv) {
-				error = EHOSTUNREACH;
-				goto done;
-			}
-			m = m1;
-			if (m == NULL)
-				goto done;
-			ip = mtod(m, struct ip *);
-		}
-#endif /* PFIL_HOOKS */
 
 #ifdef IPSEC
 	/* get SP for this packet */
@@ -555,6 +536,25 @@
 	ip->ip_off = ntohs((u_short)ip->ip_off);
 skip_ipsec:
 #endif /*IPSEC*/
+#ifdef PFIL_HOOKS
+	/*
+	 * Run through list of hooks for output packets.
+	 */
+	m1 = m;
+	pfh = pfil_hook_get(PFIL_OUT, &inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
+	for (; pfh; pfh = pfh->pfil_link.tqe_next)
+		if (pfh->pfil_func) {
+		    	rv = pfh->pfil_func(ip, hlen, ifp, 1, &m1);
+			if (rv) {
+				error = EHOSTUNREACH;
+				goto done;
+			}
+			m = m1;
+			if (m == NULL)
+				goto done;
+			ip = mtod(m, struct ip *);
+		}
+#endif /* PFIL_HOOKS */
 
 	/*
 	 * If small enough for mtu of path, can just send directly.
>Release-Note:
>Audit-Trail:
>Unformatted: