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
. Thecharon.port
setting 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). - Client
-
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_INIT
request. This can be achieved by either setting the local port used for IKE (local_port
inswanctl.conf
) to 4500 or by settingcharon.port
on the client to either0
to 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 viacharon.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 that at 4500 is usually not a problem, either).