Try next DNS entry on connect failure

Resolves: RHEL-140099
This commit is contained in:
Ondrej Holy 2026-01-16 10:36:15 +01:00
parent 6f098d9bcc
commit f4bdce6aba
5 changed files with 271 additions and 1 deletions

View File

@ -0,0 +1,43 @@
From 5a856bef31bdbecbaf69bd671d23add9779debd9 Mon Sep 17 00:00:00 2001
From: Ondrej Holy <oholy@redhat.com>
Date: Wed, 14 Jan 2026 11:37:16 +0100
Subject: [PATCH] [core,tcp] Don't ignore connect errors
Backport of commit 0bdd8da0993231216a7bb4d5e6e33e47d817a944.
Co-Authored-By: Claude <noreply@anthropic.com>
---
libfreerdp/core/tcp.c | 15 +++++++++++----
1 file changed, 11 insertions(+), 4 deletions(-)
diff --git a/libfreerdp/core/tcp.c b/libfreerdp/core/tcp.c
index 8e7ee20bd..6edfb6d71 100644
--- a/libfreerdp/core/tcp.c
+++ b/libfreerdp/core/tcp.c
@@ -857,12 +857,19 @@ static BOOL freerdp_tcp_connect_timeout(rdpContext* context, int sockfd, struct
if (WAIT_OBJECT_0 != status)
goto fail;
- const SSIZE_T res = recv(sockfd, NULL, 0, 0);
-
- if (res == SOCKET_ERROR)
{
- if (WSAGetLastError() == WSAECONNRESET)
+ INT32 optval = 0;
+ socklen_t optlen = sizeof(optval);
+ if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, &optlen) < 0)
+ goto fail;
+
+ if (optval != 0)
+ {
+ char ebuffer[256] = { 0 };
+ WLog_DBG(TAG, "connect failed with error: %s [%" PRId32 "]",
+ winpr_strerror(optval, ebuffer, sizeof(ebuffer)), optval);
goto fail;
+ }
}
status = WSAEventSelect(sockfd, handles[0], 0);
--
2.52.0

View File

