Freebsd – NAT outbound IPSEC packets using pf on FreeBSD 11 and StrongSwan x FortiGATE

freebsdipsecpfstrongswan

I've been working for more than a week trying to get outbound packets nat'ed to fit a Security Association.

This is my (example) scenario:

  • LAN: 1.1.1.0/24
  • FreeBSD interface: xn0 (Amazon EC2 instance)
  • Virtual Address to nat traffic from: 2.2.2.2/32
  • Destination to reach: 3.3.3.3/32

Problem description

Despite the fact I've all the SA's up and running in the FreeBSD Box, trying to nat the packets using either pf or ipfw, doesn't work, the nat'ed packet keeps flowing using the default route interface and doesn't get into the ipsec tunnel.

Here is an example SA using:

$ ipsec status vpn
vpn{1}:  INSTALLED, TUNNEL, reqid 1, ESP in UDP SPIs: cca608fa_i d74355dc_o vpn{1}:  AES_CBC_256/HMAC_SHA2_256_128, 2688 bytes_i (32 pkts, 32s ago), 4992 bytes_o (32 pkts, 32s ago), rekeying in 43 minutes vpn{1}:   2.2.2.2/32 === 3.3.3.3/32

this is my nat rule on pf.conf:

nat on enc0 from 1.1.1.0/24 to 2.2.2.2/32 -> 3.3.3.3

This is my ipsec0 interface status:

ipsec0:  flags=8011<UP,POINTOPOINT,MULTICAST> metric 0 mtu 1400     inet 3.3.3.3/32 --> 2.2.2.2/32 netmask 0xffffffff options=23<PERFORMNUD,ACCEPT_RTADV,AUTO_LINKLOCAL>     reqid: 0    groups: ipsec

I can reach 2.2.2.2 from 3.3.3.3 smoothly.

This is a simple packet capture on xn0 (physical interface):

$ tcpdump -i xn0 -n -vvv host 2.2.2.2
1.1.1.10 > 2.2.2.2: ICMP echo request, id 15745, seq 818, length 64

and no traffic is seen on enc0.

Another try was to set via sysctl:

net.inet.ipsec.filtertunnel=1

But I'm not completely sure what exactly this option does.

I've seen many people struggling to get this kind of nat working without success.

Best Answer

After several days struggling I've been able to handle this doing the following steps and will post the solution here to help others

Get the unique ID of the desired SA you want to nat source to, example:

setkey -DP

and find the SA unique ID:

3.3.3.3[any] 2.2.2.2[any] any
    out ipsec
    esp/tunnel/REALIPLOCAL-REALIPREMOTE/unique:1
    created: Jul 22 22:29:34 2018  lastused: Jul 22 22:29:34 2018
    lifetime: 9223372036854775807(s) validtime: 0(s)
    spid=2715 seq=0 pid=13358 scope=global
    refcnt=1

in this case: 1

add a new policy:

setkey -v -c
spdadd -4 1.1.1.0/24 2.2.2.2/32 any -P out ipsec esp/tunnel/REALLOCALIP-REALREMOTEIP/unique:1;

This should be sufficient to route packets inside the tunnel and get them nat'ed to match the real SA installed.

Keep in mind this unique id must match the installed SA and if you change the order of the SA install in StrongSwan you must change this policy to fit the new UniqueID.

The nat rules must be applied on enc0 interface.

Reference:

https://github.com/opnsense/core/issues/440

Good luck.

Related Question