netinet6: Set PFIL_FWD in ip6_tryforward()

ip6_forward() has run the outbound hooks with pfil_mbuf_fwd() since
b52b61c0b6, and ip_tryforward() since 1f4c3887e3, but
ip6_tryforward() still calls pfil_mbuf_out().  pf therefore handles a
packet on the IPv6 fast path as locally generated: it skips the
packet-too-big error it sends with the untranslated addresses, and
pf_refragment6() sends reassembled packets out through ip6_output()
instead of ip6_forward(), so their fragments leave with the hop limit
not decremented.

Use pfil_mbuf_fwd() in ip6_tryforward() as well.  The new
fragmentation_pass:v6_refrag_hlim test sends a packet that pf
reassembles and refragments through the fast path, and checks that its
fragments leave with the hop limit decremented once; before this change
they leave with it unchanged.

Reviewed by:		kp
Fixes:			b52b61c0 ("pf: distinguish forwarding and output cases for ...")
MFC after:		1 week
Sponsored by:		Rubicon Communications, LLC ("Netgate")
Differential Revision:	https://reviews.freebsd.org/D61033
This commit is contained in:
R. Christian McDonald committed 2026-10-30 13:31:37 -04:00
1 parent 622bf596b7
commit 8c73c0f123
2 files changed
+56 -1

No files matched your search

+1 -1
View File
@@ -218,7 +218,7 @@ passin:
/*
* Outgoing packet firewall processing.
*/
if (pfil_mbuf_out(V_inet6_pfil_head, &m, nh->nh_ifp,
if (pfil_mbuf_fwd(V_inet6_pfil_head, &m, nh->nh_ifp,
NULL) != PFIL_PASS)
goto dropout;
@@ -155,6 +155,60 @@ v6_cleanup()
pft_cleanup
}
# refrag_hlim REDIRECT: with net.inet6.ip6.redirect at REDIRECT on the router
# (0: ip6_tryforward(), 1: ip6_forward()), a forwarded packet that pf
# reassembles and refragments loses one hop: the echo reply comes back
# through alcatraz in fragments, with the hop limit singsing sent minus one.
refrag_hlim()
{
jexec alcatraz sysctl net.inet6.ip6.redirect=$1
atf_check -o match:"icmp_seq=0 hlim=63 " \
ping -6 -c 1 -m 64 -s 4500 2001:db8:43::3
}
atf_test_case "v6_refrag_hlim" "cleanup"
v6_refrag_hlim_head()
{
atf_set descr 'Refragmented forwarded IPv6 loses one hop'
atf_set require.user root
}
v6_refrag_hlim_body()
{
pft_init
epair_send=$(vnet_mkepair)
epair_link=$(vnet_mkepair)
vnet_mkjail alcatraz ${epair_send}b ${epair_link}a
vnet_mkjail singsing ${epair_link}b
ifconfig ${epair_send}a inet6 2001:db8:42::1/64 no_dad up
jexec alcatraz ifconfig ${epair_send}b inet6 2001:db8:42::2/64 no_dad up
jexec alcatraz ifconfig ${epair_link}a inet6 2001:db8:43::2/64 no_dad up
jexec alcatraz sysctl net.inet6.ip6.forwarding=1
jexec singsing ifconfig ${epair_link}b inet6 2001:db8:43::3/64 no_dad up
jexec singsing route add -6 2001:db8:42::/64 2001:db8:43::2
route add -6 2001:db8:43::/64 2001:db8:42::2
jexec alcatraz pfctl -e
pft_set_rules alcatraz \
"set reassemble yes" \
"pass"
atf_check -o ignore ping -6 -c 1 2001:db8:43::3
# The fast path: pf must refragment through ip6_forward().
refrag_hlim 0
}
v6_refrag_hlim_cleanup()
{
pft_cleanup
}
atf_test_case "v6_route_to" "cleanup"
v6_route_to_head()
{
@@ -718,6 +772,7 @@ atf_init_test_cases()
{
atf_add_test_case "too_many_fragments"
atf_add_test_case "v6"
atf_add_test_case "v6_refrag_hlim"
atf_add_test_case "v6_route_to"
atf_add_test_case "mtu_diff"
atf_add_test_case "overreplace"