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,
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
mobike = no in the
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_DESTINATION_IP notifications sent in the
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 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).
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
has to handle traffic differently from the default IKE UDP
This has some implications when using a
custom server port (see below).
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).
When using custom server ports, the client for simplicity only uses a single remote
port configured with
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:
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.portsetting is not relevant in this scenario (i.e. the default socket/port will not be used, hence inbound traffic to port 500 could be blocked).
The client must add a non-ESP marker when sending IKE packets to a custom server port or port 4500. strongSwan adds one if neither source nor destination port is 500. This means the client can’t use port 500 in order to already add a non-ESP marker when sending the initial
IKE_SA_INITrequest. This can be achieved by either setting the local port used for IKE (
swanctl.conf) to 4500 or by setting
charon.porton the client to either
0to allocate a random port or any number != 500 (if that port is not used by any other process), so that the source port won’t be 500 and does not have to be set explicitly in the connection config. If the latter is done, the client will, however, switch to the second source port configured via
charon.port_nat_tif a NAT situation is detected or MOBIKE is enabled, so setting both to
0usually makes most sense for mobile clients that connect to a custom server port (but leaving that at 4500 is usually not a problem, either).