From 462b02de4107845ab235e1668f78a43a31eb11fc Mon Sep 17 00:00:00 2001 From: Ondrej Holy Date: Wed, 14 Jan 2026 13:38:42 +0100 Subject: [PATCH] [core,tcp] Fix PreferIPv6OverIPv4 fallback to IPv4 addresses Backport of commit 0bdd8da0993231216a7bb4d5e6e33e47d817a944. Co-Authored-By: Claude --- libfreerdp/core/tcp.c | 61 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 51 insertions(+), 10 deletions(-) diff --git a/libfreerdp/core/tcp.c b/libfreerdp/core/tcp.c index 8a731f117..3cf24c160 100644 --- a/libfreerdp/core/tcp.c +++ b/libfreerdp/core/tcp.c @@ -1064,6 +1064,53 @@ static BOOL freerdp_tcp_set_keep_alive_mode(const rdpSettings* settings, int soc return TRUE; } +static struct addrinfo* reorder_addrinfo_by_preference(rdpContext* context, struct addrinfo* addr) +{ + WINPR_ASSERT(context); + WINPR_ASSERT(addr); + + const BOOL preferIPv6 = + freerdp_settings_get_bool(context->settings, FreeRDP_PreferIPv6OverIPv4); + if (!preferIPv6) + return addr; + + struct addrinfo* ipv6Head = NULL; + struct addrinfo* ipv6Tail = NULL; + struct addrinfo* otherHead = NULL; + struct addrinfo* otherTail = NULL; + + /* Partition the list into IPv6 and other addresses */ + while (addr) + { + struct addrinfo* next = addr->ai_next; + addr->ai_next = NULL; + + if (addr->ai_family == AF_INET6) + { + if (!ipv6Head) + ipv6Head = addr; + else + ipv6Tail->ai_next = addr; + ipv6Tail = addr; + } + else + { + if (!otherHead) + otherHead = addr; + else + otherTail->ai_next = addr; + otherTail = addr; + } + addr = next; + } + + /* Concatenate the lists */ + if (ipv6Tail) + ipv6Tail->ai_next = otherHead; + + return ipv6Head ? ipv6Head : otherHead; +} + static int get_next_addrinfo(rdpContext* context, struct addrinfo* input, struct addrinfo** result, UINT32 errorCode) { @@ -1074,14 +1121,6 @@ static int get_next_addrinfo(rdpContext* context, struct addrinfo* input, struct if (!addr) goto fail; - if (freerdp_settings_get_bool(context->settings, FreeRDP_PreferIPv6OverIPv4)) - { - while (addr && (addr->ai_family != AF_INET6)) - addr = addr->ai_next; - if (!addr) - addr = input; - } - *result = addr; return 0; @@ -1161,9 +1200,11 @@ int freerdp_tcp_connect(rdpContext* context, rdpSettings* settings, const char* freerdp_set_last_error_log(context, 0); /* - * If PreferIPv6OverIPv4 = TRUE we force to IPv6 if there - * is such an address available, but fall back to first if not found + * If PreferIPv6OverIPv4 = TRUE we reorder addresses by preference: + * IPv6 addresses come first, then other addresses. */ + result = reorder_addrinfo_by_preference(context, result); + const int rc = get_next_addrinfo(context, result, &addr, FREERDP_ERROR_DNS_NAME_NOT_FOUND); if (rc < 0) -- 2.52.0