]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
ares: always store IPv6 addresses first
authorDmitry Karpov <dkarpov@roku.com>
Thu, 3 Jun 2021 21:56:37 +0000 (23:56 +0200)
committerDaniel Stenberg <daniel@haxx.se>
Sat, 5 Jun 2021 21:41:21 +0000 (23:41 +0200)
Trying dual-stack on some embedded platform, I noticed that quite
frequently (20%) libCurl starts from IPv4 regardless the Happy Eyeballs
timeout value.  After debugging this issue, I noticed that this happens
if c-ares resolver response for IPv6 family comes before IPv4 (which was
randomly happening in my tests).

In such cases, because libCurl puts the last resolver response on top of
the address list, when IPv4 resolver response comes after IPv6 one - the
IPv4 family starts the connection phase instead of IPv6 family.

The solution for this issue is to always put IPv6 addresses on top of
the address list, regardless the order of resolver responses.

Bug: https://curl.se/mail/lib-2021-06/0003.html

Closes #7188

lib/asyn-ares.c

index 7827847350cd25c3ada5b35b90dcd021a6e90b90..9ee307beb027c0c43ac4a8fbaf89e035233efdbf 100644 (file)
@@ -493,17 +493,31 @@ CURLcode Curl_resolver_wait_resolv(struct Curl_easy *data,
 static void compound_results(struct thread_data *res,
                              struct Curl_addrinfo *ai)
 {
-  struct Curl_addrinfo *ai_tail;
   if(!ai)
     return;
-  ai_tail = ai;
 
-  while(ai_tail->ai_next)
-    ai_tail = ai_tail->ai_next;
+#ifdef ENABLE_IPV6 /* CURLRES_IPV6 */
+  if(res->temp_ai && res->temp_ai->ai_family == PF_INET6) {
+    /* We have results already, put the new IPv6 entries at the head of the
+       list. */
+    struct Curl_addrinfo *temp_ai_tail = res->temp_ai;
 
-  /* Add the new results to the list of old results. */
-  ai_tail->ai_next = res->temp_ai;
-  res->temp_ai = ai;
+    while(temp_ai_tail->ai_next)
+      temp_ai_tail = temp_ai_tail->ai_next;
+
+    temp_ai_tail->ai_next = ai;
+  }
+  else
+#endif /* CURLRES_IPV6 */
+  {
+    /* Add the new results to the list of old results. */
+    struct Curl_addrinfo *ai_tail = ai;
+    while(ai_tail->ai_next)
+      ai_tail = ai_tail->ai_next;
+
+    ai_tail->ai_next = res->temp_ai;
+    res->temp_ai = ai;
+  }
 }
 
 /*