• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
9  *
10  * This software is licensed as described in the file COPYING, which
11  * you should have received as part of this distribution. The terms
12  * are also available at https://curl.se/docs/copyright.html.
13  *
14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15  * copies of the Software, and permit persons to whom the Software is
16  * furnished to do so, under the terms of the COPYING file.
17  *
18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19  * KIND, either express or implied.
20  *
21  * SPDX-License-Identifier: curl
22  *
23  ***************************************************************************/
24 
25 #include "curl_setup.h"
26 
27 #ifdef USE_ARES
28 
29 /***********************************************************************
30  * Only for ares-enabled builds
31  * And only for functions that fulfill the asynch resolver backend API
32  * as defined in asyn.h, nothing else belongs in this file!
33  **********************************************************************/
34 
35 #include <limits.h>
36 #ifdef HAVE_NETINET_IN_H
37 #include <netinet/in.h>
38 #endif
39 #ifdef HAVE_NETDB_H
40 #include <netdb.h>
41 #endif
42 #ifdef HAVE_ARPA_INET_H
43 #include <arpa/inet.h>
44 #endif
45 #ifdef __VMS
46 #include <in.h>
47 #include <inet.h>
48 #endif
49 
50 #include "urldata.h"
51 #include "sendf.h"
52 #include "hostip.h"
53 #include "hash.h"
54 #include "share.h"
55 #include "url.h"
56 #include "multiif.h"
57 #include "inet_pton.h"
58 #include "connect.h"
59 #include "select.h"
60 #include "progress.h"
61 #include "timediff.h"
62 #include "httpsrr.h"
63 #include "strdup.h"
64 
65 #include <ares.h>
66 #include <ares_version.h> /* really old c-ares did not include this by
67                              itself */
68 
69 /*
70  * Curl_ares_getsock() is called when the outside world (using
71  * curl_multi_fdset()) wants to get our fd_set setup and we are talking with
72  * ares. The caller must make sure that this function is only called when we
73  * have a working ares channel.
74  *
75  * Returns: sockets-in-use-bitmap
76  */
77 
Curl_ares_getsock(struct Curl_easy * data,ares_channel channel,curl_socket_t * socks)78 int Curl_ares_getsock(struct Curl_easy *data,
79                       ares_channel channel,
80                       curl_socket_t *socks)
81 {
82   struct timeval maxtime = { CURL_TIMEOUT_RESOLVE, 0 };
83   struct timeval timebuf;
84   int max = ares_getsock(channel,
85                          (ares_socket_t *)socks, MAX_SOCKSPEREASYHANDLE);
86   struct timeval *timeout = ares_timeout(channel, &maxtime, &timebuf);
87   timediff_t milli = curlx_tvtoms(timeout);
88   Curl_expire(data, milli, EXPIRE_ASYNC_NAME);
89   return max;
90 }
91 
92 /*
93  * Curl_ares_perform()
94  *
95  * 1) Ask ares what sockets it currently plays with, then
96  * 2) wait for the timeout period to check for action on ares' sockets.
97  * 3) tell ares to act on all the sockets marked as "with action"
98  *
99  * return number of sockets it worked on, or -1 on error
100  */
101 
Curl_ares_perform(ares_channel channel,timediff_t timeout_ms)102 int Curl_ares_perform(ares_channel channel,
103                       timediff_t timeout_ms)
104 {
105   int nfds;
106   int bitmask;
107   ares_socket_t socks[ARES_GETSOCK_MAXNUM];
108   struct pollfd pfd[ARES_GETSOCK_MAXNUM];
109   int i;
110   int num = 0;
111 
112   bitmask = ares_getsock(channel, socks, ARES_GETSOCK_MAXNUM);
113 
114   for(i = 0; i < ARES_GETSOCK_MAXNUM; i++) {
115     pfd[i].events = 0;
116     pfd[i].revents = 0;
117     if(ARES_GETSOCK_READABLE(bitmask, i)) {
118       pfd[i].fd = socks[i];
119       pfd[i].events |= POLLRDNORM|POLLIN;
120     }
121     if(ARES_GETSOCK_WRITABLE(bitmask, i)) {
122       pfd[i].fd = socks[i];
123       pfd[i].events |= POLLWRNORM|POLLOUT;
124     }
125     if(pfd[i].events)
126       num++;
127     else
128       break;
129   }
130 
131   if(num) {
132     nfds = Curl_poll(pfd, (unsigned int)num, timeout_ms);
133     if(nfds < 0)
134       return -1;
135   }
136   else
137     nfds = 0;
138 
139   if(!nfds)
140     /* Call ares_process() unconditionally here, even if we simply timed out
141        above, as otherwise the ares name resolve will not timeout! */
142     ares_process_fd(channel, ARES_SOCKET_BAD, ARES_SOCKET_BAD);
143   else {
144     /* move through the descriptors and ask for processing on them */
145     for(i = 0; i < num; i++)
146       ares_process_fd(channel,
147                       (pfd[i].revents & (POLLRDNORM|POLLIN)) ?
148                       pfd[i].fd : ARES_SOCKET_BAD,
149                       (pfd[i].revents & (POLLWRNORM|POLLOUT)) ?
150                       pfd[i].fd : ARES_SOCKET_BAD);
151   }
152   return nfds;
153 }
154 
155 #ifdef CURLRES_ARES
156 
157 #if ARES_VERSION >= 0x010500
158 /* c-ares 1.5.0 or later, the callback proto is modified */
159 #define HAVE_CARES_CALLBACK_TIMEOUTS 1
160 #endif
161 
162 #if ARES_VERSION >= 0x010601
163 /* IPv6 supported since 1.6.1 */
164 #define HAVE_CARES_IPV6 1
165 #endif
166 
167 #if ARES_VERSION >= 0x010704
168 #define HAVE_CARES_SERVERS_CSV 1
169 #define HAVE_CARES_LOCAL_DEV 1
170 #define HAVE_CARES_SET_LOCAL 1
171 #endif
172 
173 #if ARES_VERSION >= 0x010b00
174 #define HAVE_CARES_PORTS_CSV 1
175 #endif
176 
177 #if ARES_VERSION >= 0x011000
178 /* 1.16.0 or later has ares_getaddrinfo */
179 #define HAVE_CARES_GETADDRINFO 1
180 #endif
181 
182 #if ARES_VERSION >= 0x011c00
183 /* 1.28.0 and later have ares_query_dnsrec */
184 #define HAVE_ARES_QUERY_DNSREC 1
185 #ifdef USE_HTTPSRR
186 #define USE_HTTPSRR_ARES 1
187 #endif
188 #endif
189 
190 /* The last 3 #include files should be in this order */
191 #include "curl_printf.h"
192 #include "curl_memory.h"
193 #include "memdebug.h"
194 
195 /* How long we are willing to wait for additional parallel responses after
196    obtaining a "definitive" one. For old c-ares without getaddrinfo.
197 
198    This is intended to equal the c-ares default timeout. cURL always uses that
199    default value. Unfortunately, c-ares does not expose its default timeout in
200    its API, but it is officially documented as 5 seconds.
201 
202    See query_completed_cb() for an explanation of how this is used.
203  */
204 #define HAPPY_EYEBALLS_DNS_TIMEOUT 5000
205 
206 #define CARES_TIMEOUT_PER_ATTEMPT 2000
207 
208 static int ares_ver = 0;
209 
210 /*
211  * Curl_resolver_global_init() - the generic low-level asynchronous name
212  * resolve API. Called from curl_global_init() to initialize global resolver
213  * environment. Initializes ares library.
214  */
Curl_resolver_global_init(void)215 int Curl_resolver_global_init(void)
216 {
217 #ifdef CARES_HAVE_ARES_LIBRARY_INIT
218   if(ares_library_init(ARES_LIB_INIT_ALL)) {
219     return CURLE_FAILED_INIT;
220   }
221 #endif
222   ares_version(&ares_ver);
223   return CURLE_OK;
224 }
225 
226 /*
227  * Curl_resolver_global_cleanup()
228  *
229  * Called from curl_global_cleanup() to destroy global resolver environment.
230  * Deinitializes ares library.
231  */
Curl_resolver_global_cleanup(void)232 void Curl_resolver_global_cleanup(void)
233 {
234 #ifdef CARES_HAVE_ARES_LIBRARY_CLEANUP
235   ares_library_cleanup();
236 #endif
237 }
238 
239 
sock_state_cb(void * data,ares_socket_t socket_fd,int readable,int writable)240 static void sock_state_cb(void *data, ares_socket_t socket_fd,
241                           int readable, int writable)
242 {
243   struct Curl_easy *easy = data;
244   if(!readable && !writable) {
245     DEBUGASSERT(easy);
246     Curl_multi_closed(easy, socket_fd);
247   }
248 }
249 
250 /*
251  * Curl_resolver_init()
252  *
253  * Called from curl_easy_init() -> Curl_open() to initialize resolver
254  * URL-state specific environment ('resolver' member of the UrlState
255  * structure). Fills the passed pointer by the initialized ares_channel.
256  */
Curl_resolver_init(struct Curl_easy * easy,void ** resolver)257 CURLcode Curl_resolver_init(struct Curl_easy *easy, void **resolver)
258 {
259   int status;
260   struct ares_options options;
261   int optmask = ARES_OPT_SOCK_STATE_CB;
262   options.sock_state_cb = sock_state_cb;
263   options.sock_state_cb_data = easy;
264 
265   /*
266      if c ares < 1.20.0: curl set timeout to CARES_TIMEOUT_PER_ATTEMPT (2s)
267 
268      if c-ares >= 1.20.0 it already has the timeout to 2s, curl does not need
269      to set the timeout value;
270 
271      if c-ares >= 1.24.0, user can set the timeout via /etc/resolv.conf to
272      overwrite c-ares' timeout.
273   */
274   DEBUGASSERT(ares_ver);
275   if(ares_ver < 0x011400) {
276     options.timeout = CARES_TIMEOUT_PER_ATTEMPT;
277     optmask |= ARES_OPT_TIMEOUTMS;
278   }
279 
280   status = ares_init_options((ares_channel*)resolver, &options, optmask);
281   if(status != ARES_SUCCESS) {
282     if(status == ARES_ENOMEM)
283       return CURLE_OUT_OF_MEMORY;
284     else
285       return CURLE_FAILED_INIT;
286   }
287   return CURLE_OK;
288   /* make sure that all other returns from this function should destroy the
289      ares channel before returning error! */
290 }
291 
292 /*
293  * Curl_resolver_cleanup()
294  *
295  * Called from curl_easy_cleanup() -> Curl_close() to cleanup resolver
296  * URL-state specific environment ('resolver' member of the UrlState
297  * structure). Destroys the ares channel.
298  */
Curl_resolver_cleanup(void * resolver)299 void Curl_resolver_cleanup(void *resolver)
300 {
301   ares_destroy((ares_channel)resolver);
302 }
303 
304 /*
305  * Curl_resolver_duphandle()
306  *
307  * Called from curl_easy_duphandle() to duplicate resolver URL-state specific
308  * environment ('resolver' member of the UrlState structure). Duplicates the
309  * 'from' ares channel and passes the resulting channel to the 'to' pointer.
310  */
Curl_resolver_duphandle(struct Curl_easy * easy,void ** to,void * from)311 CURLcode Curl_resolver_duphandle(struct Curl_easy *easy, void **to, void *from)
312 {
313   (void)from;
314   /*
315    * it would be better to call ares_dup instead, but right now
316    * it is not possible to set 'sock_state_cb_data' outside of
317    * ares_init_options
318    */
319   return Curl_resolver_init(easy, to);
320 }
321 
322 static void destroy_async_data(struct Curl_async *async);
323 
324 /*
325  * Cancel all possibly still on-going resolves for this connection.
326  */
Curl_resolver_cancel(struct Curl_easy * data)327 void Curl_resolver_cancel(struct Curl_easy *data)
328 {
329   DEBUGASSERT(data);
330   if(data->state.async.resolver)
331     ares_cancel((ares_channel)data->state.async.resolver);
332   destroy_async_data(&data->state.async);
333 }
334 
335 /*
336  * We are equivalent to Curl_resolver_cancel() for the c-ares resolver. We
337  * never block.
338  */
Curl_resolver_kill(struct Curl_easy * data)339 void Curl_resolver_kill(struct Curl_easy *data)
340 {
341   /* We do not need to check the resolver state because we can be called safely
342      at any time and we always do the same thing. */
343   Curl_resolver_cancel(data);
344 }
345 
346 /*
347  * destroy_async_data() cleans up async resolver data.
348  */
destroy_async_data(struct Curl_async * async)349 static void destroy_async_data(struct Curl_async *async)
350 {
351   if(async->tdata) {
352     struct thread_data *res = async->tdata;
353     if(res) {
354       if(res->temp_ai) {
355         Curl_freeaddrinfo(res->temp_ai);
356         res->temp_ai = NULL;
357       }
358       free(res);
359     }
360     async->tdata = NULL;
361   }
362 }
363 
364 /*
365  * Curl_resolver_getsock() is called when someone from the outside world
366  * (using curl_multi_fdset()) wants to get our fd_set setup.
367  */
368 
Curl_resolver_getsock(struct Curl_easy * data,curl_socket_t * socks)369 int Curl_resolver_getsock(struct Curl_easy *data, curl_socket_t *socks)
370 {
371   return Curl_ares_getsock(data, (ares_channel)data->state.async.resolver,
372                            socks);
373 }
374 
375 /*
376  * Curl_resolver_is_resolved() is called repeatedly to check if a previous
377  * name resolve request has completed. It should also make sure to time-out if
378  * the operation seems to take too long.
379  *
380  * Returns normal CURLcode errors.
381  */
Curl_resolver_is_resolved(struct Curl_easy * data,struct Curl_dns_entry ** dns)382 CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
383                                    struct Curl_dns_entry **dns)
384 {
385   struct thread_data *res = data->state.async.tdata;
386   CURLcode result = CURLE_OK;
387 
388   DEBUGASSERT(dns);
389   *dns = NULL;
390 
391   if(Curl_ares_perform((ares_channel)data->state.async.resolver, 0) < 0)
392     return CURLE_UNRECOVERABLE_POLL;
393 
394 #ifndef HAVE_CARES_GETADDRINFO
395   /* Now that we have checked for any last minute results above, see if there
396      are any responses still pending when the EXPIRE_HAPPY_EYEBALLS_DNS timer
397      expires. */
398   if(res
399      && res->num_pending
400      /* This is only set to non-zero if the timer was started. */
401      && (res->happy_eyeballs_dns_time.tv_sec
402          || res->happy_eyeballs_dns_time.tv_usec)
403      && (Curl_timediff(Curl_now(), res->happy_eyeballs_dns_time)
404          >= HAPPY_EYEBALLS_DNS_TIMEOUT)) {
405     /* Remember that the EXPIRE_HAPPY_EYEBALLS_DNS timer is no longer
406        running. */
407     memset(
408       &res->happy_eyeballs_dns_time, 0, sizeof(res->happy_eyeballs_dns_time));
409 
410     /* Cancel the raw c-ares request, which will fire query_completed_cb() with
411        ARES_ECANCELLED synchronously for all pending responses. This will
412        leave us with res->num_pending == 0, which is perfect for the next
413        block. */
414     ares_cancel((ares_channel)data->state.async.resolver);
415     DEBUGASSERT(res->num_pending == 0);
416   }
417 #endif
418 
419   if(res && !res->num_pending) {
420     (void)Curl_addrinfo_callback(data, res->last_status, res->temp_ai);
421     /* temp_ai ownership is moved to the connection, so we need not free-up
422        them */
423     res->temp_ai = NULL;
424 
425     if(!data->state.async.dns)
426       result = Curl_resolver_error(data);
427     else {
428       *dns = data->state.async.dns;
429 #ifdef USE_HTTPSRR_ARES
430       {
431         struct Curl_https_rrinfo *lhrr =
432           Curl_memdup(&res->hinfo, sizeof(struct Curl_https_rrinfo));
433         if(!lhrr)
434           result = CURLE_OUT_OF_MEMORY;
435         else
436           (*dns)->hinfo = lhrr;
437       }
438 #endif
439     }
440 
441     destroy_async_data(&data->state.async);
442   }
443 
444   return result;
445 }
446 
447 /*
448  * Curl_resolver_wait_resolv()
449  *
450  * Waits for a resolve to finish. This function should be avoided since using
451  * this risk getting the multi interface to "hang".
452  *
453  * 'entry' MUST be non-NULL.
454  *
455  * Returns CURLE_COULDNT_RESOLVE_HOST if the host was not resolved,
456  * CURLE_OPERATION_TIMEDOUT if a time-out occurred, or other errors.
457  */
Curl_resolver_wait_resolv(struct Curl_easy * data,struct Curl_dns_entry ** entry)458 CURLcode Curl_resolver_wait_resolv(struct Curl_easy *data,
459                                    struct Curl_dns_entry **entry)
460 {
461   CURLcode result = CURLE_OK;
462   timediff_t timeout;
463   struct curltime now = Curl_now();
464 
465   DEBUGASSERT(entry);
466   *entry = NULL; /* clear on entry */
467 
468   timeout = Curl_timeleft(data, &now, TRUE);
469   if(timeout < 0) {
470     /* already expired! */
471     connclose(data->conn, "Timed out before name resolve started");
472     return CURLE_OPERATION_TIMEDOUT;
473   }
474   if(!timeout)
475     timeout = CURL_TIMEOUT_RESOLVE * 1000; /* default name resolve timeout */
476 
477   /* Wait for the name resolve query to complete. */
478   while(!result) {
479     struct timeval *tvp, tv, store;
480     int itimeout;
481     timediff_t timeout_ms;
482 
483 #if TIMEDIFF_T_MAX > INT_MAX
484     itimeout = (timeout > INT_MAX) ? INT_MAX : (int)timeout;
485 #else
486     itimeout = (int)timeout;
487 #endif
488 
489     store.tv_sec = itimeout/1000;
490     store.tv_usec = (itimeout%1000)*1000;
491 
492     tvp = ares_timeout((ares_channel)data->state.async.resolver, &store, &tv);
493 
494     /* use the timeout period ares returned to us above if less than one
495        second is left, otherwise just use 1000ms to make sure the progress
496        callback gets called frequent enough */
497     if(!tvp->tv_sec)
498       timeout_ms = (timediff_t)(tvp->tv_usec/1000);
499     else
500       timeout_ms = 1000;
501 
502     if(Curl_ares_perform((ares_channel)data->state.async.resolver,
503                          timeout_ms) < 0)
504       return CURLE_UNRECOVERABLE_POLL;
505     result = Curl_resolver_is_resolved(data, entry);
506 
507     if(result || data->state.async.done)
508       break;
509 
510     if(Curl_pgrsUpdate(data))
511       result = CURLE_ABORTED_BY_CALLBACK;
512     else {
513       struct curltime now2 = Curl_now();
514       timediff_t timediff = Curl_timediff(now2, now); /* spent time */
515       if(timediff <= 0)
516         timeout -= 1; /* always deduct at least 1 */
517       else if(timediff > timeout)
518         timeout = -1;
519       else
520         timeout -= timediff;
521       now = now2; /* for next loop */
522     }
523     if(timeout < 0)
524       result = CURLE_OPERATION_TIMEDOUT;
525   }
526   if(result)
527     /* failure, so we cancel the ares operation */
528     ares_cancel((ares_channel)data->state.async.resolver);
529 
530   /* Operation complete, if the lookup was successful we now have the entry
531      in the cache. */
532   if(entry)
533     *entry = data->state.async.dns;
534 
535   if(result)
536     /* close the connection, since we cannot return failure here without
537        cleaning up this connection properly. */
538     connclose(data->conn, "c-ares resolve failed");
539 
540   return result;
541 }
542 
543 #ifndef HAVE_CARES_GETADDRINFO
544 
545 /* Connects results to the list */
compound_results(struct thread_data * res,struct Curl_addrinfo * ai)546 static void compound_results(struct thread_data *res,
547                              struct Curl_addrinfo *ai)
548 {
549   if(!ai)
550     return;
551 
552 #ifdef USE_IPV6 /* CURLRES_IPV6 */
553   if(res->temp_ai && res->temp_ai->ai_family == PF_INET6) {
554     /* We have results already, put the new IPv6 entries at the head of the
555        list. */
556     struct Curl_addrinfo *temp_ai_tail = res->temp_ai;
557 
558     while(temp_ai_tail->ai_next)
559       temp_ai_tail = temp_ai_tail->ai_next;
560 
561     temp_ai_tail->ai_next = ai;
562   }
563   else
564 #endif /* CURLRES_IPV6 */
565   {
566     /* Add the new results to the list of old results. */
567     struct Curl_addrinfo *ai_tail = ai;
568     while(ai_tail->ai_next)
569       ai_tail = ai_tail->ai_next;
570 
571     ai_tail->ai_next = res->temp_ai;
572     res->temp_ai = ai;
573   }
574 }
575 
576 /*
577  * ares_query_completed_cb() is the callback that ares will call when
578  * the host query initiated by ares_gethostbyname() from Curl_getaddrinfo(),
579  * when using ares, is completed either successfully or with failure.
580  */
query_completed_cb(void * arg,int status,int timeouts,struct hostent * hostent)581 static void query_completed_cb(void *arg,  /* (struct connectdata *) */
582                                int status,
583 #ifdef HAVE_CARES_CALLBACK_TIMEOUTS
584                                int timeouts,
585 #endif
586                                struct hostent *hostent)
587 {
588   struct Curl_easy *data = (struct Curl_easy *)arg;
589   struct thread_data *res;
590 
591 #ifdef HAVE_CARES_CALLBACK_TIMEOUTS
592   (void)timeouts; /* ignored */
593 #endif
594 
595   if(ARES_EDESTRUCTION == status)
596     /* when this ares handle is getting destroyed, the 'arg' pointer may not
597        be valid so only defer it when we know the 'status' says its fine! */
598     return;
599 
600   res = data->state.async.tdata;
601   if(res) {
602     res->num_pending--;
603 
604     if(CURL_ASYNC_SUCCESS == status) {
605       struct Curl_addrinfo *ai = Curl_he2ai(hostent, data->state.async.port);
606       if(ai) {
607         compound_results(res, ai);
608       }
609     }
610     /* A successful result overwrites any previous error */
611     if(res->last_status != ARES_SUCCESS)
612       res->last_status = status;
613 
614     /* If there are responses still pending, we presume they must be the
615        complementary IPv4 or IPv6 lookups that we started in parallel in
616        Curl_resolver_getaddrinfo() (for Happy Eyeballs). If we have got a
617        "definitive" response from one of a set of parallel queries, we need to
618        think about how long we are willing to wait for more responses. */
619     if(res->num_pending
620        /* Only these c-ares status values count as "definitive" for these
621           purposes. For example, ARES_ENODATA is what we expect when there is
622           no IPv6 entry for a domain name, and that is not a reason to get more
623           aggressive in our timeouts for the other response. Other errors are
624           either a result of bad input (which should affect all parallel
625           requests), local or network conditions, non-definitive server
626           responses, or us cancelling the request. */
627        && (status == ARES_SUCCESS || status == ARES_ENOTFOUND)) {
628       /* Right now, there can only be up to two parallel queries, so do not
629          bother handling any other cases. */
630       DEBUGASSERT(res->num_pending == 1);
631 
632       /* it is possible that one of these parallel queries could succeed
633          quickly, but the other could always fail or timeout (when we are
634          talking to a pool of DNS servers that can only successfully resolve
635          IPv4 address, for example).
636 
637          it is also possible that the other request could always just take
638          longer because it needs more time or only the second DNS server can
639          fulfill it successfully. But, to align with the philosophy of Happy
640          Eyeballs, we do not want to wait _too_ long or users will think
641          requests are slow when IPv6 lookups do not actually work (but IPv4
642          ones do).
643 
644          So, now that we have a usable answer (some IPv4 addresses, some IPv6
645          addresses, or "no such domain"), we start a timeout for the remaining
646          pending responses. Even though it is typical that this resolved
647          request came back quickly, that needn't be the case. It might be that
648          this completing request did not get a result from the first DNS
649          server or even the first round of the whole DNS server pool. So it
650          could already be quite some time after we issued the DNS queries in
651          the first place. Without modifying c-ares, we cannot know exactly
652          where in its retry cycle we are. We could guess based on how much
653          time has gone by, but it does not really matter. Happy Eyeballs tells
654          us that, given usable information in hand, we simply do not want to
655          wait "too much longer" after we get a result.
656 
657          We simply wait an additional amount of time equal to the default
658          c-ares query timeout. That is enough time for a typical parallel
659          response to arrive without being "too long". Even on a network
660          where one of the two types of queries is failing or timing out
661          constantly, this will usually mean we wait a total of the default
662          c-ares timeout (5 seconds) plus the round trip time for the successful
663          request, which seems bearable. The downside is that c-ares might race
664          with us to issue one more retry just before we give up, but it seems
665          better to "waste" that request instead of trying to guess the perfect
666          timeout to prevent it. After all, we do not even know where in the
667          c-ares retry cycle each request is.
668       */
669       res->happy_eyeballs_dns_time = Curl_now();
670       Curl_expire(data, HAPPY_EYEBALLS_DNS_TIMEOUT,
671                   EXPIRE_HAPPY_EYEBALLS_DNS);
672     }
673   }
674 }
675 #else
676 /* c-ares 1.16.0 or later */
677 
678 /*
679  * ares2addr() converts an address list provided by c-ares to an internal
680  * libcurl compatible list
681  */
ares2addr(struct ares_addrinfo_node * node)682 static struct Curl_addrinfo *ares2addr(struct ares_addrinfo_node *node)
683 {
684   /* traverse the ares_addrinfo_node list */
685   struct ares_addrinfo_node *ai;
686   struct Curl_addrinfo *cafirst = NULL;
687   struct Curl_addrinfo *calast = NULL;
688   int error = 0;
689 
690   for(ai = node; ai != NULL; ai = ai->ai_next) {
691     size_t ss_size;
692     struct Curl_addrinfo *ca;
693     /* ignore elements with unsupported address family, */
694     /* settle family-specific sockaddr structure size.  */
695     if(ai->ai_family == AF_INET)
696       ss_size = sizeof(struct sockaddr_in);
697 #ifdef USE_IPV6
698     else if(ai->ai_family == AF_INET6)
699       ss_size = sizeof(struct sockaddr_in6);
700 #endif
701     else
702       continue;
703 
704     /* ignore elements without required address info */
705     if(!ai->ai_addr || !(ai->ai_addrlen > 0))
706       continue;
707 
708     /* ignore elements with bogus address size */
709     if((size_t)ai->ai_addrlen < ss_size)
710       continue;
711 
712     ca = malloc(sizeof(struct Curl_addrinfo) + ss_size);
713     if(!ca) {
714       error = EAI_MEMORY;
715       break;
716     }
717 
718     /* copy each structure member individually, member ordering, */
719     /* size, or padding might be different for each platform.    */
720 
721     ca->ai_flags     = ai->ai_flags;
722     ca->ai_family    = ai->ai_family;
723     ca->ai_socktype  = ai->ai_socktype;
724     ca->ai_protocol  = ai->ai_protocol;
725     ca->ai_addrlen   = (curl_socklen_t)ss_size;
726     ca->ai_addr      = NULL;
727     ca->ai_canonname = NULL;
728     ca->ai_next      = NULL;
729 
730     ca->ai_addr = (void *)((char *)ca + sizeof(struct Curl_addrinfo));
731     memcpy(ca->ai_addr, ai->ai_addr, ss_size);
732 
733     /* if the return list is empty, this becomes the first element */
734     if(!cafirst)
735       cafirst = ca;
736 
737     /* add this element last in the return list */
738     if(calast)
739       calast->ai_next = ca;
740     calast = ca;
741   }
742 
743   /* if we failed, destroy the Curl_addrinfo list */
744   if(error) {
745     Curl_freeaddrinfo(cafirst);
746     cafirst = NULL;
747   }
748 
749   return cafirst;
750 }
751 
addrinfo_cb(void * arg,int status,int timeouts,struct ares_addrinfo * result)752 static void addrinfo_cb(void *arg, int status, int timeouts,
753                         struct ares_addrinfo *result)
754 {
755   struct Curl_easy *data = (struct Curl_easy *)arg;
756   struct thread_data *res = data->state.async.tdata;
757   (void)timeouts;
758   if(ARES_SUCCESS == status) {
759     res->temp_ai = ares2addr(result->nodes);
760     res->last_status = CURL_ASYNC_SUCCESS;
761     ares_freeaddrinfo(result);
762   }
763   res->num_pending--;
764 }
765 
766 #endif
767 
768 /*
769  * Curl_resolver_getaddrinfo() - when using ares
770  *
771  * Returns name information about the given hostname and port number. If
772  * successful, the 'hostent' is returned and the fourth argument will point to
773  * memory we need to free after use. That memory *MUST* be freed with
774  * Curl_freeaddrinfo(), nothing else.
775  */
Curl_resolver_getaddrinfo(struct Curl_easy * data,const char * hostname,int port,int * waitp)776 struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
777                                                 const char *hostname,
778                                                 int port,
779                                                 int *waitp)
780 {
781   struct thread_data *res = NULL;
782   size_t namelen = strlen(hostname);
783   *waitp = 0; /* default to synchronous response */
784 
785   res = calloc(1, sizeof(struct thread_data) + namelen);
786   if(res) {
787     strcpy(res->hostname, hostname);
788     data->state.async.hostname = res->hostname;
789     data->state.async.port = port;
790     data->state.async.done = FALSE;   /* not done */
791     data->state.async.status = 0;     /* clear */
792     data->state.async.dns = NULL;     /* clear */
793     data->state.async.tdata = res;
794 
795     /* initial status - failed */
796     res->last_status = ARES_ENOTFOUND;
797 
798 #ifdef HAVE_CARES_GETADDRINFO
799     {
800       struct ares_addrinfo_hints hints;
801       char service[12];
802       int pf = PF_INET;
803       memset(&hints, 0, sizeof(hints));
804 #ifdef CURLRES_IPV6
805       if((data->conn->ip_version != CURL_IPRESOLVE_V4) &&
806          Curl_ipv6works(data)) {
807         /* The stack seems to be IPv6-enabled */
808         if(data->conn->ip_version == CURL_IPRESOLVE_V6)
809           pf = PF_INET6;
810         else
811           pf = PF_UNSPEC;
812       }
813 #endif /* CURLRES_IPV6 */
814       hints.ai_family = pf;
815       hints.ai_socktype = (data->conn->transport == TRNSPRT_TCP) ?
816         SOCK_STREAM : SOCK_DGRAM;
817       /* Since the service is a numerical one, set the hint flags
818        * accordingly to save a call to getservbyname in inside C-Ares
819        */
820       hints.ai_flags = ARES_AI_NUMERICSERV;
821       msnprintf(service, sizeof(service), "%d", port);
822       res->num_pending = 1;
823       ares_getaddrinfo((ares_channel)data->state.async.resolver, hostname,
824                        service, &hints, addrinfo_cb, data);
825     }
826 #else
827 
828 #ifdef HAVE_CARES_IPV6
829     if((data->conn->ip_version != CURL_IPRESOLVE_V4) && Curl_ipv6works(data)) {
830       /* The stack seems to be IPv6-enabled */
831       res->num_pending = 2;
832 
833       /* areschannel is already setup in the Curl_open() function */
834       ares_gethostbyname((ares_channel)data->state.async.resolver, hostname,
835                           PF_INET, query_completed_cb, data);
836       ares_gethostbyname((ares_channel)data->state.async.resolver, hostname,
837                           PF_INET6, query_completed_cb, data);
838     }
839     else
840 #endif
841     {
842       res->num_pending = 1;
843 
844       /* areschannel is already setup in the Curl_open() function */
845       ares_gethostbyname((ares_channel)data->state.async.resolver,
846                          hostname, PF_INET,
847                          query_completed_cb, data);
848     }
849 #endif
850 #ifdef USE_HTTPSRR_ARES
851     {
852       res->num_pending++; /* one more */
853       memset(&res->hinfo, 0, sizeof(struct Curl_https_rrinfo));
854       ares_query_dnsrec((ares_channel)data->state.async.resolver,
855                         hostname, ARES_CLASS_IN,
856                         ARES_REC_TYPE_HTTPS,
857                         Curl_dnsrec_done_cb, data, NULL);
858     }
859 #endif
860     *waitp = 1; /* expect asynchronous response */
861   }
862   return NULL; /* no struct yet */
863 }
864 
Curl_set_dns_servers(struct Curl_easy * data,char * servers)865 CURLcode Curl_set_dns_servers(struct Curl_easy *data,
866                               char *servers)
867 {
868   CURLcode result = CURLE_NOT_BUILT_IN;
869   int ares_result;
870 
871   /* If server is NULL, this purges all DNS servers from c-ares. Reset it to
872    * default.
873    */
874   if(!servers) {
875     Curl_resolver_cleanup(data->state.async.resolver);
876     result = Curl_resolver_init(data, &data->state.async.resolver);
877     if(!result) {
878       /* this now needs to restore the other options set to c-ares */
879       if(data->set.str[STRING_DNS_INTERFACE])
880         (void)Curl_set_dns_interface(data,
881                                      data->set.str[STRING_DNS_INTERFACE]);
882       if(data->set.str[STRING_DNS_LOCAL_IP4])
883         (void)Curl_set_dns_local_ip4(data,
884                                      data->set.str[STRING_DNS_LOCAL_IP4]);
885       if(data->set.str[STRING_DNS_LOCAL_IP6])
886         (void)Curl_set_dns_local_ip6(data,
887                                      data->set.str[STRING_DNS_LOCAL_IP6]);
888     }
889     return result;
890   }
891 
892 #ifdef HAVE_CARES_SERVERS_CSV
893 #ifdef HAVE_CARES_PORTS_CSV
894   ares_result = ares_set_servers_ports_csv(data->state.async.resolver,
895                                            servers);
896 #else
897   ares_result = ares_set_servers_csv(data->state.async.resolver, servers);
898 #endif
899   switch(ares_result) {
900   case ARES_SUCCESS:
901     result = CURLE_OK;
902     break;
903   case ARES_ENOMEM:
904     result = CURLE_OUT_OF_MEMORY;
905     break;
906   case ARES_ENOTINITIALIZED:
907   case ARES_ENODATA:
908   case ARES_EBADSTR:
909   default:
910     DEBUGF(infof(data, "bad servers set"));
911     result = CURLE_BAD_FUNCTION_ARGUMENT;
912     break;
913   }
914 #else /* too old c-ares version! */
915   (void)data;
916   (void)(ares_result);
917 #endif
918   return result;
919 }
920 
Curl_set_dns_interface(struct Curl_easy * data,const char * interf)921 CURLcode Curl_set_dns_interface(struct Curl_easy *data,
922                                 const char *interf)
923 {
924 #ifdef HAVE_CARES_LOCAL_DEV
925   if(!interf)
926     interf = "";
927 
928   ares_set_local_dev((ares_channel)data->state.async.resolver, interf);
929 
930   return CURLE_OK;
931 #else /* c-ares version too old! */
932   (void)data;
933   (void)interf;
934   return CURLE_NOT_BUILT_IN;
935 #endif
936 }
937 
Curl_set_dns_local_ip4(struct Curl_easy * data,const char * local_ip4)938 CURLcode Curl_set_dns_local_ip4(struct Curl_easy *data,
939                                 const char *local_ip4)
940 {
941 #ifdef HAVE_CARES_SET_LOCAL
942   struct in_addr a4;
943 
944   if((!local_ip4) || (local_ip4[0] == 0)) {
945     a4.s_addr = 0; /* disabled: do not bind to a specific address */
946   }
947   else {
948     if(Curl_inet_pton(AF_INET, local_ip4, &a4) != 1) {
949       DEBUGF(infof(data, "bad DNS IPv4 address"));
950       return CURLE_BAD_FUNCTION_ARGUMENT;
951     }
952   }
953 
954   ares_set_local_ip4((ares_channel)data->state.async.resolver,
955                      ntohl(a4.s_addr));
956 
957   return CURLE_OK;
958 #else /* c-ares version too old! */
959   (void)data;
960   (void)local_ip4;
961   return CURLE_NOT_BUILT_IN;
962 #endif
963 }
964 
Curl_set_dns_local_ip6(struct Curl_easy * data,const char * local_ip6)965 CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data,
966                                 const char *local_ip6)
967 {
968 #if defined(HAVE_CARES_SET_LOCAL) && defined(USE_IPV6)
969   unsigned char a6[INET6_ADDRSTRLEN];
970 
971   if((!local_ip6) || (local_ip6[0] == 0)) {
972     /* disabled: do not bind to a specific address */
973     memset(a6, 0, sizeof(a6));
974   }
975   else {
976     if(Curl_inet_pton(AF_INET6, local_ip6, a6) != 1) {
977       DEBUGF(infof(data, "bad DNS IPv6 address"));
978       return CURLE_BAD_FUNCTION_ARGUMENT;
979     }
980   }
981 
982   ares_set_local_ip6((ares_channel)data->state.async.resolver, a6);
983 
984   return CURLE_OK;
985 #else /* c-ares version too old! */
986   (void)data;
987   (void)local_ip6;
988   return CURLE_NOT_BUILT_IN;
989 #endif
990 }
991 #endif /* CURLRES_ARES */
992 
993 #endif /* USE_ARES */
994