Skip to content

Commit c4f5437

Browse files
committed
fix(dns): Fix IPv6-only network, by IPv6 preference if you have public address
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.
1 parent 5634137 commit c4f5437

File tree

1 file changed

+46
-13
lines changed

1 file changed

+46
-13
lines changed

libraries/Network/src/NetworkManager.cpp

+46-13
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ NetworkManager::NetworkManager(){
1515

1616
}
1717

18+
NetworkInterface * getNetifByID(Network_Interface_ID id);
19+
1820
bool NetworkManager::begin(){
1921
static bool initialized = false;
2022
if(!initialized){
@@ -45,28 +47,62 @@ bool NetworkManager::begin(){
4547
*/
4648
int NetworkManager::hostByName(const char* aHostname, IPAddress& aResult)
4749
{
50+
static bool hasGlobalV6 = false;
4851
err_t err = ERR_OK;
52+
const char *servname = "0";
53+
struct addrinfo *res;
54+
aResult = static_cast<uint32_t>(0);
4955

50-
// This should generally check if we have a global address assigned to one of the interfaces.
51-
// If such address is not assigned, there is no point in trying to get V6 from DNS as we will not be able to reach it.
52-
// That is of course, if 'preferV6' is not set to true
53-
static bool hasGlobalV6 = false;
56+
// First check if the host parses as a literal address
57+
if (aResult.fromString(aHostname)) {
58+
return 1;
59+
}
60+
61+
// **Workaround**
62+
// LWIP AF_UNSPEC always prefers IPv4 and doesn't check what network is
63+
// available. See https://github.com/espressif/esp-idf/issues/13255
64+
// Until that is fixed, as a work around if we have a global scope IPv6,
65+
// then we check IPv6 only first.
66+
67+
// This checks if we have a global address assigned to one of the interfaces.
68+
// If such address is assigned, then we trying to get V6 from DNS first.
5469
bool hasGlobalV6Now = false;//ToDo: implement this!
70+
for (int i = 0; i < ESP_NETIF_ID_MAX; ++i){
71+
NetworkInterface * iface = getNetifByID((Network_Interface_ID)i);
72+
if(iface != NULL && iface->hasGlobalIPv6()){
73+
hasGlobalV6Now = true;
74+
}
75+
if (hasGlobalV6Now){
76+
break;
77+
}
78+
}
79+
80+
// Clear DNS cache if the flag has changed
5581
if(hasGlobalV6 != hasGlobalV6Now){
5682
hasGlobalV6 = hasGlobalV6Now;
5783
dns_clear_cache();
5884
log_d("Clearing DNS cache");
5985
}
6086

61-
aResult = static_cast<uint32_t>(0);
87+
if (hasGlobalV6) {
88+
const struct addrinfo hints6 = {
89+
.ai_family = AF_INET6,
90+
.ai_socktype = SOCK_STREAM,
91+
};
92+
err = lwip_getaddrinfo(aHostname, servname, &hints6, &res);
6293

63-
// First check if the host parses as a literal address
64-
if (aResult.fromString(aHostname)) {
65-
return 1;
94+
if (err == ERR_OK)
95+
{
96+
struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)res->ai_addr;
97+
// As an array of u8_t
98+
aResult = IPAddress(IPv6, ipv6->sin6_addr.s6_addr);
99+
log_d("DNS found first IPv6 %s", aResult.toString().c_str());
100+
lwip_freeaddrinfo(res);
101+
return 1;
102+
}
66103
}
104+
// **End Workaround**
67105

68-
const char *servname = "0";
69-
struct addrinfo *res;
70106
const struct addrinfo hints = {
71107
.ai_family = AF_UNSPEC,
72108
.ai_socktype = SOCK_STREAM,
@@ -130,8 +166,6 @@ bool NetworkManager::setHostname(const char * name)
130166
return true;
131167
}
132168

133-
NetworkInterface * getNetifByID(Network_Interface_ID id);
134-
135169
size_t NetworkManager::printTo(Print & out) const {
136170
size_t bytes = 0;
137171

@@ -144,5 +178,4 @@ size_t NetworkManager::printTo(Print & out) const {
144178
return bytes;
145179
}
146180

147-
148181
NetworkManager Network;

0 commit comments

Comments
 (0)