1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
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.haxx.se/docs/copyright.html.
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.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ***************************************************************************/
23 #include "curl_setup.h"
25 /***********************************************************************
26 * Only for ares-enabled builds
27 * And only for functions that fulfill the asynch resolver backend API
28 * as defined in asyn.h, nothing else belongs in this file!
29 **********************************************************************/
34 #ifdef HAVE_NETINET_IN_H
35 #include <netinet/in.h>
40 #ifdef HAVE_ARPA_INET_H
41 #include <arpa/inet.h>
52 #if (defined(NETWARE) && defined(__NOVELL_LIBC__))
54 #define in_addr_t unsigned long
65 #include "inet_pton.h"
70 # if defined(CURL_STATICLIB) && !defined(CARES_STATICLIB) && \
72 # define CARES_STATICLIB
75 # include <ares_version.h> /* really old c-ares didn't include this by
78 #if ARES_VERSION >= 0x010500
79 /* c-ares 1.5.0 or later, the callback proto is modified */
80 #define HAVE_CARES_CALLBACK_TIMEOUTS 1
83 /* The last 3 #include files should be in this order */
84 #include "curl_printf.h"
85 #include "curl_memory.h"
88 struct ResolverResults {
89 int num_pending; /* number of ares_gethostbyname() requests */
90 struct Curl_addrinfo *temp_ai; /* intermediary result while fetching c-ares
93 struct curltime happy_eyeballs_dns_time; /* when this timer started, or 0 */
96 /* How long we are willing to wait for additional parallel responses after
97 obtaining a "definitive" one.
99 This is intended to equal the c-ares default timeout. cURL always uses that
100 default value. Unfortunately, c-ares doesn't expose its default timeout in
101 its API, but it is officially documented as 5 seconds.
103 See query_completed_cb() for an explanation of how this is used.
105 #define HAPPY_EYEBALLS_DNS_TIMEOUT 5000
108 * Curl_resolver_global_init() - the generic low-level asynchronous name
109 * resolve API. Called from curl_global_init() to initialize global resolver
110 * environment. Initializes ares library.
112 int Curl_resolver_global_init(void)
114 #ifdef CARES_HAVE_ARES_LIBRARY_INIT
115 if(ares_library_init(ARES_LIB_INIT_ALL)) {
116 return CURLE_FAILED_INIT;
123 * Curl_resolver_global_cleanup()
125 * Called from curl_global_cleanup() to destroy global resolver environment.
126 * Deinitializes ares library.
128 void Curl_resolver_global_cleanup(void)
130 #ifdef CARES_HAVE_ARES_LIBRARY_CLEANUP
131 ares_library_cleanup();
136 static void Curl_ares_sock_state_cb(void *data, ares_socket_t socket_fd,
137 int readable, int writable)
139 struct Curl_easy *easy = data;
140 if(!readable && !writable) {
142 Curl_multi_closed(easy, socket_fd);
147 * Curl_resolver_init()
149 * Called from curl_easy_init() -> Curl_open() to initialize resolver
150 * URL-state specific environment ('resolver' member of the UrlState
151 * structure). Fills the passed pointer by the initialized ares_channel.
153 CURLcode Curl_resolver_init(struct Curl_easy *easy, void **resolver)
156 struct ares_options options;
157 int optmask = ARES_OPT_SOCK_STATE_CB;
158 options.sock_state_cb = Curl_ares_sock_state_cb;
159 options.sock_state_cb_data = easy;
160 status = ares_init_options((ares_channel*)resolver, &options, optmask);
161 if(status != ARES_SUCCESS) {
162 if(status == ARES_ENOMEM)
163 return CURLE_OUT_OF_MEMORY;
165 return CURLE_FAILED_INIT;
168 /* make sure that all other returns from this function should destroy the
169 ares channel before returning error! */
173 * Curl_resolver_cleanup()
175 * Called from curl_easy_cleanup() -> Curl_close() to cleanup resolver
176 * URL-state specific environment ('resolver' member of the UrlState
177 * structure). Destroys the ares channel.
179 void Curl_resolver_cleanup(void *resolver)
181 ares_destroy((ares_channel)resolver);
185 * Curl_resolver_duphandle()
187 * Called from curl_easy_duphandle() to duplicate resolver URL-state specific
188 * environment ('resolver' member of the UrlState structure). Duplicates the
189 * 'from' ares channel and passes the resulting channel to the 'to' pointer.
191 CURLcode Curl_resolver_duphandle(struct Curl_easy *easy, void **to, void *from)
195 * it would be better to call ares_dup instead, but right now
196 * it is not possible to set 'sock_state_cb_data' outside of
199 return Curl_resolver_init(easy, to);
202 static void destroy_async_data(struct Curl_async *async);
205 * Cancel all possibly still on-going resolves for this connection.
207 void Curl_resolver_cancel(struct connectdata *conn)
209 if(conn->data && conn->data->state.resolver)
210 ares_cancel((ares_channel)conn->data->state.resolver);
211 destroy_async_data(&conn->async);
215 * We're equivalent to Curl_resolver_cancel() for the c-ares resolver. We
218 void Curl_resolver_kill(struct connectdata *conn)
220 /* We don't need to check the resolver state because we can be called safely
221 at any time and we always do the same thing. */
222 Curl_resolver_cancel(conn);
226 * destroy_async_data() cleans up async resolver data.
228 static void destroy_async_data(struct Curl_async *async)
230 free(async->hostname);
232 if(async->os_specific) {
233 struct ResolverResults *res = (struct ResolverResults *)async->os_specific;
236 Curl_freeaddrinfo(res->temp_ai);
241 async->os_specific = NULL;
244 async->hostname = NULL;
248 * Curl_resolver_getsock() is called when someone from the outside world
249 * (using curl_multi_fdset()) wants to get our fd_set setup and we're talking
250 * with ares. The caller must make sure that this function is only called when
251 * we have a working ares channel.
253 * Returns: sockets-in-use-bitmap
256 int Curl_resolver_getsock(struct connectdata *conn,
257 curl_socket_t *socks)
259 struct timeval maxtime;
260 struct timeval timebuf;
261 struct timeval *timeout;
263 int max = ares_getsock((ares_channel)conn->data->state.resolver,
264 (ares_socket_t *)socks, MAX_SOCKSPEREASYHANDLE);
266 maxtime.tv_sec = CURL_TIMEOUT_RESOLVE;
269 timeout = ares_timeout((ares_channel)conn->data->state.resolver, &maxtime,
271 milli = (timeout->tv_sec * 1000) + (timeout->tv_usec/1000);
274 Curl_expire(conn->data, milli, EXPIRE_ASYNC_NAME);
282 * 1) Ask ares what sockets it currently plays with, then
283 * 2) wait for the timeout period to check for action on ares' sockets.
284 * 3) tell ares to act on all the sockets marked as "with action"
286 * return number of sockets it worked on
289 static int waitperform(struct connectdata *conn, timediff_t timeout_ms)
291 struct Curl_easy *data = conn->data;
294 ares_socket_t socks[ARES_GETSOCK_MAXNUM];
295 struct pollfd pfd[ARES_GETSOCK_MAXNUM];
299 bitmask = ares_getsock((ares_channel)data->state.resolver, socks,
300 ARES_GETSOCK_MAXNUM);
302 for(i = 0; i < ARES_GETSOCK_MAXNUM; i++) {
305 if(ARES_GETSOCK_READABLE(bitmask, i)) {
306 pfd[i].fd = socks[i];
307 pfd[i].events |= POLLRDNORM|POLLIN;
309 if(ARES_GETSOCK_WRITABLE(bitmask, i)) {
310 pfd[i].fd = socks[i];
311 pfd[i].events |= POLLWRNORM|POLLOUT;
313 if(pfd[i].events != 0)
320 nfds = Curl_poll(pfd, num, timeout_ms);
325 /* Call ares_process() unconditonally here, even if we simply timed out
326 above, as otherwise the ares name resolve won't timeout! */
327 ares_process_fd((ares_channel)data->state.resolver, ARES_SOCKET_BAD,
330 /* move through the descriptors and ask for processing on them */
331 for(i = 0; i < num; i++)
332 ares_process_fd((ares_channel)data->state.resolver,
333 (pfd[i].revents & (POLLRDNORM|POLLIN))?
334 pfd[i].fd:ARES_SOCKET_BAD,
335 (pfd[i].revents & (POLLWRNORM|POLLOUT))?
336 pfd[i].fd:ARES_SOCKET_BAD);
342 * Curl_resolver_is_resolved() is called repeatedly to check if a previous
343 * name resolve request has completed. It should also make sure to time-out if
344 * the operation seems to take too long.
346 * Returns normal CURLcode errors.
348 CURLcode Curl_resolver_is_resolved(struct connectdata *conn,
349 struct Curl_dns_entry **dns)
351 struct Curl_easy *data = conn->data;
352 struct ResolverResults *res = (struct ResolverResults *)
353 conn->async.os_specific;
354 CURLcode result = CURLE_OK;
359 waitperform(conn, 0);
361 /* Now that we've checked for any last minute results above, see if there are
362 any responses still pending when the EXPIRE_HAPPY_EYEBALLS_DNS timer
366 /* This is only set to non-zero if the timer was started. */
367 && (res->happy_eyeballs_dns_time.tv_sec
368 || res->happy_eyeballs_dns_time.tv_usec)
369 && (Curl_timediff(Curl_now(), res->happy_eyeballs_dns_time)
370 >= HAPPY_EYEBALLS_DNS_TIMEOUT)) {
371 /* Remember that the EXPIRE_HAPPY_EYEBALLS_DNS timer is no longer
374 &res->happy_eyeballs_dns_time, 0, sizeof(res->happy_eyeballs_dns_time));
376 /* Cancel the raw c-ares request, which will fire query_completed_cb() with
377 ARES_ECANCELLED synchronously for all pending responses. This will
378 leave us with res->num_pending == 0, which is perfect for the next
380 ares_cancel((ares_channel)data->state.resolver);
381 DEBUGASSERT(res->num_pending == 0);
384 if(res && !res->num_pending) {
385 (void)Curl_addrinfo_callback(conn, res->last_status, res->temp_ai);
386 /* temp_ai ownership is moved to the connection, so we need not free-up
390 if(!conn->async.dns) {
391 failf(data, "Could not resolve: %s (%s)",
392 conn->async.hostname, ares_strerror(conn->async.status));
393 result = conn->bits.proxy?CURLE_COULDNT_RESOLVE_PROXY:
394 CURLE_COULDNT_RESOLVE_HOST;
397 *dns = conn->async.dns;
399 destroy_async_data(&conn->async);
406 * Curl_resolver_wait_resolv()
408 * Waits for a resolve to finish. This function should be avoided since using
409 * this risk getting the multi interface to "hang".
411 * 'entry' MUST be non-NULL.
413 * Returns CURLE_COULDNT_RESOLVE_HOST if the host was not resolved,
414 * CURLE_OPERATION_TIMEDOUT if a time-out occurred, or other errors.
416 CURLcode Curl_resolver_wait_resolv(struct connectdata *conn,
417 struct Curl_dns_entry **entry)
419 CURLcode result = CURLE_OK;
420 struct Curl_easy *data = conn->data;
422 struct curltime now = Curl_now();
425 *entry = NULL; /* clear on entry */
427 timeout = Curl_timeleft(data, &now, TRUE);
429 /* already expired! */
430 connclose(conn, "Timed out before name resolve started");
431 return CURLE_OPERATION_TIMEDOUT;
434 timeout = CURL_TIMEOUT_RESOLVE * 1000; /* default name resolve timeout */
436 /* Wait for the name resolve query to complete. */
438 struct timeval *tvp, tv, store;
440 timediff_t timeout_ms;
442 #if TIMEDIFF_T_MAX > INT_MAX
443 itimeout = (timeout > INT_MAX) ? INT_MAX : (int)timeout;
445 itimeout = (int)timeout;
448 store.tv_sec = itimeout/1000;
449 store.tv_usec = (itimeout%1000)*1000;
451 tvp = ares_timeout((ares_channel)data->state.resolver, &store, &tv);
453 /* use the timeout period ares returned to us above if less than one
454 second is left, otherwise just use 1000ms to make sure the progress
455 callback gets called frequent enough */
457 timeout_ms = (timediff_t)(tvp->tv_usec/1000);
461 waitperform(conn, timeout_ms);
462 result = Curl_resolver_is_resolved(conn, entry);
464 if(result || conn->async.done)
467 if(Curl_pgrsUpdate(conn))
468 result = CURLE_ABORTED_BY_CALLBACK;
470 struct curltime now2 = Curl_now();
471 timediff_t timediff = Curl_timediff(now2, now); /* spent time */
473 timeout -= 1; /* always deduct at least 1 */
474 else if(timediff > timeout)
478 now = now2; /* for next loop */
481 result = CURLE_OPERATION_TIMEDOUT;
484 /* failure, so we cancel the ares operation */
485 ares_cancel((ares_channel)data->state.resolver);
487 /* Operation complete, if the lookup was successful we now have the entry
490 *entry = conn->async.dns;
493 /* close the connection, since we can't return failure here without
494 cleaning up this connection properly. */
495 connclose(conn, "c-ares resolve failed");
500 /* Connects results to the list */
501 static void compound_results(struct ResolverResults *res,
502 struct Curl_addrinfo *ai)
504 struct Curl_addrinfo *ai_tail;
509 while(ai_tail->ai_next)
510 ai_tail = ai_tail->ai_next;
512 /* Add the new results to the list of old results. */
513 ai_tail->ai_next = res->temp_ai;
518 * ares_query_completed_cb() is the callback that ares will call when
519 * the host query initiated by ares_gethostbyname() from Curl_getaddrinfo(),
520 * when using ares, is completed either successfully or with failure.
522 static void query_completed_cb(void *arg, /* (struct connectdata *) */
524 #ifdef HAVE_CARES_CALLBACK_TIMEOUTS
527 struct hostent *hostent)
529 struct connectdata *conn = (struct connectdata *)arg;
530 struct ResolverResults *res;
532 #ifdef HAVE_CARES_CALLBACK_TIMEOUTS
533 (void)timeouts; /* ignored */
536 if(ARES_EDESTRUCTION == status)
537 /* when this ares handle is getting destroyed, the 'arg' pointer may not
538 be valid so only defer it when we know the 'status' says its fine! */
541 res = (struct ResolverResults *)conn->async.os_specific;
545 if(CURL_ASYNC_SUCCESS == status) {
546 struct Curl_addrinfo *ai = Curl_he2ai(hostent, conn->async.port);
548 compound_results(res, ai);
551 /* A successful result overwrites any previous error */
552 if(res->last_status != ARES_SUCCESS)
553 res->last_status = status;
555 /* If there are responses still pending, we presume they must be the
556 complementary IPv4 or IPv6 lookups that we started in parallel in
557 Curl_resolver_getaddrinfo() (for Happy Eyeballs). If we've got a
558 "definitive" response from one of a set of parallel queries, we need to
559 think about how long we're willing to wait for more responses. */
561 /* Only these c-ares status values count as "definitive" for these
562 purposes. For example, ARES_ENODATA is what we expect when there is
563 no IPv6 entry for a domain name, and that's not a reason to get more
564 aggressive in our timeouts for the other response. Other errors are
565 either a result of bad input (which should affect all parallel
566 requests), local or network conditions, non-definitive server
567 responses, or us cancelling the request. */
568 && (status == ARES_SUCCESS || status == ARES_ENOTFOUND)) {
569 /* Right now, there can only be up to two parallel queries, so don't
570 bother handling any other cases. */
571 DEBUGASSERT(res->num_pending == 1);
573 /* It's possible that one of these parallel queries could succeed
574 quickly, but the other could always fail or timeout (when we're
575 talking to a pool of DNS servers that can only successfully resolve
576 IPv4 address, for example).
578 It's also possible that the other request could always just take
579 longer because it needs more time or only the second DNS server can
580 fulfill it successfully. But, to align with the philosophy of Happy
581 Eyeballs, we don't want to wait _too_ long or users will think
582 requests are slow when IPv6 lookups don't actually work (but IPv4 ones
585 So, now that we have a usable answer (some IPv4 addresses, some IPv6
586 addresses, or "no such domain"), we start a timeout for the remaining
587 pending responses. Even though it is typical that this resolved
588 request came back quickly, that needn't be the case. It might be that
589 this completing request didn't get a result from the first DNS server
590 or even the first round of the whole DNS server pool. So it could
591 already be quite some time after we issued the DNS queries in the
592 first place. Without modifying c-ares, we can't know exactly where in
593 its retry cycle we are. We could guess based on how much time has
594 gone by, but it doesn't really matter. Happy Eyeballs tells us that,
595 given usable information in hand, we simply don't want to wait "too
596 much longer" after we get a result.
598 We simply wait an additional amount of time equal to the default
599 c-ares query timeout. That is enough time for a typical parallel
600 response to arrive without being "too long". Even on a network
601 where one of the two types of queries is failing or timing out
602 constantly, this will usually mean we wait a total of the default
603 c-ares timeout (5 seconds) plus the round trip time for the successful
604 request, which seems bearable. The downside is that c-ares might race
605 with us to issue one more retry just before we give up, but it seems
606 better to "waste" that request instead of trying to guess the perfect
607 timeout to prevent it. After all, we don't even know where in the
608 c-ares retry cycle each request is.
610 res->happy_eyeballs_dns_time = Curl_now();
612 conn->data, HAPPY_EYEBALLS_DNS_TIMEOUT, EXPIRE_HAPPY_EYEBALLS_DNS);
618 * Curl_resolver_getaddrinfo() - when using ares
620 * Returns name information about the given hostname and port number. If
621 * successful, the 'hostent' is returned and the forth argument will point to
622 * memory we need to free after use. That memory *MUST* be freed with
623 * Curl_freeaddrinfo(), nothing else.
625 struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
626 const char *hostname,
631 struct Curl_easy *data = conn->data;
632 int family = PF_INET;
634 *waitp = 0; /* default to synchronous response */
637 switch(conn->ip_version) {
639 #if ARES_VERSION >= 0x010601
640 family = PF_UNSPEC; /* supported by c-ares since 1.6.1, so for older
641 c-ares versions this just falls through and defaults
645 case CURL_IPRESOLVE_V4:
648 case CURL_IPRESOLVE_V6:
652 #endif /* ENABLE_IPV6 */
654 bufp = strdup(hostname);
656 struct ResolverResults *res = NULL;
657 free(conn->async.hostname);
658 conn->async.hostname = bufp;
659 conn->async.port = port;
660 conn->async.done = FALSE; /* not done */
661 conn->async.status = 0; /* clear */
662 conn->async.dns = NULL; /* clear */
663 res = calloc(sizeof(struct ResolverResults), 1);
665 free(conn->async.hostname);
666 conn->async.hostname = NULL;
669 conn->async.os_specific = res;
671 /* initial status - failed */
672 res->last_status = ARES_ENOTFOUND;
674 if(family == PF_UNSPEC) {
675 if(Curl_ipv6works(conn)) {
676 res->num_pending = 2;
678 /* areschannel is already setup in the Curl_open() function */
679 ares_gethostbyname((ares_channel)data->state.resolver, hostname,
680 PF_INET, query_completed_cb, conn);
681 ares_gethostbyname((ares_channel)data->state.resolver, hostname,
682 PF_INET6, query_completed_cb, conn);
685 res->num_pending = 1;
687 /* areschannel is already setup in the Curl_open() function */
688 ares_gethostbyname((ares_channel)data->state.resolver, hostname,
689 PF_INET, query_completed_cb, conn);
693 #endif /* ENABLE_IPV6 */
695 res->num_pending = 1;
697 /* areschannel is already setup in the Curl_open() function */
698 ares_gethostbyname((ares_channel)data->state.resolver, hostname, family,
699 query_completed_cb, conn);
702 *waitp = 1; /* expect asynchronous response */
704 return NULL; /* no struct yet */
707 CURLcode Curl_set_dns_servers(struct Curl_easy *data,
710 CURLcode result = CURLE_NOT_BUILT_IN;
713 /* If server is NULL or empty, this would purge all DNS servers
714 * from ares library, which will cause any and all queries to fail.
715 * So, just return OK if none are configured and don't actually make
716 * any changes to c-ares. This lets c-ares use it's defaults, which
717 * it gets from the OS (for instance from /etc/resolv.conf on Linux).
719 if(!(servers && servers[0]))
722 #if (ARES_VERSION >= 0x010704)
723 #if (ARES_VERSION >= 0x010b00)
724 ares_result = ares_set_servers_ports_csv(data->state.resolver, servers);
726 ares_result = ares_set_servers_csv(data->state.resolver, servers);
728 switch(ares_result) {
733 result = CURLE_OUT_OF_MEMORY;
735 case ARES_ENOTINITIALIZED:
739 result = CURLE_BAD_FUNCTION_ARGUMENT;
742 #else /* too old c-ares version! */
749 CURLcode Curl_set_dns_interface(struct Curl_easy *data,
752 #if (ARES_VERSION >= 0x010704)
756 ares_set_local_dev((ares_channel)data->state.resolver, interf);
759 #else /* c-ares version too old! */
762 return CURLE_NOT_BUILT_IN;
766 CURLcode Curl_set_dns_local_ip4(struct Curl_easy *data,
767 const char *local_ip4)
769 #if (ARES_VERSION >= 0x010704)
772 if((!local_ip4) || (local_ip4[0] == 0)) {
773 a4.s_addr = 0; /* disabled: do not bind to a specific address */
776 if(Curl_inet_pton(AF_INET, local_ip4, &a4) != 1) {
777 return CURLE_BAD_FUNCTION_ARGUMENT;
781 ares_set_local_ip4((ares_channel)data->state.resolver, ntohl(a4.s_addr));
784 #else /* c-ares version too old! */
787 return CURLE_NOT_BUILT_IN;
791 CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data,
792 const char *local_ip6)
794 #if (ARES_VERSION >= 0x010704) && defined(ENABLE_IPV6)
795 unsigned char a6[INET6_ADDRSTRLEN];
797 if((!local_ip6) || (local_ip6[0] == 0)) {
798 /* disabled: do not bind to a specific address */
799 memset(a6, 0, sizeof(a6));
802 if(Curl_inet_pton(AF_INET6, local_ip6, a6) != 1) {
803 return CURLE_BAD_FUNCTION_ARGUMENT;
807 ares_set_local_ip6((ares_channel)data->state.resolver, a6);
810 #else /* c-ares version too old! */
813 return CURLE_NOT_BUILT_IN;
816 #endif /* CURLRES_ARES */