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.

Example:

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

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 10.20.30.2 for packets to 10.0.0.0/8, otherwise NAT to 200.2.2.2. 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.

Background

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: 10.20.30.2[any] 10.0.0.0/8[any] any
2:        out ipsec
3:        esp/tunnel/200.2.2.2-100.1.1.1/require
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 (10.20.30.2) to another (10.0.0.0/8), optionally with some more constraints, e.g. protocol. In our example case a packet going from 10.20.30.2 to 10.0.0.1 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 200.2.2.2 to 100.1.1.1.

[ ... to be continued ... ]
Place for your feedback...
4th October 2004 at 12:19
kernel-xfrm-block.diff Kernel Crash
Hi,

Using SuSE 9.1 Pro, with the latest YOU updates. Kernel 2.6.5-7.108-default.

I applied the patch manually. At first it appeared to behave as expected, queueing the packets. However if data was flowing through the connection and racoon, version 0.3.3-1.2 supplied as part of SuSE install and updated using YOU, was restarted there would be a complete crash. No messages relating to the crash appeared in the messages file, even with the debug turned on in the racoon.conf. Other debug messages were seen OK. This was repeatable.

As a workaround I have a simple way to bring the tunnels up ready by re-reading the setkey.conf file. This only works if the entry is for udp or any. If for example the entry is for tcp it doesn't work.

When excepting icmp there appears to be a difference between using ping and fping on the machine that is the gateway. If ping is used it appears that it considers it to be initially udp and tries to set up a tunnel, then sends the ping requests in the clear. If fping is used then it behaves correctly! I'll put this on the main mailing list with details of the test config file.

SuSE do not appear to have fixed the spddelete bug in the kernel module. I am now using the latest vanilla kernel that has the fix. I haven't tried applying the patch to this to queue the packets, as I'm not aware of any other differences that would effect this.

Thanks,
Bob
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)