NAT with IPsec on 2.6 kernel

This mini HOWTO explains a solution for a typical situation, where a homeworker...

The picture attempts to describes the situation:

Network scheme

Kernel 2.4.x + FreeS/WAN

In the old forgotten ages of 2.4 it was simple - the IPsec tunnel created its own interface called ipsec0 and all traffic leaving through the tunnel could have been NATted by attaching a hook to that interface.


iptables -t nat -A POSTROUTING -o ipsec0 -j SNAT --to
iptables -t nat -A POSTROUTING -o eth0 -j SNAT --to

Kernel 2.6.x

Unfortunately there is no ipsec0 in 2.6 anymore. Life is hard. Your first idea might be to do the NAT on the outgoing interface and differentiate the resulting address (--to a.b.c.d) according to the packet destination. E.g. NAT to for packets to, otherwise NAT to This does not work. The reason is that on the outgoing interface you normally see only the resulting ESP packets. NATing these doesn't make any sense.

The proper way is to catch the packet yet before it is encrypted, NAT it and then encrypt and encapsulate to ESP and send out. With vanilla kernel 2.6.5 this is not possible. But don't give up! There are patches by Patrick McHardy that allow these packet games. In order to use it you need to patch both kernel and the userspace iptables. From now on I assume that you have the patched kernel running and patched iptables ready.


Every packed being received, forwarded or sent is checked against SPD (Security Policy Database) to see if it should be encapsulated (e.g. to ESP), discarded, or sent as is. SPD rules are of three types: in, fwd and out and are usually set by the userspace IPsec tool (e.g. setkey in the case of IPsec-tools or pluto in case of FreeS/WAN and its otherSWAN successors).

Example of such a SPD rule can be:

   # setkey -DP
1:[any][any] any
2:        out ipsec
3:        esp/tunnel/
4:        created: Jun 17 18:01:03 2004  lastused: Jun 17 18:33:17 2004
5:        lifetime: 0(s) validtime: 0(s)
6:        spid=305 seq=12 pid=3848
7:        refcnt=1

Every SPD rule applies to a packet going from one address ( to another (, optionally with some more constraints, e.g. protocol. In our example case a packet going from to would match the rule. Now the kernel learns that it should use ipsec (line #2, other possibilities are none to send it as is and discard to drop it silently). From line #3 it learns that it must encapsulate the packet to esp in tunnel mode. As a result of this transformation there will be an ESP packet prepared to travel from to

[ ... to be continued ... ]
Place for your feedback...
Oct 4   12:19 kernel-xfrm-block.diff Kernel Crash (by Bob Martin)
Apr 13   12:25 kernel-xfrm-block.diff causes repeateable kernel crash (by Konstantin Shemyak)