Hi,

IPv6 IPsec transport mode does not work if pf is enabled.  The
problem is that the decrypted packets in the input path are not
checked with pf(4).  So if you have stateful filtering on enc0 (the
default) direction aware protocols like ping or TCP do not pass.
Only the output packets are matched with the states.

Adding an explicit pf_test() in ipsec_common_input_cb() fixes this.
In the IPv4 case the decrypted packet is enqueued again, so it hits
pf_test() in IPv4_input().  In IPv6 the ip6_local() shortcut is
taken.  I like to keep the shortcut as it corresponds to the idea
of IPv6 header chains.

ok?

bluhm

Index: netinet/ipsec_input.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ipsec_input.c,v
retrieving revision 1.148
diff -u -p -r1.148 ipsec_input.c
--- netinet/ipsec_input.c       5 May 2017 11:04:18 -0000       1.148
+++ netinet/ipsec_input.c       8 May 2017 16:44:31 -0000
@@ -591,6 +591,25 @@ ipsec_common_input_cb(struct mbuf *m, st
                return;
 #ifdef INET6
        case AF_INET6:
+#if NPF > 0
+               if ((tdbp->tdb_flags & TDBF_TUNNELING) == 0) {
+                       struct ifnet *ifp;
+
+                       /* This is the enc0 interface unless for ipcomp. */
+                       if ((ifp = if_get(m->m_pkthdr.ph_ifidx)) == NULL) {
+                               m_freem(m);
+                               return;
+                       }
+                       if (pf_test(AF_INET6, PF_IN, ifp, &m) != PF_PASS) {
+                               if_put(ifp);
+                               m_freem(m);
+                               return;
+                       }
+                       if_put(ifp);
+                       if (m == NULL)
+                               return;
+               }
+#endif
                ip6_local(m, skip, prot);
                return;
 #endif /* INET6 */

Reply via email to