From 3a0dd1cbe5029c7eaff261c1ab133828de475722 Mon Sep 17 00:00:00 2001 From: Sly Gryphon Date: Fri, 12 Apr 2024 19:28:12 +1000 Subject: [PATCH] fix(dns): Fix IPv6-only network, by checking IPv6 first if you have public address (#9443) Work around because AF_UNSPEC does not check available addresses when determining result. If you have a global scope IPv6 address, then first check for IPv6 DNS result; if you don't have an IPv6, or there is no IPv6 result, then check IPv4. This allows IPv6-only networks to connect to dual-stack destinations, as they will get the IPv6 address (rather than the unusable IPv4). It also means a dual-stack host to a dual-stack destination will preference IPv6. There is no effect if you are on an IPv4-only network, or it is an IPv4-only destination. --- libraries/Network/src/NetworkManager.cpp | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/libraries/Network/src/NetworkManager.cpp b/libraries/Network/src/NetworkManager.cpp index c90136eea60..90e185d5964 100644 --- a/libraries/Network/src/NetworkManager.cpp +++ b/libraries/Network/src/NetworkManager.cpp @@ -88,10 +88,32 @@ int NetworkManager::hostByName(const char* aHostname, IPAddress& aResult) struct addrinfo hints; memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; + // **Workaround** + // LWIP AF_UNSPEC always prefers IPv4 and doesn't check what network is + // available. See https://github.com/espressif/esp-idf/issues/13255 + // Until that is fixed, as a work around if we have a global scope IPv6, + // then we check IPv6 only first. + if (hasGlobalV6) { + hints.ai_family = AF_INET6; + err = lwip_getaddrinfo(aHostname, servname, &hints, &res); + + if (err == ERR_OK) + { + struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)res->ai_addr; + // As an array of u8_t + aResult = IPAddress(IPv6, ipv6->sin6_addr.s6_addr); + log_d("DNS found IPv6 first %s", aResult.toString().c_str()); + lwip_freeaddrinfo(res); + return 1; + } + } + // **End Workaround** + + hints.ai_family = AF_UNSPEC; err = lwip_getaddrinfo(aHostname, servname, &hints, &res); + if (err == ERR_OK) { if (res->ai_family == AF_INET6)