[Bug 296598] pf: IPsec tunnel mode over if_wg, inner header not visible to pf
Krämer, Lars <[email protected]> Tue, 28 Jul 2026 08:18:57 +0000
| Newsgroups | gmane.os.freebsd.devel.net |
|---|---|
| Message-ID | <[email protected]> |
Hi,
I've tracked down a bug where TCP connections over IPsec die after a short =
time when IPsec runs over if_wg.
I would appreciate if someone could take a look at it.
Lots of diagnostic data is in the bugzilla report: https://bugs.freebsd.org=
/bugzilla/show_bug.cgi?id=3D296598
In a few words, ipsec4_common_input_cb tries stripping the outer IP-IP head=
er from the packet before passing it to pf hooks.
When a packet arrives via if_wg, the head of the mbuf is just the outer IP =
header and m_striphdr leaves behind a zero-length head.
This breaks when pf_test tries to read the IP header via mtod(), because th=
is condition is never checked, and pf reads the outer header instead.
The patch below fixes this by performing a pullup on the mbuf, though that =
might not necessarily be the correct way of handling this.
--- sys/netipsec/ipsec_input.c.orig
+++ sys/netipsec/ipsec_input.c
@@ -409,7 +409,10 @@
goto bad;
}
/* enc0: strip outer IPv4 header */
- m_striphdr(m, 0, ip->ip_hl << 2);
+ m_striphdr(m, 0, ip->ip_hl << 2);
+ m =3D m_pullup(m, sizeof(struct ip));
+ if (m =3D=3D NULL) { error =3D ENOBUFS; goto bad; }
}
#ifdef INET6
/* IPv6-in-IP encapsulation. */
@@ -421,7 +424,10 @@
goto bad;
}
/* enc0: strip IPv4 header, keep IPv6 header only */
- m_striphdr(m, 0, ip->ip_hl << 2);
+ m_striphdr(m, 0, ip->ip_hl << 2);
+ m =3D m_pullup(m, sizeof(struct ip6_hdr));
+ if (m =3D=3D NULL) { error =3D ENOBUFS; goto bad; }
}
#endif /* INET6 */
Reproduced on 13.2, 14.3 (OPNSense) and vanilla 15.1.
Thanks!
Lars Kr=E4mer