mirror of
https://github.com/morgan9e/FreeRDP
synced 2026-04-15 00:44:19 +09:00
[core,tcp] Fix PreferIPv6OverIPv4 fallback to IPv4 addresses
Currently, when the `FreeRDP_PreferIPv6OverIPv4` option is `TRUE` and the `getaddrinfo` function returns IPv4 addresses before IPv6 addresses, the code tries all IPv6 addresses, but it doesn't try any IPv4 address. This happens because the `get_next_addrinfo` function skips to the first IPv6 address, but never goes back to try IPv4 addresses that appeared earlier in the list. Let's fix this by reordering the address list first when the `PreferIPv6OverIPv4` option is `TRUE`. Co-Authored-By: Claude <noreply@anthropic.com> Related: https://github.com/FreeRDP/FreeRDP/issues/5335
This commit is contained in:
@@ -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);
|
||||
@@ -1200,9 +1239,11 @@ static int freerdp_host_connect(rdpContext* context, const char* hostname, int p
|
||||
freerdp_set_last_error_log(context, 0);
|
||||
|
||||
/* 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)
|
||||
goto fail;
|
||||
|
||||
Reference in New Issue
Block a user