@ -0,0 +1,102 @@
From 4864954a384e4028298e95a19795505f688b21ae Mon Sep 17 00:00:00 2001
From: Ondrej Holy <oholy@redhat.com>
Date: Wed, 14 Jan 2026 11:38:11 +0100
Subject: [PATCH] [core,tcp] Fix PreferIPv6OverIPv4 fallback to IPv4 addresses
Backport of commit 0bdd8da0993231216a7bb4d5e6e33e47d817a944.
Co-Authored-By: Claude <noreply@anthropic.com>
---
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 6edfb6d71..83cc9af1e 100644
--- a/libfreerdp/core/tcp.c
+++ b/libfreerdp/core/tcp.c
@@ -1081,6 +1081,53 @@ int freerdp_tcp_connect(rdpContext* context, const char* hostname, int port, DWO
return transport_tcp_connect(context->rdp->transport, hostname, port, timeout);
}
+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)
{
@@ -1091,14 +1138,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;
- }
-
/* We want to force IPvX, abort if not detected */
const UINT32 IPvX = freerdp_settings_get_uint32(context->settings, FreeRDP_ForceIPvX);
switch (IPvX)
@@ -1237,9 +1276,11 @@ int freerdp_tcp_default_connect(rdpContext* context, rdpSettings* settings, cons
/* By default we take the first returned entry.
*
- * 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

View File

@ -0,0 +1,76 @@
From e4adf227177fd807f47f8621a5e2568748619a23 Mon Sep 17 00:00:00 2001
From: Ondrej Holy <oholy@redhat.com>
Date: Wed, 14 Jan 2026 11:34:53 +0100
Subject: [PATCH] [core,tcp] Try next DNS entry on connect failure
Backport of commit bd67348eb3380a66b544835346191bd2138a5ba4.
Co-Authored-By: Claude <noreply@anthropic.com>
---
libfreerdp/core/tcp.c | 41 ++++++++++++++++++++++-------------------
1 file changed, 22 insertions(+), 19 deletions(-)
diff --git a/libfreerdp/core/tcp.c b/libfreerdp/core/tcp.c
index 53e3a412f..8e7ee20bd 100644
--- a/libfreerdp/core/tcp.c
+++ b/libfreerdp/core/tcp.c
@@ -1241,34 +1241,37 @@ int freerdp_tcp_default_connect(rdpContext* context, rdpSettings* settings, cons
do
{
sockfd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
+ if (sockfd >= 0)
+ {
+ if ((peerAddress = freerdp_tcp_address_to_string(
+ (const struct sockaddr_storage*)addr->ai_addr, NULL)) != NULL)
+ {
+ WLog_DBG(TAG, "connecting to peer %s", peerAddress);
+ free(peerAddress);
+ }
+
+ if (!freerdp_tcp_connect_timeout(context, sockfd, addr->ai_addr,
+ addr->ai_addrlen, timeout))
+ {
+ close(sockfd);
+ sockfd = -1;
+ }
+ }
+
if (sockfd < 0)
{
const int lrc = get_next_addrinfo(context, addr->ai_next, &addr,
FREERDP_ERROR_CONNECT_FAILED);
if (lrc < 0)
+ {
+ freeaddrinfo(result);
+ freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_FAILED);
+ WLog_ERR(TAG, "failed to connect to %s", hostname);
return lrc;
+ }
}
} while (sockfd < 0);
- if ((peerAddress = freerdp_tcp_address_to_string(
- (const struct sockaddr_storage*)addr->ai_addr, NULL)) != NULL)
- {
- WLog_DBG(TAG, "connecting to peer %s", peerAddress);
- free(peerAddress);
- }
-
- if (!freerdp_tcp_connect_timeout(context, sockfd, addr->ai_addr, addr->ai_addrlen,
- timeout))
- {
- freeaddrinfo(result);
- close(sockfd);
-
- freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_FAILED);
-
- WLog_ERR(TAG, "failed to connect to %s", hostname);
- return -1;
- }
-
freeaddrinfo(result);
}
}
--
2.52.0

View File

@ -0,0 +1,39 @@
From 0a660bf3b3cf2660a4fa15bd37d8b8b3d03fbfef Mon Sep 17 00:00:00 2001
From: Ondrej Holy <oholy@redhat.com>
Date: Wed, 14 Jan 2026 12:55:42 +0100
Subject: [PATCH] [core,tcp] fix double free in get_next_addrinfo
Backport of commit 48197426444b7b3587874b5eae175af1113beab8.
Co-Authored-By: Claude <noreply@anthropic.com>
---
libfreerdp/core/tcp.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/libfreerdp/core/tcp.c b/libfreerdp/core/tcp.c
index 83cc9af1e..a3e12d14b 100644
--- a/libfreerdp/core/tcp.c
+++ b/libfreerdp/core/tcp.c
@@ -1164,7 +1164,7 @@ static int get_next_addrinfo(rdpContext* context, struct addrinfo* input, struct
fail:
freerdp_set_last_error_if_not(context, errorCode);
- freeaddrinfo(input);
+ *result = NULL;
return -1;
}
@@ -1284,7 +1284,10 @@ int freerdp_tcp_default_connect(rdpContext* context, rdpSettings* settings, cons
const int rc =
get_next_addrinfo(context, result, &addr, FREERDP_ERROR_DNS_NAME_NOT_FOUND);
if (rc < 0)
+ {
+ freeaddrinfo(result);
return rc;
+ }
do
{
--
2.52.0

View File

@ -30,7 +30,7 @@
Name: freerdp
Epoch: 2
Version: 3.10.3
Release: 6%{?dist}
Release: 7%{?dist}
Summary: Free implementation of the Remote Desktop Protocol (RDP)
# The effective license is Apache-2.0 but:
@ -59,6 +59,12 @@ Patch4: Limit-minimum-threadpool-size.patch
# https://issues.redhat.com/browse/RHEL-73724
Patch: core-connection-print-SSL-warnings-after-init.patch
# https://issues.redhat.com/browse/RHEL-140099
Patch: core-tcp-Try-next-DNS-entry-on-connect-failure.patch
Patch: core-tcp-Don-t-ignore-connect-errors.patch
Patch: core-tcp-Fix-PreferIPv6OverIPv4-fallback-to-IPv4-add.patch
Patch: core-tcp-fix-double-free-in-get_next_addrinfo.patch
BuildRequires: gcc
BuildRequires: gcc-c++
BuildRequires: alsa-lib-devel
@ -382,6 +388,10 @@ find %{buildroot} -name "*.a" -delete
%{_libdir}/pkgconfig/winpr-tools3.pc
%changelog
* Fri Jan 16 2026 Ondrej Holy <oholy@redhat.com> - 2:3.10.3-7
- Try next DNS entry on connect failure
Resolves: RHEL-140099
* Tue Dec 16 2025 Ondrej Holy <oholy@redhat.com> - 2:3.10.3-6
- Fix broken SSL checks and disable runtime checks (RHEL-73724)