Solved NAT + IPSEC ... can't get it to work

At an office, a FreeBSD router is set up using ipfw and nat. This part works great and has for years.

We added an ipsec tunnel for a remote network. I have the tunnel up, and can ping from the internal interface (em1 172.31.0.200) to the remote IP 10.4.4.4, no problem.

For the nat, I set up a 'reverse nat' on the internal interface... I can't add NAT to the external interface as ipsec processes the packet first.
Code:
ipfw nat 2 config ip 172.31.0.200 reverse
ipfw add 1198 nat 2 all from any to 10.4.4.0/24 in via em1
ipfw add 1199 nat 2 all from 10.4.4.0/24 to any out em1

Problem is, that ipsec doesn't pass the packets back to ipfw after it processes the packet and finds out it is 'local' on em1. I can fire up tcpdump on enc0 and see the return packet (verifiing all the ipsec is OK), but I can't get the packet to hop back into divert
Code:
# tcpdump -n -i enc0
13:25:06.775073 (authentic,confidential): SPI 0x008395b0: IP 172.31.0.200 > 10.4.4.4: ICMP echo request, id 46048, seq 1, length 64
13:25:06.775089 (authentic,confidential): SPI 0x008395b0: IP 5.4.3.211 > 93.184.216.34: IP 172.31.0.200 > 10.4.4.4: ICMP echo request, id 46048, seq 1, length 64 (ipip-proto-4)
13:25:06.799967 (authentic,confidential): SPI 0x0519c7cb: IP 93.184.216.34 > 5.4.3.211: IP 10.4.4.4 > 172.31.0.200: ICMP echo reply, id 46048, seq 1, length 64 (ipip-proto-4)


Am I messing up my NAT rule, or is there someway to push the packet into divert after ipsec? Thanks!
 
Please share your full ruleset. Below you find mine and this works just fine with IPsec, em0 is my external interface.
I have somehow "anonymized" my rules by replacing the actual port numbers not related to IPsec with XXX.
If you have dynamic rules, you need to disable one-pass behavior too (and depending on your ruleset default allow).

Code:
00001 reass ip from any to any in
00010 allow ip from any to any via table(trustedif)
00050 deny log ip from any to any not antispoof in
00100 nat 1 ip4 from any to any in recv em0
00500 skipto 10000 tcp from any to any out xmit em0 setup keep-state :default
00501 skipto 10000 udp from any to any out xmit em0 keep-state :default
00502 skipto 10000 icmp from any to any out xmit em0 keep-state :default
00503 skipto 10000 ipv6-icmp from any to any out xmit em0 keep-state :default
05000 allow tcp from any to me XXX in recv em0 setup keep-state :default
05001 allow udp from any to me 500,XXX,4500 in recv em0 keep-state :default
05002 allow icmp from any to me in recv em0 keep-state :default
05003 allow ipv6-icmp from any to any in recv em0 keep-state :default
09999 deny log ip from any to any
10000 nat 1 ip4 from any to any out xmit em0
65535 allow ip from any to any
 
I solved it!


I couldn't get the 'in and out' interfaces the same... packets came in em1 and went out enc0. On return, they came in em0 and didn't go out any interface as the ip address for aliasing was on 172.31.0.200 was local (on em1).
NAT requires the 'ipnat rule' to have a matching in and out rule on the same interface (as far as I can tell).

To solve it, I removed the alias ip from em1 and set a static route OUT my internal interface for the 'fake' NAT ip.
route add 172.31.0.200 -iface em1

Now I have a simple NAT rule at the top of my IPFW and it works:
Code:
ipfw nat 2 config ip 172.31.0.200 same_ports log reverse
ipfw add 10 nat 2 all from any to 10.4.4.0/24 in via em1
ipfw add 11 nat 2 all from 10.4.4.0/24 to any out via em1

The key is that my alias IP is not on any interface!

PS: I am running IPsec on the same box that has the ipfw / nat.
For some not too interesting reasons, we didn't want to push out our internal office IP block to the client via the IPSec tunnel, so we decided to NAT onto one IP not in our network. That is why we didn't just route our whole LAN over IPSec tunnel...
 
Back
Top