113498266Sopenharmony_ci/*************************************************************************** 213498266Sopenharmony_ci * _ _ ____ _ 313498266Sopenharmony_ci * Project ___| | | | _ \| | 413498266Sopenharmony_ci * / __| | | | |_) | | 513498266Sopenharmony_ci * | (__| |_| | _ <| |___ 613498266Sopenharmony_ci * \___|\___/|_| \_\_____| 713498266Sopenharmony_ci * 813498266Sopenharmony_ci * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. 913498266Sopenharmony_ci * 1013498266Sopenharmony_ci * This software is licensed as described in the file COPYING, which 1113498266Sopenharmony_ci * you should have received as part of this distribution. The terms 1213498266Sopenharmony_ci * are also available at https://curl.se/docs/copyright.html. 1313498266Sopenharmony_ci * 1413498266Sopenharmony_ci * You may opt to use, copy, modify, merge, publish, distribute and/or sell 1513498266Sopenharmony_ci * copies of the Software, and permit persons to whom the Software is 1613498266Sopenharmony_ci * furnished to do so, under the terms of the COPYING file. 1713498266Sopenharmony_ci * 1813498266Sopenharmony_ci * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 1913498266Sopenharmony_ci * KIND, either express or implied. 2013498266Sopenharmony_ci * 2113498266Sopenharmony_ci * SPDX-License-Identifier: curl 2213498266Sopenharmony_ci * 2313498266Sopenharmony_ci ***************************************************************************/ 2413498266Sopenharmony_ci 2513498266Sopenharmony_ci#include "curl_setup.h" 2613498266Sopenharmony_ci 2713498266Sopenharmony_ci/*********************************************************************** 2813498266Sopenharmony_ci * Only for ares-enabled builds 2913498266Sopenharmony_ci * And only for functions that fulfill the asynch resolver backend API 3013498266Sopenharmony_ci * as defined in asyn.h, nothing else belongs in this file! 3113498266Sopenharmony_ci **********************************************************************/ 3213498266Sopenharmony_ci 3313498266Sopenharmony_ci#ifdef CURLRES_ARES 3413498266Sopenharmony_ci 3513498266Sopenharmony_ci#include <limits.h> 3613498266Sopenharmony_ci#ifdef HAVE_NETINET_IN_H 3713498266Sopenharmony_ci#include <netinet/in.h> 3813498266Sopenharmony_ci#endif 3913498266Sopenharmony_ci#ifdef HAVE_NETDB_H 4013498266Sopenharmony_ci#include <netdb.h> 4113498266Sopenharmony_ci#endif 4213498266Sopenharmony_ci#ifdef HAVE_ARPA_INET_H 4313498266Sopenharmony_ci#include <arpa/inet.h> 4413498266Sopenharmony_ci#endif 4513498266Sopenharmony_ci#ifdef __VMS 4613498266Sopenharmony_ci#include <in.h> 4713498266Sopenharmony_ci#include <inet.h> 4813498266Sopenharmony_ci#endif 4913498266Sopenharmony_ci 5013498266Sopenharmony_ci#include "urldata.h" 5113498266Sopenharmony_ci#include "sendf.h" 5213498266Sopenharmony_ci#include "hostip.h" 5313498266Sopenharmony_ci#include "hash.h" 5413498266Sopenharmony_ci#include "share.h" 5513498266Sopenharmony_ci#include "url.h" 5613498266Sopenharmony_ci#include "multiif.h" 5713498266Sopenharmony_ci#include "inet_pton.h" 5813498266Sopenharmony_ci#include "connect.h" 5913498266Sopenharmony_ci#include "select.h" 6013498266Sopenharmony_ci#include "progress.h" 6113498266Sopenharmony_ci#include "timediff.h" 6213498266Sopenharmony_ci 6313498266Sopenharmony_ci#if defined(CURL_STATICLIB) && !defined(CARES_STATICLIB) && \ 6413498266Sopenharmony_ci defined(_WIN32) 6513498266Sopenharmony_ci# define CARES_STATICLIB 6613498266Sopenharmony_ci#endif 6713498266Sopenharmony_ci#include <ares.h> 6813498266Sopenharmony_ci#include <ares_version.h> /* really old c-ares didn't include this by 6913498266Sopenharmony_ci itself */ 7013498266Sopenharmony_ci 7113498266Sopenharmony_ci#if ARES_VERSION >= 0x010500 7213498266Sopenharmony_ci/* c-ares 1.5.0 or later, the callback proto is modified */ 7313498266Sopenharmony_ci#define HAVE_CARES_CALLBACK_TIMEOUTS 1 7413498266Sopenharmony_ci#endif 7513498266Sopenharmony_ci 7613498266Sopenharmony_ci#if ARES_VERSION >= 0x010601 7713498266Sopenharmony_ci/* IPv6 supported since 1.6.1 */ 7813498266Sopenharmony_ci#define HAVE_CARES_IPV6 1 7913498266Sopenharmony_ci#endif 8013498266Sopenharmony_ci 8113498266Sopenharmony_ci#if ARES_VERSION >= 0x010704 8213498266Sopenharmony_ci#define HAVE_CARES_SERVERS_CSV 1 8313498266Sopenharmony_ci#define HAVE_CARES_LOCAL_DEV 1 8413498266Sopenharmony_ci#define HAVE_CARES_SET_LOCAL 1 8513498266Sopenharmony_ci#endif 8613498266Sopenharmony_ci 8713498266Sopenharmony_ci#if ARES_VERSION >= 0x010b00 8813498266Sopenharmony_ci#define HAVE_CARES_PORTS_CSV 1 8913498266Sopenharmony_ci#endif 9013498266Sopenharmony_ci 9113498266Sopenharmony_ci#if ARES_VERSION >= 0x011000 9213498266Sopenharmony_ci/* 1.16.0 or later has ares_getaddrinfo */ 9313498266Sopenharmony_ci#define HAVE_CARES_GETADDRINFO 1 9413498266Sopenharmony_ci#endif 9513498266Sopenharmony_ci 9613498266Sopenharmony_ci/* The last 3 #include files should be in this order */ 9713498266Sopenharmony_ci#include "curl_printf.h" 9813498266Sopenharmony_ci#include "curl_memory.h" 9913498266Sopenharmony_ci#include "memdebug.h" 10013498266Sopenharmony_ci 10113498266Sopenharmony_cistruct thread_data { 10213498266Sopenharmony_ci int num_pending; /* number of outstanding c-ares requests */ 10313498266Sopenharmony_ci struct Curl_addrinfo *temp_ai; /* intermediary result while fetching c-ares 10413498266Sopenharmony_ci parts */ 10513498266Sopenharmony_ci int last_status; 10613498266Sopenharmony_ci#ifndef HAVE_CARES_GETADDRINFO 10713498266Sopenharmony_ci struct curltime happy_eyeballs_dns_time; /* when this timer started, or 0 */ 10813498266Sopenharmony_ci#endif 10913498266Sopenharmony_ci char hostname[1]; 11013498266Sopenharmony_ci}; 11113498266Sopenharmony_ci 11213498266Sopenharmony_ci/* How long we are willing to wait for additional parallel responses after 11313498266Sopenharmony_ci obtaining a "definitive" one. For old c-ares without getaddrinfo. 11413498266Sopenharmony_ci 11513498266Sopenharmony_ci This is intended to equal the c-ares default timeout. cURL always uses that 11613498266Sopenharmony_ci default value. Unfortunately, c-ares doesn't expose its default timeout in 11713498266Sopenharmony_ci its API, but it is officially documented as 5 seconds. 11813498266Sopenharmony_ci 11913498266Sopenharmony_ci See query_completed_cb() for an explanation of how this is used. 12013498266Sopenharmony_ci */ 12113498266Sopenharmony_ci#define HAPPY_EYEBALLS_DNS_TIMEOUT 5000 12213498266Sopenharmony_ci 12313498266Sopenharmony_ci#define CARES_TIMEOUT_PER_ATTEMPT 2000 12413498266Sopenharmony_ci 12513498266Sopenharmony_ci/* 12613498266Sopenharmony_ci * Curl_resolver_global_init() - the generic low-level asynchronous name 12713498266Sopenharmony_ci * resolve API. Called from curl_global_init() to initialize global resolver 12813498266Sopenharmony_ci * environment. Initializes ares library. 12913498266Sopenharmony_ci */ 13013498266Sopenharmony_ciint Curl_resolver_global_init(void) 13113498266Sopenharmony_ci{ 13213498266Sopenharmony_ci#ifdef CARES_HAVE_ARES_LIBRARY_INIT 13313498266Sopenharmony_ci if(ares_library_init(ARES_LIB_INIT_ALL)) { 13413498266Sopenharmony_ci return CURLE_FAILED_INIT; 13513498266Sopenharmony_ci } 13613498266Sopenharmony_ci#endif 13713498266Sopenharmony_ci return CURLE_OK; 13813498266Sopenharmony_ci} 13913498266Sopenharmony_ci 14013498266Sopenharmony_ci/* 14113498266Sopenharmony_ci * Curl_resolver_global_cleanup() 14213498266Sopenharmony_ci * 14313498266Sopenharmony_ci * Called from curl_global_cleanup() to destroy global resolver environment. 14413498266Sopenharmony_ci * Deinitializes ares library. 14513498266Sopenharmony_ci */ 14613498266Sopenharmony_civoid Curl_resolver_global_cleanup(void) 14713498266Sopenharmony_ci{ 14813498266Sopenharmony_ci#ifdef CARES_HAVE_ARES_LIBRARY_CLEANUP 14913498266Sopenharmony_ci ares_library_cleanup(); 15013498266Sopenharmony_ci#endif 15113498266Sopenharmony_ci} 15213498266Sopenharmony_ci 15313498266Sopenharmony_ci 15413498266Sopenharmony_cistatic void sock_state_cb(void *data, ares_socket_t socket_fd, 15513498266Sopenharmony_ci int readable, int writable) 15613498266Sopenharmony_ci{ 15713498266Sopenharmony_ci struct Curl_easy *easy = data; 15813498266Sopenharmony_ci if(!readable && !writable) { 15913498266Sopenharmony_ci DEBUGASSERT(easy); 16013498266Sopenharmony_ci Curl_multi_closed(easy, socket_fd); 16113498266Sopenharmony_ci } 16213498266Sopenharmony_ci} 16313498266Sopenharmony_ci 16413498266Sopenharmony_ci/* 16513498266Sopenharmony_ci * Curl_resolver_init() 16613498266Sopenharmony_ci * 16713498266Sopenharmony_ci * Called from curl_easy_init() -> Curl_open() to initialize resolver 16813498266Sopenharmony_ci * URL-state specific environment ('resolver' member of the UrlState 16913498266Sopenharmony_ci * structure). Fills the passed pointer by the initialized ares_channel. 17013498266Sopenharmony_ci */ 17113498266Sopenharmony_ciCURLcode Curl_resolver_init(struct Curl_easy *easy, void **resolver) 17213498266Sopenharmony_ci{ 17313498266Sopenharmony_ci int status; 17413498266Sopenharmony_ci struct ares_options options; 17513498266Sopenharmony_ci int optmask = ARES_OPT_SOCK_STATE_CB; 17613498266Sopenharmony_ci static int ares_ver = 0; 17713498266Sopenharmony_ci options.sock_state_cb = sock_state_cb; 17813498266Sopenharmony_ci options.sock_state_cb_data = easy; 17913498266Sopenharmony_ci if(ares_ver == 0) 18013498266Sopenharmony_ci ares_version(&ares_ver); 18113498266Sopenharmony_ci 18213498266Sopenharmony_ci if(ares_ver < 0x011400) { /* c-ares included similar change since 1.20.0 */ 18313498266Sopenharmony_ci options.timeout = CARES_TIMEOUT_PER_ATTEMPT; 18413498266Sopenharmony_ci optmask |= ARES_OPT_TIMEOUTMS; 18513498266Sopenharmony_ci } 18613498266Sopenharmony_ci 18713498266Sopenharmony_ci /* 18813498266Sopenharmony_ci if c ares < 1.20.0: curl set timeout to CARES_TIMEOUT_PER_ATTEMPT (2s) 18913498266Sopenharmony_ci 19013498266Sopenharmony_ci if c-ares >= 1.20.0 it already has the timeout to 2s, curl does not need 19113498266Sopenharmony_ci to set the timeout value; 19213498266Sopenharmony_ci 19313498266Sopenharmony_ci if c-ares >= 1.24.0, user can set the timeout via /etc/resolv.conf to 19413498266Sopenharmony_ci overwrite c-ares' timeout. 19513498266Sopenharmony_ci */ 19613498266Sopenharmony_ci 19713498266Sopenharmony_ci status = ares_init_options((ares_channel*)resolver, &options, optmask); 19813498266Sopenharmony_ci if(status != ARES_SUCCESS) { 19913498266Sopenharmony_ci if(status == ARES_ENOMEM) 20013498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 20113498266Sopenharmony_ci else 20213498266Sopenharmony_ci return CURLE_FAILED_INIT; 20313498266Sopenharmony_ci } 20413498266Sopenharmony_ci return CURLE_OK; 20513498266Sopenharmony_ci /* make sure that all other returns from this function should destroy the 20613498266Sopenharmony_ci ares channel before returning error! */ 20713498266Sopenharmony_ci} 20813498266Sopenharmony_ci 20913498266Sopenharmony_ci/* 21013498266Sopenharmony_ci * Curl_resolver_cleanup() 21113498266Sopenharmony_ci * 21213498266Sopenharmony_ci * Called from curl_easy_cleanup() -> Curl_close() to cleanup resolver 21313498266Sopenharmony_ci * URL-state specific environment ('resolver' member of the UrlState 21413498266Sopenharmony_ci * structure). Destroys the ares channel. 21513498266Sopenharmony_ci */ 21613498266Sopenharmony_civoid Curl_resolver_cleanup(void *resolver) 21713498266Sopenharmony_ci{ 21813498266Sopenharmony_ci ares_destroy((ares_channel)resolver); 21913498266Sopenharmony_ci} 22013498266Sopenharmony_ci 22113498266Sopenharmony_ci/* 22213498266Sopenharmony_ci * Curl_resolver_duphandle() 22313498266Sopenharmony_ci * 22413498266Sopenharmony_ci * Called from curl_easy_duphandle() to duplicate resolver URL-state specific 22513498266Sopenharmony_ci * environment ('resolver' member of the UrlState structure). Duplicates the 22613498266Sopenharmony_ci * 'from' ares channel and passes the resulting channel to the 'to' pointer. 22713498266Sopenharmony_ci */ 22813498266Sopenharmony_ciCURLcode Curl_resolver_duphandle(struct Curl_easy *easy, void **to, void *from) 22913498266Sopenharmony_ci{ 23013498266Sopenharmony_ci (void)from; 23113498266Sopenharmony_ci /* 23213498266Sopenharmony_ci * it would be better to call ares_dup instead, but right now 23313498266Sopenharmony_ci * it is not possible to set 'sock_state_cb_data' outside of 23413498266Sopenharmony_ci * ares_init_options 23513498266Sopenharmony_ci */ 23613498266Sopenharmony_ci return Curl_resolver_init(easy, to); 23713498266Sopenharmony_ci} 23813498266Sopenharmony_ci 23913498266Sopenharmony_cistatic void destroy_async_data(struct Curl_async *async); 24013498266Sopenharmony_ci 24113498266Sopenharmony_ci/* 24213498266Sopenharmony_ci * Cancel all possibly still on-going resolves for this connection. 24313498266Sopenharmony_ci */ 24413498266Sopenharmony_civoid Curl_resolver_cancel(struct Curl_easy *data) 24513498266Sopenharmony_ci{ 24613498266Sopenharmony_ci DEBUGASSERT(data); 24713498266Sopenharmony_ci if(data->state.async.resolver) 24813498266Sopenharmony_ci ares_cancel((ares_channel)data->state.async.resolver); 24913498266Sopenharmony_ci destroy_async_data(&data->state.async); 25013498266Sopenharmony_ci} 25113498266Sopenharmony_ci 25213498266Sopenharmony_ci/* 25313498266Sopenharmony_ci * We're equivalent to Curl_resolver_cancel() for the c-ares resolver. We 25413498266Sopenharmony_ci * never block. 25513498266Sopenharmony_ci */ 25613498266Sopenharmony_civoid Curl_resolver_kill(struct Curl_easy *data) 25713498266Sopenharmony_ci{ 25813498266Sopenharmony_ci /* We don't need to check the resolver state because we can be called safely 25913498266Sopenharmony_ci at any time and we always do the same thing. */ 26013498266Sopenharmony_ci Curl_resolver_cancel(data); 26113498266Sopenharmony_ci} 26213498266Sopenharmony_ci 26313498266Sopenharmony_ci/* 26413498266Sopenharmony_ci * destroy_async_data() cleans up async resolver data. 26513498266Sopenharmony_ci */ 26613498266Sopenharmony_cistatic void destroy_async_data(struct Curl_async *async) 26713498266Sopenharmony_ci{ 26813498266Sopenharmony_ci if(async->tdata) { 26913498266Sopenharmony_ci struct thread_data *res = async->tdata; 27013498266Sopenharmony_ci if(res) { 27113498266Sopenharmony_ci if(res->temp_ai) { 27213498266Sopenharmony_ci Curl_freeaddrinfo(res->temp_ai); 27313498266Sopenharmony_ci res->temp_ai = NULL; 27413498266Sopenharmony_ci } 27513498266Sopenharmony_ci free(res); 27613498266Sopenharmony_ci } 27713498266Sopenharmony_ci async->tdata = NULL; 27813498266Sopenharmony_ci } 27913498266Sopenharmony_ci} 28013498266Sopenharmony_ci 28113498266Sopenharmony_ci/* 28213498266Sopenharmony_ci * Curl_resolver_getsock() is called when someone from the outside world 28313498266Sopenharmony_ci * (using curl_multi_fdset()) wants to get our fd_set setup and we're talking 28413498266Sopenharmony_ci * with ares. The caller must make sure that this function is only called when 28513498266Sopenharmony_ci * we have a working ares channel. 28613498266Sopenharmony_ci * 28713498266Sopenharmony_ci * Returns: sockets-in-use-bitmap 28813498266Sopenharmony_ci */ 28913498266Sopenharmony_ci 29013498266Sopenharmony_ciint Curl_resolver_getsock(struct Curl_easy *data, 29113498266Sopenharmony_ci curl_socket_t *socks) 29213498266Sopenharmony_ci{ 29313498266Sopenharmony_ci struct timeval maxtime; 29413498266Sopenharmony_ci struct timeval timebuf; 29513498266Sopenharmony_ci struct timeval *timeout; 29613498266Sopenharmony_ci long milli; 29713498266Sopenharmony_ci int max = ares_getsock((ares_channel)data->state.async.resolver, 29813498266Sopenharmony_ci (ares_socket_t *)socks, MAX_SOCKSPEREASYHANDLE); 29913498266Sopenharmony_ci 30013498266Sopenharmony_ci maxtime.tv_sec = CURL_TIMEOUT_RESOLVE; 30113498266Sopenharmony_ci maxtime.tv_usec = 0; 30213498266Sopenharmony_ci 30313498266Sopenharmony_ci timeout = ares_timeout((ares_channel)data->state.async.resolver, &maxtime, 30413498266Sopenharmony_ci &timebuf); 30513498266Sopenharmony_ci milli = (long)curlx_tvtoms(timeout); 30613498266Sopenharmony_ci if(milli == 0) 30713498266Sopenharmony_ci milli += 10; 30813498266Sopenharmony_ci Curl_expire(data, milli, EXPIRE_ASYNC_NAME); 30913498266Sopenharmony_ci 31013498266Sopenharmony_ci return max; 31113498266Sopenharmony_ci} 31213498266Sopenharmony_ci 31313498266Sopenharmony_ci/* 31413498266Sopenharmony_ci * waitperform() 31513498266Sopenharmony_ci * 31613498266Sopenharmony_ci * 1) Ask ares what sockets it currently plays with, then 31713498266Sopenharmony_ci * 2) wait for the timeout period to check for action on ares' sockets. 31813498266Sopenharmony_ci * 3) tell ares to act on all the sockets marked as "with action" 31913498266Sopenharmony_ci * 32013498266Sopenharmony_ci * return number of sockets it worked on, or -1 on error 32113498266Sopenharmony_ci */ 32213498266Sopenharmony_ci 32313498266Sopenharmony_cistatic int waitperform(struct Curl_easy *data, timediff_t timeout_ms) 32413498266Sopenharmony_ci{ 32513498266Sopenharmony_ci int nfds; 32613498266Sopenharmony_ci int bitmask; 32713498266Sopenharmony_ci ares_socket_t socks[ARES_GETSOCK_MAXNUM]; 32813498266Sopenharmony_ci struct pollfd pfd[ARES_GETSOCK_MAXNUM]; 32913498266Sopenharmony_ci int i; 33013498266Sopenharmony_ci int num = 0; 33113498266Sopenharmony_ci 33213498266Sopenharmony_ci bitmask = ares_getsock((ares_channel)data->state.async.resolver, socks, 33313498266Sopenharmony_ci ARES_GETSOCK_MAXNUM); 33413498266Sopenharmony_ci 33513498266Sopenharmony_ci for(i = 0; i < ARES_GETSOCK_MAXNUM; i++) { 33613498266Sopenharmony_ci pfd[i].events = 0; 33713498266Sopenharmony_ci pfd[i].revents = 0; 33813498266Sopenharmony_ci if(ARES_GETSOCK_READABLE(bitmask, i)) { 33913498266Sopenharmony_ci pfd[i].fd = socks[i]; 34013498266Sopenharmony_ci pfd[i].events |= POLLRDNORM|POLLIN; 34113498266Sopenharmony_ci } 34213498266Sopenharmony_ci if(ARES_GETSOCK_WRITABLE(bitmask, i)) { 34313498266Sopenharmony_ci pfd[i].fd = socks[i]; 34413498266Sopenharmony_ci pfd[i].events |= POLLWRNORM|POLLOUT; 34513498266Sopenharmony_ci } 34613498266Sopenharmony_ci if(pfd[i].events) 34713498266Sopenharmony_ci num++; 34813498266Sopenharmony_ci else 34913498266Sopenharmony_ci break; 35013498266Sopenharmony_ci } 35113498266Sopenharmony_ci 35213498266Sopenharmony_ci if(num) { 35313498266Sopenharmony_ci nfds = Curl_poll(pfd, num, timeout_ms); 35413498266Sopenharmony_ci if(nfds < 0) 35513498266Sopenharmony_ci return -1; 35613498266Sopenharmony_ci } 35713498266Sopenharmony_ci else 35813498266Sopenharmony_ci nfds = 0; 35913498266Sopenharmony_ci 36013498266Sopenharmony_ci if(!nfds) 36113498266Sopenharmony_ci /* Call ares_process() unconditionally here, even if we simply timed out 36213498266Sopenharmony_ci above, as otherwise the ares name resolve won't timeout! */ 36313498266Sopenharmony_ci ares_process_fd((ares_channel)data->state.async.resolver, ARES_SOCKET_BAD, 36413498266Sopenharmony_ci ARES_SOCKET_BAD); 36513498266Sopenharmony_ci else { 36613498266Sopenharmony_ci /* move through the descriptors and ask for processing on them */ 36713498266Sopenharmony_ci for(i = 0; i < num; i++) 36813498266Sopenharmony_ci ares_process_fd((ares_channel)data->state.async.resolver, 36913498266Sopenharmony_ci (pfd[i].revents & (POLLRDNORM|POLLIN))? 37013498266Sopenharmony_ci pfd[i].fd:ARES_SOCKET_BAD, 37113498266Sopenharmony_ci (pfd[i].revents & (POLLWRNORM|POLLOUT))? 37213498266Sopenharmony_ci pfd[i].fd:ARES_SOCKET_BAD); 37313498266Sopenharmony_ci } 37413498266Sopenharmony_ci return nfds; 37513498266Sopenharmony_ci} 37613498266Sopenharmony_ci 37713498266Sopenharmony_ci/* 37813498266Sopenharmony_ci * Curl_resolver_is_resolved() is called repeatedly to check if a previous 37913498266Sopenharmony_ci * name resolve request has completed. It should also make sure to time-out if 38013498266Sopenharmony_ci * the operation seems to take too long. 38113498266Sopenharmony_ci * 38213498266Sopenharmony_ci * Returns normal CURLcode errors. 38313498266Sopenharmony_ci */ 38413498266Sopenharmony_ciCURLcode Curl_resolver_is_resolved(struct Curl_easy *data, 38513498266Sopenharmony_ci struct Curl_dns_entry **dns) 38613498266Sopenharmony_ci{ 38713498266Sopenharmony_ci struct thread_data *res = data->state.async.tdata; 38813498266Sopenharmony_ci CURLcode result = CURLE_OK; 38913498266Sopenharmony_ci 39013498266Sopenharmony_ci DEBUGASSERT(dns); 39113498266Sopenharmony_ci *dns = NULL; 39213498266Sopenharmony_ci 39313498266Sopenharmony_ci if(waitperform(data, 0) < 0) 39413498266Sopenharmony_ci return CURLE_UNRECOVERABLE_POLL; 39513498266Sopenharmony_ci 39613498266Sopenharmony_ci#ifndef HAVE_CARES_GETADDRINFO 39713498266Sopenharmony_ci /* Now that we've checked for any last minute results above, see if there are 39813498266Sopenharmony_ci any responses still pending when the EXPIRE_HAPPY_EYEBALLS_DNS timer 39913498266Sopenharmony_ci expires. */ 40013498266Sopenharmony_ci if(res 40113498266Sopenharmony_ci && res->num_pending 40213498266Sopenharmony_ci /* This is only set to non-zero if the timer was started. */ 40313498266Sopenharmony_ci && (res->happy_eyeballs_dns_time.tv_sec 40413498266Sopenharmony_ci || res->happy_eyeballs_dns_time.tv_usec) 40513498266Sopenharmony_ci && (Curl_timediff(Curl_now(), res->happy_eyeballs_dns_time) 40613498266Sopenharmony_ci >= HAPPY_EYEBALLS_DNS_TIMEOUT)) { 40713498266Sopenharmony_ci /* Remember that the EXPIRE_HAPPY_EYEBALLS_DNS timer is no longer 40813498266Sopenharmony_ci running. */ 40913498266Sopenharmony_ci memset( 41013498266Sopenharmony_ci &res->happy_eyeballs_dns_time, 0, sizeof(res->happy_eyeballs_dns_time)); 41113498266Sopenharmony_ci 41213498266Sopenharmony_ci /* Cancel the raw c-ares request, which will fire query_completed_cb() with 41313498266Sopenharmony_ci ARES_ECANCELLED synchronously for all pending responses. This will 41413498266Sopenharmony_ci leave us with res->num_pending == 0, which is perfect for the next 41513498266Sopenharmony_ci block. */ 41613498266Sopenharmony_ci ares_cancel((ares_channel)data->state.async.resolver); 41713498266Sopenharmony_ci DEBUGASSERT(res->num_pending == 0); 41813498266Sopenharmony_ci } 41913498266Sopenharmony_ci#endif 42013498266Sopenharmony_ci 42113498266Sopenharmony_ci if(res && !res->num_pending) { 42213498266Sopenharmony_ci (void)Curl_addrinfo_callback(data, res->last_status, res->temp_ai); 42313498266Sopenharmony_ci /* temp_ai ownership is moved to the connection, so we need not free-up 42413498266Sopenharmony_ci them */ 42513498266Sopenharmony_ci res->temp_ai = NULL; 42613498266Sopenharmony_ci 42713498266Sopenharmony_ci if(!data->state.async.dns) 42813498266Sopenharmony_ci result = Curl_resolver_error(data); 42913498266Sopenharmony_ci else 43013498266Sopenharmony_ci *dns = data->state.async.dns; 43113498266Sopenharmony_ci 43213498266Sopenharmony_ci destroy_async_data(&data->state.async); 43313498266Sopenharmony_ci } 43413498266Sopenharmony_ci 43513498266Sopenharmony_ci return result; 43613498266Sopenharmony_ci} 43713498266Sopenharmony_ci 43813498266Sopenharmony_ci/* 43913498266Sopenharmony_ci * Curl_resolver_wait_resolv() 44013498266Sopenharmony_ci * 44113498266Sopenharmony_ci * Waits for a resolve to finish. This function should be avoided since using 44213498266Sopenharmony_ci * this risk getting the multi interface to "hang". 44313498266Sopenharmony_ci * 44413498266Sopenharmony_ci * 'entry' MUST be non-NULL. 44513498266Sopenharmony_ci * 44613498266Sopenharmony_ci * Returns CURLE_COULDNT_RESOLVE_HOST if the host was not resolved, 44713498266Sopenharmony_ci * CURLE_OPERATION_TIMEDOUT if a time-out occurred, or other errors. 44813498266Sopenharmony_ci */ 44913498266Sopenharmony_ciCURLcode Curl_resolver_wait_resolv(struct Curl_easy *data, 45013498266Sopenharmony_ci struct Curl_dns_entry **entry) 45113498266Sopenharmony_ci{ 45213498266Sopenharmony_ci CURLcode result = CURLE_OK; 45313498266Sopenharmony_ci timediff_t timeout; 45413498266Sopenharmony_ci struct curltime now = Curl_now(); 45513498266Sopenharmony_ci 45613498266Sopenharmony_ci DEBUGASSERT(entry); 45713498266Sopenharmony_ci *entry = NULL; /* clear on entry */ 45813498266Sopenharmony_ci 45913498266Sopenharmony_ci timeout = Curl_timeleft(data, &now, TRUE); 46013498266Sopenharmony_ci if(timeout < 0) { 46113498266Sopenharmony_ci /* already expired! */ 46213498266Sopenharmony_ci connclose(data->conn, "Timed out before name resolve started"); 46313498266Sopenharmony_ci return CURLE_OPERATION_TIMEDOUT; 46413498266Sopenharmony_ci } 46513498266Sopenharmony_ci if(!timeout) 46613498266Sopenharmony_ci timeout = CURL_TIMEOUT_RESOLVE * 1000; /* default name resolve timeout */ 46713498266Sopenharmony_ci 46813498266Sopenharmony_ci /* Wait for the name resolve query to complete. */ 46913498266Sopenharmony_ci while(!result) { 47013498266Sopenharmony_ci struct timeval *tvp, tv, store; 47113498266Sopenharmony_ci int itimeout; 47213498266Sopenharmony_ci timediff_t timeout_ms; 47313498266Sopenharmony_ci 47413498266Sopenharmony_ci#if TIMEDIFF_T_MAX > INT_MAX 47513498266Sopenharmony_ci itimeout = (timeout > INT_MAX) ? INT_MAX : (int)timeout; 47613498266Sopenharmony_ci#else 47713498266Sopenharmony_ci itimeout = (int)timeout; 47813498266Sopenharmony_ci#endif 47913498266Sopenharmony_ci 48013498266Sopenharmony_ci store.tv_sec = itimeout/1000; 48113498266Sopenharmony_ci store.tv_usec = (itimeout%1000)*1000; 48213498266Sopenharmony_ci 48313498266Sopenharmony_ci tvp = ares_timeout((ares_channel)data->state.async.resolver, &store, &tv); 48413498266Sopenharmony_ci 48513498266Sopenharmony_ci /* use the timeout period ares returned to us above if less than one 48613498266Sopenharmony_ci second is left, otherwise just use 1000ms to make sure the progress 48713498266Sopenharmony_ci callback gets called frequent enough */ 48813498266Sopenharmony_ci if(!tvp->tv_sec) 48913498266Sopenharmony_ci timeout_ms = (timediff_t)(tvp->tv_usec/1000); 49013498266Sopenharmony_ci else 49113498266Sopenharmony_ci timeout_ms = 1000; 49213498266Sopenharmony_ci 49313498266Sopenharmony_ci if(waitperform(data, timeout_ms) < 0) 49413498266Sopenharmony_ci return CURLE_UNRECOVERABLE_POLL; 49513498266Sopenharmony_ci result = Curl_resolver_is_resolved(data, entry); 49613498266Sopenharmony_ci 49713498266Sopenharmony_ci if(result || data->state.async.done) 49813498266Sopenharmony_ci break; 49913498266Sopenharmony_ci 50013498266Sopenharmony_ci if(Curl_pgrsUpdate(data)) 50113498266Sopenharmony_ci result = CURLE_ABORTED_BY_CALLBACK; 50213498266Sopenharmony_ci else { 50313498266Sopenharmony_ci struct curltime now2 = Curl_now(); 50413498266Sopenharmony_ci timediff_t timediff = Curl_timediff(now2, now); /* spent time */ 50513498266Sopenharmony_ci if(timediff <= 0) 50613498266Sopenharmony_ci timeout -= 1; /* always deduct at least 1 */ 50713498266Sopenharmony_ci else if(timediff > timeout) 50813498266Sopenharmony_ci timeout = -1; 50913498266Sopenharmony_ci else 51013498266Sopenharmony_ci timeout -= timediff; 51113498266Sopenharmony_ci now = now2; /* for next loop */ 51213498266Sopenharmony_ci } 51313498266Sopenharmony_ci if(timeout < 0) 51413498266Sopenharmony_ci result = CURLE_OPERATION_TIMEDOUT; 51513498266Sopenharmony_ci } 51613498266Sopenharmony_ci if(result) 51713498266Sopenharmony_ci /* failure, so we cancel the ares operation */ 51813498266Sopenharmony_ci ares_cancel((ares_channel)data->state.async.resolver); 51913498266Sopenharmony_ci 52013498266Sopenharmony_ci /* Operation complete, if the lookup was successful we now have the entry 52113498266Sopenharmony_ci in the cache. */ 52213498266Sopenharmony_ci if(entry) 52313498266Sopenharmony_ci *entry = data->state.async.dns; 52413498266Sopenharmony_ci 52513498266Sopenharmony_ci if(result) 52613498266Sopenharmony_ci /* close the connection, since we can't return failure here without 52713498266Sopenharmony_ci cleaning up this connection properly. */ 52813498266Sopenharmony_ci connclose(data->conn, "c-ares resolve failed"); 52913498266Sopenharmony_ci 53013498266Sopenharmony_ci return result; 53113498266Sopenharmony_ci} 53213498266Sopenharmony_ci 53313498266Sopenharmony_ci#ifndef HAVE_CARES_GETADDRINFO 53413498266Sopenharmony_ci 53513498266Sopenharmony_ci/* Connects results to the list */ 53613498266Sopenharmony_cistatic void compound_results(struct thread_data *res, 53713498266Sopenharmony_ci struct Curl_addrinfo *ai) 53813498266Sopenharmony_ci{ 53913498266Sopenharmony_ci if(!ai) 54013498266Sopenharmony_ci return; 54113498266Sopenharmony_ci 54213498266Sopenharmony_ci#ifdef ENABLE_IPV6 /* CURLRES_IPV6 */ 54313498266Sopenharmony_ci if(res->temp_ai && res->temp_ai->ai_family == PF_INET6) { 54413498266Sopenharmony_ci /* We have results already, put the new IPv6 entries at the head of the 54513498266Sopenharmony_ci list. */ 54613498266Sopenharmony_ci struct Curl_addrinfo *temp_ai_tail = res->temp_ai; 54713498266Sopenharmony_ci 54813498266Sopenharmony_ci while(temp_ai_tail->ai_next) 54913498266Sopenharmony_ci temp_ai_tail = temp_ai_tail->ai_next; 55013498266Sopenharmony_ci 55113498266Sopenharmony_ci temp_ai_tail->ai_next = ai; 55213498266Sopenharmony_ci } 55313498266Sopenharmony_ci else 55413498266Sopenharmony_ci#endif /* CURLRES_IPV6 */ 55513498266Sopenharmony_ci { 55613498266Sopenharmony_ci /* Add the new results to the list of old results. */ 55713498266Sopenharmony_ci struct Curl_addrinfo *ai_tail = ai; 55813498266Sopenharmony_ci while(ai_tail->ai_next) 55913498266Sopenharmony_ci ai_tail = ai_tail->ai_next; 56013498266Sopenharmony_ci 56113498266Sopenharmony_ci ai_tail->ai_next = res->temp_ai; 56213498266Sopenharmony_ci res->temp_ai = ai; 56313498266Sopenharmony_ci } 56413498266Sopenharmony_ci} 56513498266Sopenharmony_ci 56613498266Sopenharmony_ci/* 56713498266Sopenharmony_ci * ares_query_completed_cb() is the callback that ares will call when 56813498266Sopenharmony_ci * the host query initiated by ares_gethostbyname() from Curl_getaddrinfo(), 56913498266Sopenharmony_ci * when using ares, is completed either successfully or with failure. 57013498266Sopenharmony_ci */ 57113498266Sopenharmony_cistatic void query_completed_cb(void *arg, /* (struct connectdata *) */ 57213498266Sopenharmony_ci int status, 57313498266Sopenharmony_ci#ifdef HAVE_CARES_CALLBACK_TIMEOUTS 57413498266Sopenharmony_ci int timeouts, 57513498266Sopenharmony_ci#endif 57613498266Sopenharmony_ci struct hostent *hostent) 57713498266Sopenharmony_ci{ 57813498266Sopenharmony_ci struct Curl_easy *data = (struct Curl_easy *)arg; 57913498266Sopenharmony_ci struct thread_data *res; 58013498266Sopenharmony_ci 58113498266Sopenharmony_ci#ifdef HAVE_CARES_CALLBACK_TIMEOUTS 58213498266Sopenharmony_ci (void)timeouts; /* ignored */ 58313498266Sopenharmony_ci#endif 58413498266Sopenharmony_ci 58513498266Sopenharmony_ci if(ARES_EDESTRUCTION == status) 58613498266Sopenharmony_ci /* when this ares handle is getting destroyed, the 'arg' pointer may not 58713498266Sopenharmony_ci be valid so only defer it when we know the 'status' says its fine! */ 58813498266Sopenharmony_ci return; 58913498266Sopenharmony_ci 59013498266Sopenharmony_ci res = data->state.async.tdata; 59113498266Sopenharmony_ci if(res) { 59213498266Sopenharmony_ci res->num_pending--; 59313498266Sopenharmony_ci 59413498266Sopenharmony_ci if(CURL_ASYNC_SUCCESS == status) { 59513498266Sopenharmony_ci struct Curl_addrinfo *ai = Curl_he2ai(hostent, data->state.async.port); 59613498266Sopenharmony_ci if(ai) { 59713498266Sopenharmony_ci compound_results(res, ai); 59813498266Sopenharmony_ci } 59913498266Sopenharmony_ci } 60013498266Sopenharmony_ci /* A successful result overwrites any previous error */ 60113498266Sopenharmony_ci if(res->last_status != ARES_SUCCESS) 60213498266Sopenharmony_ci res->last_status = status; 60313498266Sopenharmony_ci 60413498266Sopenharmony_ci /* If there are responses still pending, we presume they must be the 60513498266Sopenharmony_ci complementary IPv4 or IPv6 lookups that we started in parallel in 60613498266Sopenharmony_ci Curl_resolver_getaddrinfo() (for Happy Eyeballs). If we've got a 60713498266Sopenharmony_ci "definitive" response from one of a set of parallel queries, we need to 60813498266Sopenharmony_ci think about how long we're willing to wait for more responses. */ 60913498266Sopenharmony_ci if(res->num_pending 61013498266Sopenharmony_ci /* Only these c-ares status values count as "definitive" for these 61113498266Sopenharmony_ci purposes. For example, ARES_ENODATA is what we expect when there is 61213498266Sopenharmony_ci no IPv6 entry for a domain name, and that's not a reason to get more 61313498266Sopenharmony_ci aggressive in our timeouts for the other response. Other errors are 61413498266Sopenharmony_ci either a result of bad input (which should affect all parallel 61513498266Sopenharmony_ci requests), local or network conditions, non-definitive server 61613498266Sopenharmony_ci responses, or us cancelling the request. */ 61713498266Sopenharmony_ci && (status == ARES_SUCCESS || status == ARES_ENOTFOUND)) { 61813498266Sopenharmony_ci /* Right now, there can only be up to two parallel queries, so don't 61913498266Sopenharmony_ci bother handling any other cases. */ 62013498266Sopenharmony_ci DEBUGASSERT(res->num_pending == 1); 62113498266Sopenharmony_ci 62213498266Sopenharmony_ci /* It's possible that one of these parallel queries could succeed 62313498266Sopenharmony_ci quickly, but the other could always fail or timeout (when we're 62413498266Sopenharmony_ci talking to a pool of DNS servers that can only successfully resolve 62513498266Sopenharmony_ci IPv4 address, for example). 62613498266Sopenharmony_ci 62713498266Sopenharmony_ci It's also possible that the other request could always just take 62813498266Sopenharmony_ci longer because it needs more time or only the second DNS server can 62913498266Sopenharmony_ci fulfill it successfully. But, to align with the philosophy of Happy 63013498266Sopenharmony_ci Eyeballs, we don't want to wait _too_ long or users will think 63113498266Sopenharmony_ci requests are slow when IPv6 lookups don't actually work (but IPv4 ones 63213498266Sopenharmony_ci do). 63313498266Sopenharmony_ci 63413498266Sopenharmony_ci So, now that we have a usable answer (some IPv4 addresses, some IPv6 63513498266Sopenharmony_ci addresses, or "no such domain"), we start a timeout for the remaining 63613498266Sopenharmony_ci pending responses. Even though it is typical that this resolved 63713498266Sopenharmony_ci request came back quickly, that needn't be the case. It might be that 63813498266Sopenharmony_ci this completing request didn't get a result from the first DNS server 63913498266Sopenharmony_ci or even the first round of the whole DNS server pool. So it could 64013498266Sopenharmony_ci already be quite some time after we issued the DNS queries in the 64113498266Sopenharmony_ci first place. Without modifying c-ares, we can't know exactly where in 64213498266Sopenharmony_ci its retry cycle we are. We could guess based on how much time has 64313498266Sopenharmony_ci gone by, but it doesn't really matter. Happy Eyeballs tells us that, 64413498266Sopenharmony_ci given usable information in hand, we simply don't want to wait "too 64513498266Sopenharmony_ci much longer" after we get a result. 64613498266Sopenharmony_ci 64713498266Sopenharmony_ci We simply wait an additional amount of time equal to the default 64813498266Sopenharmony_ci c-ares query timeout. That is enough time for a typical parallel 64913498266Sopenharmony_ci response to arrive without being "too long". Even on a network 65013498266Sopenharmony_ci where one of the two types of queries is failing or timing out 65113498266Sopenharmony_ci constantly, this will usually mean we wait a total of the default 65213498266Sopenharmony_ci c-ares timeout (5 seconds) plus the round trip time for the successful 65313498266Sopenharmony_ci request, which seems bearable. The downside is that c-ares might race 65413498266Sopenharmony_ci with us to issue one more retry just before we give up, but it seems 65513498266Sopenharmony_ci better to "waste" that request instead of trying to guess the perfect 65613498266Sopenharmony_ci timeout to prevent it. After all, we don't even know where in the 65713498266Sopenharmony_ci c-ares retry cycle each request is. 65813498266Sopenharmony_ci */ 65913498266Sopenharmony_ci res->happy_eyeballs_dns_time = Curl_now(); 66013498266Sopenharmony_ci Curl_expire(data, HAPPY_EYEBALLS_DNS_TIMEOUT, 66113498266Sopenharmony_ci EXPIRE_HAPPY_EYEBALLS_DNS); 66213498266Sopenharmony_ci } 66313498266Sopenharmony_ci } 66413498266Sopenharmony_ci} 66513498266Sopenharmony_ci#else 66613498266Sopenharmony_ci/* c-ares 1.16.0 or later */ 66713498266Sopenharmony_ci 66813498266Sopenharmony_ci/* 66913498266Sopenharmony_ci * ares2addr() converts an address list provided by c-ares to an internal 67013498266Sopenharmony_ci * libcurl compatible list 67113498266Sopenharmony_ci */ 67213498266Sopenharmony_cistatic struct Curl_addrinfo *ares2addr(struct ares_addrinfo_node *node) 67313498266Sopenharmony_ci{ 67413498266Sopenharmony_ci /* traverse the ares_addrinfo_node list */ 67513498266Sopenharmony_ci struct ares_addrinfo_node *ai; 67613498266Sopenharmony_ci struct Curl_addrinfo *cafirst = NULL; 67713498266Sopenharmony_ci struct Curl_addrinfo *calast = NULL; 67813498266Sopenharmony_ci int error = 0; 67913498266Sopenharmony_ci 68013498266Sopenharmony_ci for(ai = node; ai != NULL; ai = ai->ai_next) { 68113498266Sopenharmony_ci size_t ss_size; 68213498266Sopenharmony_ci struct Curl_addrinfo *ca; 68313498266Sopenharmony_ci /* ignore elements with unsupported address family, */ 68413498266Sopenharmony_ci /* settle family-specific sockaddr structure size. */ 68513498266Sopenharmony_ci if(ai->ai_family == AF_INET) 68613498266Sopenharmony_ci ss_size = sizeof(struct sockaddr_in); 68713498266Sopenharmony_ci#ifdef ENABLE_IPV6 68813498266Sopenharmony_ci else if(ai->ai_family == AF_INET6) 68913498266Sopenharmony_ci ss_size = sizeof(struct sockaddr_in6); 69013498266Sopenharmony_ci#endif 69113498266Sopenharmony_ci else 69213498266Sopenharmony_ci continue; 69313498266Sopenharmony_ci 69413498266Sopenharmony_ci /* ignore elements without required address info */ 69513498266Sopenharmony_ci if(!ai->ai_addr || !(ai->ai_addrlen > 0)) 69613498266Sopenharmony_ci continue; 69713498266Sopenharmony_ci 69813498266Sopenharmony_ci /* ignore elements with bogus address size */ 69913498266Sopenharmony_ci if((size_t)ai->ai_addrlen < ss_size) 70013498266Sopenharmony_ci continue; 70113498266Sopenharmony_ci 70213498266Sopenharmony_ci ca = malloc(sizeof(struct Curl_addrinfo) + ss_size); 70313498266Sopenharmony_ci if(!ca) { 70413498266Sopenharmony_ci error = EAI_MEMORY; 70513498266Sopenharmony_ci break; 70613498266Sopenharmony_ci } 70713498266Sopenharmony_ci 70813498266Sopenharmony_ci /* copy each structure member individually, member ordering, */ 70913498266Sopenharmony_ci /* size, or padding might be different for each platform. */ 71013498266Sopenharmony_ci 71113498266Sopenharmony_ci ca->ai_flags = ai->ai_flags; 71213498266Sopenharmony_ci ca->ai_family = ai->ai_family; 71313498266Sopenharmony_ci ca->ai_socktype = ai->ai_socktype; 71413498266Sopenharmony_ci ca->ai_protocol = ai->ai_protocol; 71513498266Sopenharmony_ci ca->ai_addrlen = (curl_socklen_t)ss_size; 71613498266Sopenharmony_ci ca->ai_addr = NULL; 71713498266Sopenharmony_ci ca->ai_canonname = NULL; 71813498266Sopenharmony_ci ca->ai_next = NULL; 71913498266Sopenharmony_ci 72013498266Sopenharmony_ci ca->ai_addr = (void *)((char *)ca + sizeof(struct Curl_addrinfo)); 72113498266Sopenharmony_ci memcpy(ca->ai_addr, ai->ai_addr, ss_size); 72213498266Sopenharmony_ci 72313498266Sopenharmony_ci /* if the return list is empty, this becomes the first element */ 72413498266Sopenharmony_ci if(!cafirst) 72513498266Sopenharmony_ci cafirst = ca; 72613498266Sopenharmony_ci 72713498266Sopenharmony_ci /* add this element last in the return list */ 72813498266Sopenharmony_ci if(calast) 72913498266Sopenharmony_ci calast->ai_next = ca; 73013498266Sopenharmony_ci calast = ca; 73113498266Sopenharmony_ci } 73213498266Sopenharmony_ci 73313498266Sopenharmony_ci /* if we failed, destroy the Curl_addrinfo list */ 73413498266Sopenharmony_ci if(error) { 73513498266Sopenharmony_ci Curl_freeaddrinfo(cafirst); 73613498266Sopenharmony_ci cafirst = NULL; 73713498266Sopenharmony_ci } 73813498266Sopenharmony_ci 73913498266Sopenharmony_ci return cafirst; 74013498266Sopenharmony_ci} 74113498266Sopenharmony_ci 74213498266Sopenharmony_cistatic void addrinfo_cb(void *arg, int status, int timeouts, 74313498266Sopenharmony_ci struct ares_addrinfo *result) 74413498266Sopenharmony_ci{ 74513498266Sopenharmony_ci struct Curl_easy *data = (struct Curl_easy *)arg; 74613498266Sopenharmony_ci struct thread_data *res = data->state.async.tdata; 74713498266Sopenharmony_ci (void)timeouts; 74813498266Sopenharmony_ci if(ARES_SUCCESS == status) { 74913498266Sopenharmony_ci res->temp_ai = ares2addr(result->nodes); 75013498266Sopenharmony_ci res->last_status = CURL_ASYNC_SUCCESS; 75113498266Sopenharmony_ci ares_freeaddrinfo(result); 75213498266Sopenharmony_ci } 75313498266Sopenharmony_ci res->num_pending--; 75413498266Sopenharmony_ci} 75513498266Sopenharmony_ci 75613498266Sopenharmony_ci#endif 75713498266Sopenharmony_ci/* 75813498266Sopenharmony_ci * Curl_resolver_getaddrinfo() - when using ares 75913498266Sopenharmony_ci * 76013498266Sopenharmony_ci * Returns name information about the given hostname and port number. If 76113498266Sopenharmony_ci * successful, the 'hostent' is returned and the fourth argument will point to 76213498266Sopenharmony_ci * memory we need to free after use. That memory *MUST* be freed with 76313498266Sopenharmony_ci * Curl_freeaddrinfo(), nothing else. 76413498266Sopenharmony_ci */ 76513498266Sopenharmony_cistruct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data, 76613498266Sopenharmony_ci const char *hostname, 76713498266Sopenharmony_ci int port, 76813498266Sopenharmony_ci int *waitp) 76913498266Sopenharmony_ci{ 77013498266Sopenharmony_ci struct thread_data *res = NULL; 77113498266Sopenharmony_ci size_t namelen = strlen(hostname); 77213498266Sopenharmony_ci *waitp = 0; /* default to synchronous response */ 77313498266Sopenharmony_ci 77413498266Sopenharmony_ci res = calloc(1, sizeof(struct thread_data) + namelen); 77513498266Sopenharmony_ci if(res) { 77613498266Sopenharmony_ci strcpy(res->hostname, hostname); 77713498266Sopenharmony_ci data->state.async.hostname = res->hostname; 77813498266Sopenharmony_ci data->state.async.port = port; 77913498266Sopenharmony_ci data->state.async.done = FALSE; /* not done */ 78013498266Sopenharmony_ci data->state.async.status = 0; /* clear */ 78113498266Sopenharmony_ci data->state.async.dns = NULL; /* clear */ 78213498266Sopenharmony_ci data->state.async.tdata = res; 78313498266Sopenharmony_ci 78413498266Sopenharmony_ci /* initial status - failed */ 78513498266Sopenharmony_ci res->last_status = ARES_ENOTFOUND; 78613498266Sopenharmony_ci 78713498266Sopenharmony_ci#ifdef HAVE_CARES_GETADDRINFO 78813498266Sopenharmony_ci { 78913498266Sopenharmony_ci struct ares_addrinfo_hints hints; 79013498266Sopenharmony_ci char service[12]; 79113498266Sopenharmony_ci int pf = PF_INET; 79213498266Sopenharmony_ci memset(&hints, 0, sizeof(hints)); 79313498266Sopenharmony_ci#ifdef CURLRES_IPV6 79413498266Sopenharmony_ci if((data->conn->ip_version != CURL_IPRESOLVE_V4) && 79513498266Sopenharmony_ci Curl_ipv6works(data)) { 79613498266Sopenharmony_ci /* The stack seems to be IPv6-enabled */ 79713498266Sopenharmony_ci if(data->conn->ip_version == CURL_IPRESOLVE_V6) 79813498266Sopenharmony_ci pf = PF_INET6; 79913498266Sopenharmony_ci else 80013498266Sopenharmony_ci pf = PF_UNSPEC; 80113498266Sopenharmony_ci } 80213498266Sopenharmony_ci#endif /* CURLRES_IPV6 */ 80313498266Sopenharmony_ci hints.ai_family = pf; 80413498266Sopenharmony_ci hints.ai_socktype = (data->conn->transport == TRNSPRT_TCP)? 80513498266Sopenharmony_ci SOCK_STREAM : SOCK_DGRAM; 80613498266Sopenharmony_ci /* Since the service is a numerical one, set the hint flags 80713498266Sopenharmony_ci * accordingly to save a call to getservbyname in inside C-Ares 80813498266Sopenharmony_ci */ 80913498266Sopenharmony_ci hints.ai_flags = ARES_AI_NUMERICSERV; 81013498266Sopenharmony_ci msnprintf(service, sizeof(service), "%d", port); 81113498266Sopenharmony_ci res->num_pending = 1; 81213498266Sopenharmony_ci ares_getaddrinfo((ares_channel)data->state.async.resolver, hostname, 81313498266Sopenharmony_ci service, &hints, addrinfo_cb, data); 81413498266Sopenharmony_ci } 81513498266Sopenharmony_ci#else 81613498266Sopenharmony_ci 81713498266Sopenharmony_ci#ifdef HAVE_CARES_IPV6 81813498266Sopenharmony_ci if((data->conn->ip_version != CURL_IPRESOLVE_V4) && Curl_ipv6works(data)) { 81913498266Sopenharmony_ci /* The stack seems to be IPv6-enabled */ 82013498266Sopenharmony_ci res->num_pending = 2; 82113498266Sopenharmony_ci 82213498266Sopenharmony_ci /* areschannel is already setup in the Curl_open() function */ 82313498266Sopenharmony_ci ares_gethostbyname((ares_channel)data->state.async.resolver, hostname, 82413498266Sopenharmony_ci PF_INET, query_completed_cb, data); 82513498266Sopenharmony_ci ares_gethostbyname((ares_channel)data->state.async.resolver, hostname, 82613498266Sopenharmony_ci PF_INET6, query_completed_cb, data); 82713498266Sopenharmony_ci } 82813498266Sopenharmony_ci else 82913498266Sopenharmony_ci#endif 83013498266Sopenharmony_ci { 83113498266Sopenharmony_ci res->num_pending = 1; 83213498266Sopenharmony_ci 83313498266Sopenharmony_ci /* areschannel is already setup in the Curl_open() function */ 83413498266Sopenharmony_ci ares_gethostbyname((ares_channel)data->state.async.resolver, 83513498266Sopenharmony_ci hostname, PF_INET, 83613498266Sopenharmony_ci query_completed_cb, data); 83713498266Sopenharmony_ci } 83813498266Sopenharmony_ci#endif 83913498266Sopenharmony_ci *waitp = 1; /* expect asynchronous response */ 84013498266Sopenharmony_ci } 84113498266Sopenharmony_ci return NULL; /* no struct yet */ 84213498266Sopenharmony_ci} 84313498266Sopenharmony_ci 84413498266Sopenharmony_ciCURLcode Curl_set_dns_servers(struct Curl_easy *data, 84513498266Sopenharmony_ci char *servers) 84613498266Sopenharmony_ci{ 84713498266Sopenharmony_ci CURLcode result = CURLE_NOT_BUILT_IN; 84813498266Sopenharmony_ci int ares_result; 84913498266Sopenharmony_ci 85013498266Sopenharmony_ci /* If server is NULL or empty, this would purge all DNS servers 85113498266Sopenharmony_ci * from ares library, which will cause any and all queries to fail. 85213498266Sopenharmony_ci * So, just return OK if none are configured and don't actually make 85313498266Sopenharmony_ci * any changes to c-ares. This lets c-ares use it's defaults, which 85413498266Sopenharmony_ci * it gets from the OS (for instance from /etc/resolv.conf on Linux). 85513498266Sopenharmony_ci */ 85613498266Sopenharmony_ci if(!(servers && servers[0])) 85713498266Sopenharmony_ci return CURLE_OK; 85813498266Sopenharmony_ci 85913498266Sopenharmony_ci#ifdef HAVE_CARES_SERVERS_CSV 86013498266Sopenharmony_ci#ifdef HAVE_CARES_PORTS_CSV 86113498266Sopenharmony_ci ares_result = ares_set_servers_ports_csv(data->state.async.resolver, 86213498266Sopenharmony_ci servers); 86313498266Sopenharmony_ci#else 86413498266Sopenharmony_ci ares_result = ares_set_servers_csv(data->state.async.resolver, servers); 86513498266Sopenharmony_ci#endif 86613498266Sopenharmony_ci switch(ares_result) { 86713498266Sopenharmony_ci case ARES_SUCCESS: 86813498266Sopenharmony_ci result = CURLE_OK; 86913498266Sopenharmony_ci break; 87013498266Sopenharmony_ci case ARES_ENOMEM: 87113498266Sopenharmony_ci result = CURLE_OUT_OF_MEMORY; 87213498266Sopenharmony_ci break; 87313498266Sopenharmony_ci case ARES_ENOTINITIALIZED: 87413498266Sopenharmony_ci case ARES_ENODATA: 87513498266Sopenharmony_ci case ARES_EBADSTR: 87613498266Sopenharmony_ci default: 87713498266Sopenharmony_ci DEBUGF(infof(data, "bad servers set")); 87813498266Sopenharmony_ci result = CURLE_BAD_FUNCTION_ARGUMENT; 87913498266Sopenharmony_ci break; 88013498266Sopenharmony_ci } 88113498266Sopenharmony_ci#else /* too old c-ares version! */ 88213498266Sopenharmony_ci (void)data; 88313498266Sopenharmony_ci (void)(ares_result); 88413498266Sopenharmony_ci#endif 88513498266Sopenharmony_ci return result; 88613498266Sopenharmony_ci} 88713498266Sopenharmony_ci 88813498266Sopenharmony_ciCURLcode Curl_set_dns_interface(struct Curl_easy *data, 88913498266Sopenharmony_ci const char *interf) 89013498266Sopenharmony_ci{ 89113498266Sopenharmony_ci#ifdef HAVE_CARES_LOCAL_DEV 89213498266Sopenharmony_ci if(!interf) 89313498266Sopenharmony_ci interf = ""; 89413498266Sopenharmony_ci 89513498266Sopenharmony_ci ares_set_local_dev((ares_channel)data->state.async.resolver, interf); 89613498266Sopenharmony_ci 89713498266Sopenharmony_ci return CURLE_OK; 89813498266Sopenharmony_ci#else /* c-ares version too old! */ 89913498266Sopenharmony_ci (void)data; 90013498266Sopenharmony_ci (void)interf; 90113498266Sopenharmony_ci return CURLE_NOT_BUILT_IN; 90213498266Sopenharmony_ci#endif 90313498266Sopenharmony_ci} 90413498266Sopenharmony_ci 90513498266Sopenharmony_ciCURLcode Curl_set_dns_local_ip4(struct Curl_easy *data, 90613498266Sopenharmony_ci const char *local_ip4) 90713498266Sopenharmony_ci{ 90813498266Sopenharmony_ci#ifdef HAVE_CARES_SET_LOCAL 90913498266Sopenharmony_ci struct in_addr a4; 91013498266Sopenharmony_ci 91113498266Sopenharmony_ci if((!local_ip4) || (local_ip4[0] == 0)) { 91213498266Sopenharmony_ci a4.s_addr = 0; /* disabled: do not bind to a specific address */ 91313498266Sopenharmony_ci } 91413498266Sopenharmony_ci else { 91513498266Sopenharmony_ci if(Curl_inet_pton(AF_INET, local_ip4, &a4) != 1) { 91613498266Sopenharmony_ci DEBUGF(infof(data, "bad DNS IPv4 address")); 91713498266Sopenharmony_ci return CURLE_BAD_FUNCTION_ARGUMENT; 91813498266Sopenharmony_ci } 91913498266Sopenharmony_ci } 92013498266Sopenharmony_ci 92113498266Sopenharmony_ci ares_set_local_ip4((ares_channel)data->state.async.resolver, 92213498266Sopenharmony_ci ntohl(a4.s_addr)); 92313498266Sopenharmony_ci 92413498266Sopenharmony_ci return CURLE_OK; 92513498266Sopenharmony_ci#else /* c-ares version too old! */ 92613498266Sopenharmony_ci (void)data; 92713498266Sopenharmony_ci (void)local_ip4; 92813498266Sopenharmony_ci return CURLE_NOT_BUILT_IN; 92913498266Sopenharmony_ci#endif 93013498266Sopenharmony_ci} 93113498266Sopenharmony_ci 93213498266Sopenharmony_ciCURLcode Curl_set_dns_local_ip6(struct Curl_easy *data, 93313498266Sopenharmony_ci const char *local_ip6) 93413498266Sopenharmony_ci{ 93513498266Sopenharmony_ci#if defined(HAVE_CARES_SET_LOCAL) && defined(ENABLE_IPV6) 93613498266Sopenharmony_ci unsigned char a6[INET6_ADDRSTRLEN]; 93713498266Sopenharmony_ci 93813498266Sopenharmony_ci if((!local_ip6) || (local_ip6[0] == 0)) { 93913498266Sopenharmony_ci /* disabled: do not bind to a specific address */ 94013498266Sopenharmony_ci memset(a6, 0, sizeof(a6)); 94113498266Sopenharmony_ci } 94213498266Sopenharmony_ci else { 94313498266Sopenharmony_ci if(Curl_inet_pton(AF_INET6, local_ip6, a6) != 1) { 94413498266Sopenharmony_ci DEBUGF(infof(data, "bad DNS IPv6 address")); 94513498266Sopenharmony_ci return CURLE_BAD_FUNCTION_ARGUMENT; 94613498266Sopenharmony_ci } 94713498266Sopenharmony_ci } 94813498266Sopenharmony_ci 94913498266Sopenharmony_ci ares_set_local_ip6((ares_channel)data->state.async.resolver, a6); 95013498266Sopenharmony_ci 95113498266Sopenharmony_ci return CURLE_OK; 95213498266Sopenharmony_ci#else /* c-ares version too old! */ 95313498266Sopenharmony_ci (void)data; 95413498266Sopenharmony_ci (void)local_ip6; 95513498266Sopenharmony_ci return CURLE_NOT_BUILT_IN; 95613498266Sopenharmony_ci#endif 95713498266Sopenharmony_ci} 95813498266Sopenharmony_ci#endif /* CURLRES_ARES */ 959