]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
ike-natd: Float to the NAT-T port early when not connecting to port 500
authormichael-dev <michael-dev@fami-braun.de>
Mon, 10 Feb 2025 12:36:34 +0000 (13:36 +0100)
committerTobias Brunner <tobias@strongswan.org>
Fri, 28 Feb 2025 15:25:32 +0000 (16:25 +0100)
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>
src/libcharon/sa/ikev2/tasks/ike_natd.c

index 72d057e627cf8f7dec5729da622c0402533d24bc..a9cce2efb42dd609282878bfac681613c669ef9e 100644 (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);