Try next DNS entry on connect failure

Resolves: RHEL-113722
This commit is contained in:
Ondrej Holy 2026-01-16 10:49:11 +01:00
parent 8730c65986
commit e95c7d895e
6 changed files with 384 additions and 1 deletions

View File

@ -0,0 +1,55 @@
From c3673aaa5b65e8670c218bdfb5916a4112b628c7 Mon Sep 17 00:00:00 2001
From: Ondrej Holy <oholy@redhat.com>
Date: Wed, 14 Jan 2026 13:29:34 +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 | 18 ++++++++++++++----
1 file changed, 14 insertions(+), 4 deletions(-)
diff --git a/libfreerdp/core/tcp.c b/libfreerdp/core/tcp.c
index 1d7eda92e..8a731f117 100644
--- a/libfreerdp/core/tcp.c
+++ b/libfreerdp/core/tcp.c
@@ -26,8 +26,11 @@
#include <errno.h>
#include <fcntl.h>
+#include <inttypes.h>
+
#include <winpr/crt.h>
#include <winpr/platform.h>
+#include <winpr/string.h>
#include <winpr/winsock.h>
#if !defined(_WIN32)
@@ -846,12 +849,19 @@ static BOOL freerdp_tcp_connect_timeout(rdpContext* context, int sockfd, struct
if (WAIT_OBJECT_0 != status)
goto fail;
- status = recv(sockfd, NULL, 0, 0);
-
- if (status == 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 462b02de4107845ab235e1668f78a43a31eb11fc Mon Sep 17 00:00:00 2001
From: Ondrej Holy <oholy@redhat.com>
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 <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 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

View File

@ -0,0 +1,76 @@
From 051218feec6c3404e625637c9d812817b7d69c26 Mon Sep 17 00:00:00 2001
From: Ondrej Holy <oholy@redhat.com>
Date: Wed, 14 Jan 2026 13:28:18 +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 efc2aec36..1d7eda92e 100644
--- a/libfreerdp/core/tcp.c
+++ b/libfreerdp/core/tcp.c
@@ -1162,34 +1162,37 @@ int freerdp_tcp_connect(rdpContext* context, rdpSettings* settings, const char*
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 rc = get_next_addrinfo(context, addr->ai_next, &addr,
FREERDP_ERROR_CONNECT_FAILED);
if (rc < 0)
+ {
+ freeaddrinfo(result);
+ freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_FAILED);
+ WLog_ERR(TAG, "failed to connect to %s", hostname);
return rc;
+ }
}
} 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 c13c873fcd3e95dcb21e5a811ac878c21ce38d80 Mon Sep 17 00:00:00 2001
From: Ondrej Holy <oholy@redhat.com>
Date: Wed, 14 Jan 2026 13:39:04 +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 3cf24c160..25632f882 100644
--- a/libfreerdp/core/tcp.c
+++ b/libfreerdp/core/tcp.c
@@ -1126,7 +1126,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;
}
@@ -1208,7 +1208,10 @@ int freerdp_tcp_connect(rdpContext* context, rdpSettings* settings, const char*
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

@ -0,0 +1,100 @@
From 84f0e60c998d7c497d141492f7933bc940f7b239 Mon Sep 17 00:00:00 2001
From: Ondrej Holy <oholy@redhat.com>
Date: Tue, 6 Jan 2026 12:38:34 +0100
Subject: [PATCH] [core,tcp] retry all DNS entries until success
Backport of commit 4286a4c16495916fbfa6b8a6764c35fc82e1c5ba.
Co-Authored-By: Claude <noreply@anthropic.com>
---
libfreerdp/core/tcp.c | 63 +++++++++++++++++++++++++++++--------------
1 file changed, 43 insertions(+), 20 deletions(-)
diff --git a/libfreerdp/core/tcp.c b/libfreerdp/core/tcp.c
index 0d0641b82..efc2aec36 100644
--- a/libfreerdp/core/tcp.c
+++ b/libfreerdp/core/tcp.c
@@ -1054,6 +1054,33 @@ static BOOL freerdp_tcp_set_keep_alive_mode(const rdpSettings* settings, int soc
return TRUE;
}
+static int get_next_addrinfo(rdpContext* context, struct addrinfo* input, struct addrinfo** result,
+ UINT32 errorCode)
+{
+ WINPR_ASSERT(context);
+ WINPR_ASSERT(result);
+
+ struct addrinfo* addr = input;
+ 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;
+
+fail:
+ freerdp_set_last_error_if_not(context, errorCode);
+ freeaddrinfo(input);
+ return -1;
+}
+
int freerdp_tcp_connect(rdpContext* context, rdpSettings* settings, const char* hostname, int port,
DWORD timeout)
{
@@ -1123,30 +1150,26 @@ int freerdp_tcp_connect(rdpContext* context, rdpSettings* settings, const char*
}
freerdp_set_last_error_log(context, 0);
- addr = result;
+ /*
+ * If PreferIPv6OverIPv4 = TRUE we force to IPv6 if there
+ * is such an address available, but fall back to first if not found
+ */
+ const int rc =
+ get_next_addrinfo(context, result, &addr, FREERDP_ERROR_DNS_NAME_NOT_FOUND);
+ if (rc < 0)
+ return rc;
- if ((addr->ai_family == AF_INET6) && (addr->ai_next != 0) &&
- !settings->PreferIPv6OverIPv4)
+ do
{
- while ((addr = addr->ai_next))
+ sockfd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
+ if (sockfd < 0)
{
- if (addr->ai_family == AF_INET)
- break;
+ const int rc = get_next_addrinfo(context, addr->ai_next, &addr,
+ FREERDP_ERROR_CONNECT_FAILED);
+ if (rc < 0)
+ return rc;
}
-
- if (!addr)
- addr = result;
- }
-
- sockfd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
-
- if (sockfd < 0)
- {
- freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_FAILED);
-
- freeaddrinfo(result);
- return -1;
- }
+ } while (sockfd < 0);
if ((peerAddress = freerdp_tcp_address_to_string(
(const struct sockaddr_storage*)addr->ai_addr, NULL)) != NULL)
--
2.52.0

View File

@ -27,7 +27,7 @@
Name: freerdp
Version: 2.11.7
Release: 1%{?dist}
Release: 2%{?dist}
Epoch: 2
Summary: Free implementation of the Remote Desktop Protocol (RDP)
License: ASL 2.0
@ -35,6 +35,13 @@ URL: http://www.freerdp.com/
Source0: https://github.com/FreeRDP/FreeRDP/archive/%{version}/FreeRDP-%{version}.tar.gz
# https://issues.redhat.com/browse/RHEL-113722
Patch: core-tcp-retry-all-DNS-entries-until-success.patch
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
@ -292,6 +299,10 @@ find %{buildroot} -name "*.a" -delete
%{_libdir}/pkgconfig/winpr-tools2.pc
%changelog
* Fri Jan 16 2026 Ondrej Holy <oholy@redhat.com> - 2:2.11.7-2
- Try next DNS entry on connect failure
Resolves: RHEL-113722
* Thu May 09 2024 Ondrej Holy <oholy@redhat.com> - 2:2.11.7-1
- Update to 2.11.7 (CVE-2024-32039, CVE-2024-32040, CVE-2024-32041,
CVE-2024-32458, CVE-2024-32459, CVE-2024-32460, CVE-2024-32658,