@@ -47,55 +47,90 @@ int NetworkManager::hostByName(const char* aHostname, IPAddress& aResult, bool p
4747{
4848 // IDEA: Rename to getAddressInfo() ?
4949
50- err_t err = ERR_OK;
51-
52- // This should generally check if we have a global address assigned to one of the interfaces.
53- // 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.
54- // That is of course, if 'preferV6' is not set to true
50+ err_t err = -1 ;
51+ const char *servname = " 0" ;
52+ struct addrinfo *res;
5553 static bool hasGlobalV6 = false ;
56- bool hasGlobalV6Now = false ;// ToDo: implement this!
54+
55+ aResult = static_cast <uint32_t >(0 );
56+
57+ // First check if the host parses as a literal address
58+ if (aResult.fromString (aHostname)) {
59+ return 1 ;
60+ }
61+
62+ // **Workaround**
63+ // LWIP AF_UNSPEC always prefers IPv4 and doesn't check what network is
64+ // available. See https://github.com/espressif/esp-idf/issues/13255
65+ // Until that is fixed, as a work around if we have a global scope IPv6,
66+ // then we check IPv6 only first.
67+
68+ // Iterate over active interfaces, and find if we have any global scope IPv6
69+ bool hasGlobalV6Now = false ;
70+ esp_netif_t *netif = NULL ;
71+ while ((netif = esp_netif_next_unsafe (netif)) != NULL ) {
72+ esp_ip6_addr_t ip6[CONFIG_LWIP_IPV6_NUM_ADDRESSES];
73+ int ip6_addrs = esp_netif_get_all_ip6 (netif, ip6);
74+ for (int j = 0 ; j < ip6_addrs; ++j) {
75+ // Both global and unique local addresses have global scope.
76+ // ULA assumes either private DNS or NAT66 (same assumption as IPv4 private address ranges).
77+ esp_ip6_addr_type_t ipv6_type = esp_netif_ip6_get_addr_type (&(ip6[j]));
78+ if (ipv6_type == ESP_IP6_ADDR_IS_GLOBAL || ipv6_type == ESP_IP6_ADDR_IS_UNIQUE_LOCAL) {
79+ hasGlobalV6Now = true ;
80+ break ;
81+ }
82+ }
83+ if (hasGlobalV6Now) break ;
84+ }
85+
86+ // Clear DNS cache if the flag has changed
5787 if (hasGlobalV6 != hasGlobalV6Now){
5888 hasGlobalV6 = hasGlobalV6Now;
5989 dns_clear_cache ();
6090 log_d (" Clearing DNS cache" );
6191 }
6292
63- aResult = static_cast <uint32_t >(0 );
64-
65- // First check if the host parses as a literal address
66- if (!aResult.fromString (aHostname)) {
67- const char *servname = " 0" ;
68- struct addrinfo *res;
69- const struct addrinfo hints = {
70- .ai_family = AF_UNSPEC,
93+ if (hasGlobalV6) {
94+ const struct addrinfo hints6 = {
95+ .ai_family = AF_INET6,
7196 .ai_socktype = SOCK_STREAM,
7297 };
73- err = lwip_getaddrinfo (aHostname, servname, &hints, &res);
74- if (err == 0 )
75- {
76- if (res->ai_family == AF_INET6)
77- {
78- struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)res->ai_addr ;
79- // As an array of u8_t
80- aResult = IPAddress (IPv6, ipv6->sin6_addr .s6_addr );
81- log_d (" DNS found IPv6 %s" , aResult.toString ().c_str ());
82- }
83- else if (res->ai_family == AF_INET)
84- {
85- struct sockaddr_in *ipv4 = (struct sockaddr_in *)res->ai_addr ;
86- // As a single u32_t
87- aResult = IPAddress (ipv4->sin_addr .s_addr );
88- log_d (" DNS found IPv4 %s" , aResult.toString ().c_str ());
89- }
90- else
91- {
92- err = -1 ;
93- }
98+ err = lwip_getaddrinfo (aHostname, servname, &hints6, &res);
9499
100+ if (err == ERR_OK)
101+ {
102+ struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)res->ai_addr ;
103+ // As an array of u8_t
104+ aResult = IPAddress (IPv6, ipv6->sin6_addr .s6_addr );
105+ log_d (" DNS found first IPv6 %s" , aResult.toString ().c_str ());
95106 lwip_freeaddrinfo (res);
107+ return 1 ;
96108 }
97109 }
98- if (err == ERR_OK) {
110+ // **End Workaround**
111+
112+ const struct addrinfo hints = {
113+ .ai_family = AF_UNSPEC,
114+ .ai_socktype = SOCK_STREAM,
115+ };
116+ err = lwip_getaddrinfo (aHostname, servname, &hints, &res);
117+ if (err == ERR_OK)
118+ {
119+ if (res->ai_family == AF_INET6)
120+ {
121+ struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)res->ai_addr ;
122+ // As an array of u8_t
123+ aResult = IPAddress (IPv6, ipv6->sin6_addr .s6_addr );
124+ log_d (" DNS found any IPv6 %s" , aResult.toString ().c_str ());
125+ }
126+ else
127+ {
128+ struct sockaddr_in *ipv4 = (struct sockaddr_in *)res->ai_addr ;
129+ // As a single u32_t
130+ aResult = IPAddress (ipv4->sin_addr .s_addr );
131+ log_d (" DNS found any IPv4 %s" , aResult.toString ().c_str ());
132+ }
133+ lwip_freeaddrinfo (res);
99134 return 1 ;
100135 }
101136 log_e (" DNS Failed for '%s' with error '%d'" , aHostname, err);
0 commit comments