ares: use ares_getaddrinfo()
ares_getaddrinfo() is the getaddrinfo() cloned provided by c-ares, introduced in version 1.16.0. With older c-ares versions, curl invokes ares_gethostbyname() twice - once for IPv4 and once for IPv6 to resolve both addresses, and then combines the returned results. Reported-by: jjandesmet Fixes #7364 Closes #7552
This commit is contained in:
parent
2bfa57bff1
commit
ba904db070
117
lib/asyn-ares.c
117
lib/asyn-ares.c
@ -86,7 +86,7 @@
|
|||||||
#include "memdebug.h"
|
#include "memdebug.h"
|
||||||
|
|
||||||
struct thread_data {
|
struct thread_data {
|
||||||
int num_pending; /* number of ares_gethostbyname() requests */
|
int num_pending; /* number of outstanding c-ares requests */
|
||||||
struct Curl_addrinfo *temp_ai; /* intermediary result while fetching c-ares
|
struct Curl_addrinfo *temp_ai; /* intermediary result while fetching c-ares
|
||||||
parts */
|
parts */
|
||||||
int last_status;
|
int last_status;
|
||||||
@ -490,6 +490,8 @@ CURLcode Curl_resolver_wait_resolv(struct Curl_easy *data,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ARES_VERSION < 0x011000 /* before 1.16.0 */
|
||||||
|
|
||||||
/* Connects results to the list */
|
/* Connects results to the list */
|
||||||
static void compound_results(struct thread_data *res,
|
static void compound_results(struct thread_data *res,
|
||||||
struct Curl_addrinfo *ai)
|
struct Curl_addrinfo *ai)
|
||||||
@ -620,7 +622,97 @@ static void query_completed_cb(void *arg, /* (struct connectdata *) */
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
/* c-ares 1.16.0 or later */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ares2addr() converts an address list provided by c-ares to an internal
|
||||||
|
* libcurl compatible list
|
||||||
|
*/
|
||||||
|
static struct Curl_addrinfo *ares2addr(struct ares_addrinfo_node *node)
|
||||||
|
{
|
||||||
|
/* traverse the ares_addrinfo_node list */
|
||||||
|
struct ares_addrinfo_node *ai;
|
||||||
|
struct Curl_addrinfo *cafirst = NULL;
|
||||||
|
struct Curl_addrinfo *calast = NULL;
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
|
for(ai = node; ai != NULL; ai = ai->ai_next) {
|
||||||
|
size_t ss_size;
|
||||||
|
struct Curl_addrinfo *ca;
|
||||||
|
/* ignore elements with unsupported address family, */
|
||||||
|
/* settle family-specific sockaddr structure size. */
|
||||||
|
if(ai->ai_family == AF_INET)
|
||||||
|
ss_size = sizeof(struct sockaddr_in);
|
||||||
|
#ifdef ENABLE_IPV6
|
||||||
|
else if(ai->ai_family == AF_INET6)
|
||||||
|
ss_size = sizeof(struct sockaddr_in6);
|
||||||
|
#endif
|
||||||
|
else
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* ignore elements without required address info */
|
||||||
|
if(!ai->ai_addr || !(ai->ai_addrlen > 0))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* ignore elements with bogus address size */
|
||||||
|
if((size_t)ai->ai_addrlen < ss_size)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
ca = malloc(sizeof(struct Curl_addrinfo) + ss_size);
|
||||||
|
if(!ca) {
|
||||||
|
error = EAI_MEMORY;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* copy each structure member individually, member ordering, */
|
||||||
|
/* size, or padding might be different for each platform. */
|
||||||
|
|
||||||
|
ca->ai_flags = ai->ai_flags;
|
||||||
|
ca->ai_family = ai->ai_family;
|
||||||
|
ca->ai_socktype = ai->ai_socktype;
|
||||||
|
ca->ai_protocol = ai->ai_protocol;
|
||||||
|
ca->ai_addrlen = (curl_socklen_t)ss_size;
|
||||||
|
ca->ai_addr = NULL;
|
||||||
|
ca->ai_canonname = NULL;
|
||||||
|
ca->ai_next = NULL;
|
||||||
|
|
||||||
|
ca->ai_addr = (void *)((char *)ca + sizeof(struct Curl_addrinfo));
|
||||||
|
memcpy(ca->ai_addr, ai->ai_addr, ss_size);
|
||||||
|
|
||||||
|
/* if the return list is empty, this becomes the first element */
|
||||||
|
if(!cafirst)
|
||||||
|
cafirst = ca;
|
||||||
|
|
||||||
|
/* add this element last in the return list */
|
||||||
|
if(calast)
|
||||||
|
calast->ai_next = ca;
|
||||||
|
calast = ca;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if we failed, destroy the Curl_addrinfo list */
|
||||||
|
if(error) {
|
||||||
|
Curl_freeaddrinfo(cafirst);
|
||||||
|
cafirst = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cafirst;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void addrinfo_cb(void *arg, int status, int timeouts,
|
||||||
|
struct ares_addrinfo *result)
|
||||||
|
{
|
||||||
|
struct Curl_easy *data = (struct Curl_easy *)arg;
|
||||||
|
struct thread_data *res = data->state.async.tdata;
|
||||||
|
(void)timeouts;
|
||||||
|
if(ARES_SUCCESS == status) {
|
||||||
|
res->temp_ai = ares2addr(result->nodes);
|
||||||
|
res->last_status = CURL_ASYNC_SUCCESS;
|
||||||
|
}
|
||||||
|
res->num_pending--;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
/*
|
/*
|
||||||
* Curl_resolver_getaddrinfo() - when using ares
|
* Curl_resolver_getaddrinfo() - when using ares
|
||||||
*
|
*
|
||||||
@ -658,6 +750,27 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
|
|||||||
/* initial status - failed */
|
/* initial status - failed */
|
||||||
res->last_status = ARES_ENOTFOUND;
|
res->last_status = ARES_ENOTFOUND;
|
||||||
|
|
||||||
|
#if ARES_VERSION >= 0x010601
|
||||||
|
{
|
||||||
|
struct ares_addrinfo_hints hints;
|
||||||
|
char service[12];
|
||||||
|
int pf = PF_INET;
|
||||||
|
memset(&hints, 0, sizeof(hints));
|
||||||
|
#ifdef CURLRES_IPV6
|
||||||
|
if(Curl_ipv6works(data))
|
||||||
|
/* The stack seems to be IPv6-enabled */
|
||||||
|
pf = PF_UNSPEC;
|
||||||
|
#endif /* CURLRES_IPV6 */
|
||||||
|
hints.ai_family = pf;
|
||||||
|
hints.ai_socktype = (data->conn->transport == TRNSPRT_TCP)?
|
||||||
|
SOCK_STREAM : SOCK_DGRAM;
|
||||||
|
msnprintf(service, sizeof(service), "%d", port);
|
||||||
|
res->num_pending = 1;
|
||||||
|
ares_getaddrinfo((ares_channel)data->state.async.resolver, hostname,
|
||||||
|
service, &hints, addrinfo_cb, data);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
|
||||||
#if ARES_VERSION >= 0x010601
|
#if ARES_VERSION >= 0x010601
|
||||||
/* IPv6 supported by c-ares since 1.6.1 */
|
/* IPv6 supported by c-ares since 1.6.1 */
|
||||||
if(Curl_ipv6works(data)) {
|
if(Curl_ipv6works(data)) {
|
||||||
@ -680,7 +793,7 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
|
|||||||
hostname, PF_INET,
|
hostname, PF_INET,
|
||||||
query_completed_cb, data);
|
query_completed_cb, data);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
*waitp = 1; /* expect asynchronous response */
|
*waitp = 1; /* expect asynchronous response */
|
||||||
}
|
}
|
||||||
return NULL; /* no struct yet */
|
return NULL; /* no struct yet */
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user