According to the example of the handbook regarding NAT (https://www.freebsd.org/doc/handbook/firewalls-ipfw.html), the inbound NAT rule should be placed first (below 0400) followed by the outbound NAT rule (below 24000) -------8<-------- ipfw nat 123 config ip xxx.xxx.xxx.xxx same_ports reset 00100 reass ip from any to any in 00200 allow ip from any to any via lo0 00300 allow ip from any to any via em1 00400 nat 123 ip from any to any in recv em0 00500 check-state 00600 skipto 24000 ip from any to me dst-port 80,443,22,500,4500,1194,993,8112 in recv em0 keep-state 00700 skipto 24000 ip from any to any out xmit em0 keep-state 00800 deny log ip from any to any 24000 nat 123 ip from any to any out xmit em0 24100 allow ip from any to any -------8<-------- However this allows some packets to escape NAT (why?) and IPs on the LAN (behind NAT) are exposed on the external interface (where NAT is performed). When one places the NAT rules with the opposite order (i.e. outbound rule first and then the inbound rule) the problem disappears. -------8<-------- ipfw nat 123 config ip xxx.xxx.xxx.xxx same_ports reset 00100 reass ip from any to any in 00200 allow ip from any to any via lo0 00300 allow ip from any to any via em1 00400 nat 123 ip from any to any out xmit em0 00500 check-state 00600 skipto 24000 ip from any to me dst-port 80,443,22,500,4500,1194,993,8112 in recv em0 keep-state 00700 skipto 24000 ip from any to any out xmit em0 keep-state 00800 deny log ip from any to any 24000 nat 123 ip from any to any in recv em0 24100 allow ip from any to any -------8<-------- See https://forums.freebsd.org/threads/ipfw-keep-state-and-in-kernel-nat-exposes-local-ip-on-external-interface.52134/
You're not alone. I got the same problem for months. See https://forums.freebsd.org/threads/some-ip-frames-not-nated-with-ipfw-natd.51015/ for more information.
(In reply to dlegrand from comment #1) Could you confirm that reversing the NAT rules resolves the issue for you?
(In reply to g_amanakis@yahoo.com from comment #2) I've done the changes you proposed, and there is no more IP packet not nated. But I don't think there is an error in the handbook for the intended purpose in the NAT section. If the outbound traffic is aliased before checking rules in your IPFW rules file, you can't check on LAN private IP because the private IP is replaced with your public IP. This is why we are using 'skipto' to do outbound aliasing after the check on private IP. I think there is something wrong with IPFW + NAT, but the handbook seems OK.
(In reply to dlegrand from comment #3) You are definitely right. See PR 201590. https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=201590