NAT Traversal
The IKEv2 protocol includes NAT Traversal (NAT-T) in the core
standard but it is optional to implement for vendors. The strongSwan
charon daemon implements NAT-Traversal
without any special prior configuration but the mechanism cannot be disabled,
either.
|
If you don’t like the automatic port floating to UDP port 4500 due to the
MOBIKE protocol which happens even if no NAT
situation exists, then you can disable MOBIKE by
setting mobike = no in the swanctl.conf
connection definition.
|
Since the ESP protocol with IP protocol number 50
doesn’t have any ports,
per se it is not suited for Port Address Translation, the standard method of
traversing a NAT router for the TCP and UDP protocols.
Some NAT routers have a feature, often called something like IPsec Passthrough that detects outbound IKE traffic from a single host behind the NAT device and will forward inbound IKE and ESP packets to that specific host as shown in the figure below

Unfortunately this won’t work with multiple IPsec clients behind the same NAT router that all want to communicate with the same VPN gateway as shown in the network topology below

The solution proposed by RFC 3948 is to encapsulate ESP packets in
UDP datagrams which then allows to apply Port Address Translation as shown in
the figure above. The well-known NAT Traversal UDP port 4500
is shared with
the IKE protocol when a NAT situation is detected between
the two IPsec endpoints. The detection is based on the NAT_DETECTION_SOURCE_IP
and NAT_DETECTION_DESTINATION_IP
notifications sent in the IKE_SA_INIT
exchange
that contain source and destination IP address hashes, respectively.
ESP-in-UDP encapsulation can be enforced even if no NAT situation exists by setting
encap = yes
for a given connection definition in
swanctl.conf
. If enabled, the
charon
daemon will send a manipulated
NAT_DETECTION_SOURCE_IP
notify payload so that it will look to the remote peer
as if there were a NAT situation.
ESP-in-UDP Encapsulation
ESP-in-UDP encapsulation means that an eight octet UDP header is inserted between
the IP Header and the ESP Header of the ESP packet. At the outset the UDP source
and destination ports are both set to the well-known value 4500
but might get
changed on the way by one or several NAT routers.

The first field in the ESP header right after the UDP header is the 32 bit non-zero Security Parameters Index (SPI).
Non-ESP Marker
If the first 32 bits right after the UDP header are set to zero then instead of
an encapsulated ESP payload packet, an IKE management packet is carried. Thus this
four octet all-zero Non-ESP Marker is used to differentiate between ESP and IKE
traffic. ESP packets are processed in the kernel, whereas the IKE packets are
forwarded to the charon
userland IKE daemon.

The insertion of a Non-ESP Marker means that the default UDP 4500
socket/port
has to handle traffic differently from the default IKE UDP 500
socket/port.
This has some implications when using a
custom server port (see below).
NAT-T Keepalives
When a NAT router applies Port Address Translation to an outbound IP packet, the address/port mapping is stored in an internal lookup table together with a time-to-live value. This mapping is needed by the router so that inbound IP packets can be translated back to the original address/port values.

Since an established IPsec connection can be inactive for minutes or even hours,
the IPsec peer behind a NAT router has to send periodic NAT-T keepalive UDP
packets containing a single 0xff
byte in order to refresh the NAT mapping entry
in the NAT router’s lookup table.
Of course the NAT-T keepalives also reach the IPsec peer on the other side of the
connection but the packets are silently dropped by the kernel. By default the
keep-alives are sent ever 20s
but the interval can configured via the
charon.keep_alive
parameter in
strongswan.conf
(set to 0
to disable
sending keepalives, e.g. behind a static DNAT aka port forwarding).
Custom Server Ports
When using custom server ports, the client for simplicity only uses a single remote
port configured with remote_port
in
swanctl.conf
. This means that there will not be
a port switch while establishing the connection. As described above, if UDP
encapsulation is used, the ESP packets are sent on the ports already used for IKE
traffic. Therefore, the server must be prepared to process UDP-encapsulated ESP
packets on that custom port and consequently is only able to accept IKE packets
with non-ESP marker on it. That in turn forces the client to send all its IKE
packets (including the initial IKE_SA_INIT
request) with a non-ESP marker.
Otherwise they would be treated as UDP-encapsulated ESP packets.
This has implications for the client and the server configuration:
- Server
-
Because the client has to connect to a socket/port that is prepared to process UDP-encapsulated ESP packets, the correct setting to specify a custom port is
charon.port_nat_t
instrongswan.conf
.
Thecharon.port
setting is not relevant in this scenario (i.e. the default socket/port is not be used, so inbound traffic to port 500 could be blocked). - Client
-
The client must add a non-ESP marker when sending IKE packets to port 4500 or a custom server port. strongSwan adds one if neither source nor destination port is 500, which means the client can’t send packets from port 500 so that such a marker gets already added to the initial
IKE_SA_INIT
request.-
Since version 6.0.1, this is handled automatically by sending the initial message from the NAT-T socket if the destination port is not 500.
-
For older releases, this can be achieved in two ways:
-
Either by setting the source port used for IKE to 4500 explicitly in the connection config (
local_port
inswanctl.conf
). -
Or by setting
charon.port
instrongswan.conf
to either0
, to allocate a random port, or any number != 500 (as long as that port is not used by any other process). That way the source port won’t be 500 and also doesn’t have to be set explicitly in the connection config. Note that the client will switch to the second source port configured incharon.port_nat_t
if a NAT situation is detected or MOBIKE is enabled. So setting both to0
usually makes most sense for mobile clients that connect to a custom server port (but leaving the second setting at 4500 is usually not a problem either).
-
-