[Bug 268241] broken handling of icmp needfrag packets with libalias/ipfw_nat and smaller wan mtu

From: <bugzilla-noreply_at_freebsd.org>
Date: Thu, 08 Dec 2022 11:31:26 UTC
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=268241

            Bug ID: 268241
           Summary: broken handling of icmp needfrag packets with
                    libalias/ipfw_nat and smaller wan mtu
           Product: Base System
           Version: 13.1-RELEASE
          Hardware: Any
                OS: Any
            Status: New
          Severity: Affects Only Me
          Priority: ---
         Component: kern
          Assignee: bugs@FreeBSD.org
          Reporter: john@sanren.ac.za

Created attachment 238625
  --> https://bugs.freebsd.org/bugzilla/attachment.cgi?id=238625&action=edit
patch to make needfrag packets work with nat and an interface with a smaller
mtu on the same device.

When using ipfw + nat on the same device as the wan interface and the mtu of
the wan interface is smaller than the default, the created needfrag packets are
not handled correctly.

The problem is if a packet is received from the lan it will go through nat and
gets translated to use the ip address of the outgoing interface as source ip.
If it then tries to send it out, the output part of the stack will realize that
it is too big and create the needfrag icmp packet. It will use the source ip as
the destination and realize that is a local address and use 127.0.0.1 as the
source address and route it on lo0. Currently libalias has no way to fix the
source ip of 127.0.0.1.

Using firewall rules like this:

#####
wan="vtnet0"
lan="vtnet1"
${fwcmd} nat 123 config if ${wan} log
${fwcmd} add 1000 count log all from any to any
${fwcmd} add 5000 nat 123 ip4 from any to any via ${wan}
${fwcmd} add 5050 nat 123 ip4 from any to not 127.0.0.1 via lo0
${fwcmd} add 6000 allow log all from any to any
#####

Results in the ipfw logs like this. (The client is 10.10.1.3, the wan
interface/nat address is 10.10.2.2 and the test target is 10.10.5.5)

#####
Dec  7 14:17:31 rtr kernel: ipfw: 1000 Count ICMP:8.0 10.10.1.3 10.10.5.5 in
via vtnet1
Dec  7 14:17:31 rtr kernel: ipfw: 6000 Accept ICMP:8.0 10.10.1.3 10.10.5.5 in
via vtnet1
Dec  7 14:17:31 rtr kernel: ipfw: 1000 Count ICMP:8.0 10.10.1.3 10.10.5.5 out
via vtnet0
Dec  7 14:17:31 rtr kernel: ipfw: 6000 Accept ICMP:8.0 10.10.2.2 10.10.5.5 out
via vtnet0
Dec  7 14:17:31 rtr kernel: ipfw: 1000 Count ICMP:3.4 127.0.0.1 10.10.2.2 out
via lo0
Dec  7 14:17:31 rtr kernel: ipfw: 6000 Accept ICMP:3.4 127.0.0.1 10.10.2.2 out
via lo0
Dec  7 14:17:31 rtr kernel: ipfw: 1000 Count ICMP:3.4 127.0.0.1 10.10.2.2 in
via lo0
Dec  7 14:17:31 rtr kernel: ipfw: 6000 Accept ICMP:3.4 127.0.0.1 10.10.1.3 in
via lo0
Dec  7 14:17:31 rtr kernel: ipfw: 1000 Count ICMP:3.4 127.0.0.1 10.10.1.3 out
via vtnet1
Dec  7 14:17:31 rtr kernel: ipfw: 6000 Accept ICMP:3.4 127.0.0.1 10.10.1.3 out
via vtnet1
######

I have made a patch to libalias/alias.c in IcmpAliasIn2() to check if the
source ip is IN_LOOPBACK() and the destination is not IN_LOOPBACK() and then
just copy the destination to the source address. There might be better ways and
it might be better to use the ip address of the outgoing interface as the
source, but it did not seem easy to retrieve that from inside libalias.

With this ping and ssh works as expected.

Regards

John

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