[Bug 268717] [pf] rdr rules don't work for traffic originating at localhost

From: <bugzilla-noreply_at_freebsd.org>
Date: Fri, 06 Jan 2023 02:39:02 UTC
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=268717

Kristof Provost <kp@freebsd.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |kp@freebsd.org

--- Comment #7 from Kristof Provost <kp@freebsd.org> ---
(In reply to dfr from comment #6)
I've been poking at this a bit as well (briefly, because I'm supposed to be on
vacation), and I believe your diagnosis may be correct.

To summarise what I've done so far: after turning your script into a atf-sh
test case I can reproduce the problem, and poke at things with dtrace.

The test script sets up a vnet jail (IP 192.0.2.1) with an rdr rule redirecting
traffic for 192.0.2.1:8080 to 192.0.2.2:8080.

The following D script:

#!/usr/sbin/dtrace -s

fbt:pf:pf_state_insert:entry
{
        s = (struct pf_state_key *)arg2;

        printf("%x -> %x, %d:%d af %d proto %d\n", s->addr[0].pfa.v4.s_addr,
                s->addr[1].pfa.v4.s_addr,
                ntohs(s->port[0]), ntohs(s->port[1]), s->af, s->proto);

        s = (struct pf_state_key *)arg3;

        printf("%x -> %x, %d:%d af %d proto %d", s->addr[0].pfa.v4.s_addr,
                s->addr[1].pfa.v4.s_addr,
                ntohs(s->port[0]), ntohs(s->port[1]), s->af, s->proto);

stack();
}

fbt:pf:pf_find_state:entry
{
        s = (struct pf_state_key *)arg1;

        printf("%x -> %x, %d:%d af %d proto %d", s->addr[0].pfa.v4.s_addr,
                s->addr[1].pfa.v4.s_addr,
                ntohs(s->port[0]), ntohs(s->port[1]), s->af, s->proto);
}
fbt:pf:pf_find_state:return
{
        printf("=> %p", arg1);
}

produces 

dtrace: script '/home/kp/pf.dtrace' matched 3 probes
CPU     ID                    FUNCTION:NAME
  5  80283              pf_find_state:entry 10200c0 -> 10200c0, 8080:40477 af 2
proto 6
  5  80284             pf_find_state:return => 0
  6  80283              pf_find_state:entry 10200c0 -> 10200c0, 40477:8080 af 2
proto 6
  6  80284             pf_find_state:return => 0
  6  80537            pf_state_insert:entry 10200c0 -> 10200c0, 40477:8080 af 2
proto 6
10200c0 -> 20200c0, 40477:8080 af 2 proto 6
              pf.ko`pf_test_rule+0x282b
              pf.ko`pf_check_in+0x25
              kernel`pfil_mbuf_in+0x55
              kernel`ip_input+0x3c6
              kernel`swi_net+0x191
              kernel`ithread_loop+0x279
              kernel`fork_exit+0x80
              kernel`0xffffffff810a44ae

  6  80283              pf_find_state:entry 20200c0 -> 10200c0, 8080:40477 af 2
proto 6
  6  80284             pf_find_state:return => 0

So I think that matches your diagnosis, in that we're creating states (both the
original 192.0.2.1 to 192.0.2.1 and rdr'd 192.0.2.1 to 192.0.2.2 traffic, but
only on PF_IN. When the reply comes in we don't find a corresponding state, and
things don't work.

I'm rather wary of inserting special case handling for this in pf_test(). I
wonder if we don't need to add a pfil call in the if_lo handling somewhere, to
make that traffic match the normal (i.e. non-loopback) traffic patter.

-- 
You are receiving this mail because:
You are the assignee for the bug.