ike-natd: Float to the NAT-T port early when not connecting to port 500

When using port 4500 for IKE_SA_INIT, Windows Server 2016, 2025 and
possibly others send back all packets to the port initially used by the
client, not the one floated to before sending IKE_AUTH. So if UDP
encapsulation is used, no traffic can be received as the initial socket
can't have UDP decapsulation enabled.

tcpdump output:
```
IP <client-ip>.47547 > <server-ip>.4500: UDP-encap: ESP(spi=0xfd4e5fc2,seq=...)
IP <server-ip>.4500 > <client-ip>.57962: UDP-encap: ESP(spi=0xccc5e213,seq=...)
```

Avoid this by floating early if a non-default destination port is used.
This also ensures we don't send packets from port 500 (without non-ESP
marker) if ephemeral source ports are not used.

Closes strongswan/strongswan#2664

Signed-off-by: Michael Braun <michael-dev@fami-braun.de>
Co-authored-by: Tobias Brunner <tobias@strongswan.org>
This commit is contained in:
michael-dev
2025-02-28 16:25:32 +01:00
committed by Tobias Brunner
co-authored by Tobias Brunner
parent 882b19c1df
commit bff500dfd0
+23 -1
View File
@@ -340,7 +340,29 @@ METHOD(task_t, build_i, status_t,
ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa);
host = message->get_source(message);
host = message->get_destination(message);
if (host->get_port(host) != IKEV2_UDP_PORT)
{
/* if not connecting to port 500, the destination socket has to enable
* UDP-encap (we can't float to a different destination port later
* if there is a NAT), so we have to use non-ESP markers from the start.
* that is, our source port can't be 500 at this point. we can use two
* different ephemeral ports and float from one to the other as we'd do
* normally (if neither port is 500, a marker is added). unfortunately,
* some implementations don't reply to the correct port when we do that,
* breaking UDP-encap as our first socket can't process such messages.
* so we switch now, which ensures (1) that we don't send from port 500
* if no ephemeral ports are used and (2) that the source port doesn't
* change later (at least not because of us) */
this->ike_sa->float_ports(this->ike_sa);
host = this->ike_sa->get_my_host(this->ike_sa);
message->set_source(message, host->clone(host));
}
else
{
host = message->get_source(message);
}
if (!host->is_anyaddr(host) || force_encap(ike_cfg))
{
notify = build_natd_payload(this, NAT_DETECTION_SOURCE_IP, host);