Re: pf.c: IPv6 Fragmentation Tag Not Cleared after Reassembly

Alexandr Nedvedicky <[email protected]>
Newsgroups gmane.os.openbsd.bugs
Message-ID <[email protected]>
Hello,

I still need to configure wireguard tunnel over IPv6 just to
try it out first so I can understand things better.

to get to this code path one needs to set wg(4) mtu to 9k and try to
send ICMPv6 echo-requests 32k big. then we should get to 'double
fragmentation' path:

	32k -> 9k -> ~1.5k (physical ethernet)

receiving reply goes in reverse direction:

    ip6_input_if() on ethernet
	pf_test(PF_IN, 1.5k)
	    add PACKET_TAG_PF_REASSEMBLED
	    reassemble packet to 9k UDP datagram with wg(4) payload

	ip_ours()
	    wg_input()
		the PACKET_TAG_PF_REASSEMBLED is left at mbuf
		pf_pkt_addr_changed(m)
		put packet to wg_deliver_in() task which calls ip6_input_if()


the ip6_input_if() task then does:

    pf_test(PF_IN, 9k)

	add PACKET_TAG_PF_REASSEMBLED after 9k frags are
	reassembled to 32k ICMPv6 fragment. my understanding
	is the packet has two PACKET_TAG_PF_REASSEMBLED tags now.
	one for ethernet, the other for wireguard.

    ip_ours() for local bound packets or ip6_forward() for forwarding
    local bound traffic should should be fine here.

    it's forwarding case what brings us to code path where we hit
    error. for forwarding case the IP stack calls pf_test() again

    pf_test(PF_FWD, 32k). the code reaches the area touched by your diff:

8786 
8787 #ifdef INET6
8788         /* if reassembled packet passed, create new fragments */
8789         if (pf_status.reass && action == PF_PASS && pd.m && fwdir == PF_FWD &&
8790             pd.af == AF_INET6) {
8791                 struct m_tag    *mtag;
8792 
8793                 if ((mtag = m_tag_find(pd.m, PACKET_TAG_PF_REASSEMBLED, NULL)))
8794                         action = pf_refragment6(&pd.m, mtag, NULL, NULL, NULL);
8795         }
8796 #endif  /* INET6 */

     the pf_refragment() creates a chain of brand new packets. the frag sizes
     match the MTU of outbound interface.

So this is my understadning. I was trying to think of some observable error.
but apart from having a packet with two REASSEMBLED tags attached I can not
think of anything else that goes wrong here.

I'm more concerned the things may actually break when the tag is deleted
for PF_IN packets. that's just my gut feeling about it.


thanks and
regards
sashan


On Sun, Aug 09, 2026 at 04:35:58PM +0000, Zixu Wu wrote:
</snip>
> diff --git a/sys/net/pf.c b/sys/net/pf.c
> index 0fd00c0dbf3..493b7385730 100644
> --- a/sys/net/pf.c
> +++ b/sys/net/pf.c
> @@ -8785,13 +8785,17 @@ done:
>   }
> 
>  #ifdef INET6
> - /* if reassembled packet passed, create new fragments */
> - if (pf_status.reass && action == PF_PASS && pd.m && fwdir == PF_FWD &&
> -     pd.af == AF_INET6) {
> + /* create new fragments if necessary */
> + if (pd.m && pd.af == AF_INET6) {
>     struct m_tag  *mtag;
> 
> -   if ((mtag = m_tag_find(pd.m, PACKET_TAG_PF_REASSEMBLED, NULL)))
> -     action = pf_refragment6(&pd.m, mtag, NULL, NULL, NULL);
> +   if ((mtag = m_tag_find(pd.m, PACKET_TAG_PF_REASSEMBLED, NULL))) {
> +     if (action == PF_PASS && fwdir == PF_FWD) {
> +       action = pf_refragment6(&pd.m, mtag, NULL, NULL, NULL);
> +     } else {
> +       m_tag_delete(pd.m, mtag);
> +     }
> +   }
>   }
>  #endif /* INET6 */
>   if (st && action != PF_DROP) {
>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.