kern/157670: [patch] IPv6 in IPsec packets always get passed to pfil

Manuel Kasper mk at
Mon Jun 6 19:40:08 UTC 2011

>Number:         157670
>Category:       kern
>Synopsis:       [patch] IPv6 in IPsec packets always get passed to pfil
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Mon Jun 06 19:40:08 UTC 2011
>Originator:     Manuel Kasper
>Release:        8.2-RELEASE
For IPv4, one can use the net.inet.ipsec.filtertunnel sysctl to control whether decapsulated IPsec packets are sent through pfil. This defaults to 0 (unless the deprecated IPSEC_FILTERTUNNEL option is set in the kernel config) and works as intended.

For IPv6, there is a similar sysctl net.ip6.ipsec6.filtertunnel, but it doesn't seem to do anything (i.e. packets get passed to the filter even if it's set to 0).

This is especially annoying when using if_enc, as one will then see decapsulated IPv6 packets twice (once on enc0, and again on the physical interface that the corresponding IPsec packet came in on), when usually one only wants to see them on enc0.

Closer investigation of the kernel source code shows that there is a function ip6_ipsec_filtertunnel() to check whether pfil should be bypassed for a packet, but unlike its v4 counterpart, it doesn't seem to be called anywhere in the ip6_input path.
Set up an IPv6 IPsec connection between two FreeBSD 8.2 hosts. Load your favourite pfil-based firewall on one host and add rules to match decapsulated packets on enc0 and the physical interface. Send IPsec traffic from the other host. Observe that the firewall sees each packet twice even though net.ip6.ipsec6.filtertunnel=0.
A simple patch that fixes the issue for me is attached.

Patch attached with submission follows:

--- sys/netinet6/ip6_input.c.orig	2010-12-21 18:09:25.000000000 +0100
+++ sys/netinet6/ip6_input.c	2011-05-18 18:28:36.000000000 +0200
@@ -480,6 +480,14 @@
+#ifdef IPSEC
+	/*
+	 * Bypass packet filtering for packets from a tunnel (gif).
+	 */
+	if (ip6_ipsec_filtertunnel(m))
+		goto passin;
+#endif /* IPSEC */
 	 * Run through list of hooks for input packets.


More information about the freebsd-bugs mailing list