mirror of
https://github.com/curl/curl.git
synced 2026-08-24 15:23:36 +03:00
CURLOPT_IPRESOLVE: preventing wrong IP version from being used
In some situations, it was possible that a transfer was setup to use an specific IP version, but due do DNS caching or connection reuse, it ended up using a different IP version from requested. This commit changes the effect of CURLOPT_IPRESOLVE from simply restricting address resolution to preventing the wrong connection type being used, when choosing a connection from the pool, and to restricting what addresses could be used when establishing a new connection. It is important that all addresses versions are resolved, even if not used in that transfer in particular, because the result is cached, and could be useful for a different transfer with a different CURLOPT_IPRESOLVE setting. Closes #6853
This commit is contained in:
parent
ac54b10933
commit
84d2839740
11 changed files with 69 additions and 100 deletions
|
|
@ -620,28 +620,9 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
|
|||
int *waitp)
|
||||
{
|
||||
char *bufp;
|
||||
int family = PF_INET;
|
||||
|
||||
*waitp = 0; /* default to synchronous response */
|
||||
|
||||
#ifdef ENABLE_IPV6
|
||||
switch(data->set.ipver) {
|
||||
default:
|
||||
#if ARES_VERSION >= 0x010601
|
||||
family = PF_UNSPEC; /* supported by c-ares since 1.6.1, so for older
|
||||
c-ares versions this just falls through and defaults
|
||||
to PF_INET */
|
||||
break;
|
||||
#endif
|
||||
case CURL_IPRESOLVE_V4:
|
||||
family = PF_INET;
|
||||
break;
|
||||
case CURL_IPRESOLVE_V6:
|
||||
family = PF_INET6;
|
||||
break;
|
||||
}
|
||||
#endif /* ENABLE_IPV6 */
|
||||
|
||||
bufp = strdup(hostname);
|
||||
if(bufp) {
|
||||
struct thread_data *res = NULL;
|
||||
|
|
@ -661,33 +642,27 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
|
|||
|
||||
/* initial status - failed */
|
||||
res->last_status = ARES_ENOTFOUND;
|
||||
#ifdef ENABLE_IPV6
|
||||
if(family == PF_UNSPEC) {
|
||||
if(Curl_ipv6works(data)) {
|
||||
res->num_pending = 2;
|
||||
|
||||
/* areschannel is already setup in the Curl_open() function */
|
||||
ares_gethostbyname((ares_channel)data->state.async.resolver, hostname,
|
||||
PF_INET, query_completed_cb, data);
|
||||
ares_gethostbyname((ares_channel)data->state.async.resolver, hostname,
|
||||
PF_INET6, query_completed_cb, data);
|
||||
}
|
||||
else {
|
||||
res->num_pending = 1;
|
||||
#if ARES_VERSION >= 0x010601
|
||||
/* IPv6 supported by c-ares since 1.6.1 */
|
||||
if(Curl_ipv6works(data)) {
|
||||
/* The stack seems to be IPv6-enabled */
|
||||
res->num_pending = 2;
|
||||
|
||||
/* areschannel is already setup in the Curl_open() function */
|
||||
ares_gethostbyname((ares_channel)data->state.async.resolver, hostname,
|
||||
PF_INET, query_completed_cb, data);
|
||||
}
|
||||
/* areschannel is already setup in the Curl_open() function */
|
||||
ares_gethostbyname((ares_channel)data->state.async.resolver, hostname,
|
||||
PF_INET, query_completed_cb, data);
|
||||
ares_gethostbyname((ares_channel)data->state.async.resolver, hostname,
|
||||
PF_INET6, query_completed_cb, data);
|
||||
}
|
||||
else
|
||||
#endif /* ENABLE_IPV6 */
|
||||
#endif /* ARES_VERSION >= 0x010601 */
|
||||
{
|
||||
res->num_pending = 1;
|
||||
|
||||
/* areschannel is already setup in the Curl_open() function */
|
||||
ares_gethostbyname((ares_channel)data->state.async.resolver,
|
||||
hostname, family,
|
||||
hostname, PF_INET,
|
||||
query_completed_cb, data);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -701,24 +701,9 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
|
|||
*waitp = 0; /* default to synchronous response */
|
||||
|
||||
#ifdef CURLRES_IPV6
|
||||
/*
|
||||
* Check if a limited name resolve has been requested.
|
||||
*/
|
||||
switch(data->set.ipver) {
|
||||
case CURL_IPRESOLVE_V4:
|
||||
pf = PF_INET;
|
||||
break;
|
||||
case CURL_IPRESOLVE_V6:
|
||||
pf = PF_INET6;
|
||||
break;
|
||||
default:
|
||||
if(Curl_ipv6works(data))
|
||||
/* The stack seems to be IPv6-enabled */
|
||||
pf = PF_UNSPEC;
|
||||
break;
|
||||
}
|
||||
|
||||
if((pf != PF_INET) && !Curl_ipv6works(data))
|
||||
/* The stack seems to be a non-IPv6 one */
|
||||
pf = PF_INET;
|
||||
#endif /* CURLRES_IPV6 */
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
|
|
|
|||
|
|
@ -1367,14 +1367,31 @@ CURLcode Curl_connecthost(struct Curl_easy *data,
|
|||
conn->timeoutms_per_addr[1] =
|
||||
conn->tempaddr[1]->ai_next == NULL ? timeout_ms : timeout_ms / 2;
|
||||
|
||||
conn->tempfamily[0] = conn->tempaddr[0]?
|
||||
conn->tempaddr[0]->ai_family:0;
|
||||
if(conn->ip_version == CURL_IPRESOLVE_WHATEVER) {
|
||||
/* any IP version is allowed */
|
||||
conn->tempfamily[0] = conn->tempaddr[0]?
|
||||
conn->tempaddr[0]->ai_family:0;
|
||||
#ifdef ENABLE_IPV6
|
||||
conn->tempfamily[1] = conn->tempfamily[0] == AF_INET6 ?
|
||||
AF_INET : AF_INET6;
|
||||
conn->tempfamily[1] = conn->tempfamily[0] == AF_INET6 ?
|
||||
AF_INET : AF_INET6;
|
||||
#else
|
||||
conn->tempfamily[1] = AF_UNSPEC;
|
||||
conn->tempfamily[1] = AF_UNSPEC;
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
/* only one IP version is allowed */
|
||||
conn->tempfamily[0] = (conn->ip_version == CURL_IPRESOLVE_V4) ?
|
||||
AF_INET :
|
||||
#ifdef ENABLE_IPV6
|
||||
AF_INET6;
|
||||
#else
|
||||
AF_UNSPEC;
|
||||
#endif
|
||||
conn->tempfamily[1] = AF_UNSPEC;
|
||||
|
||||
ainext(conn, 0, FALSE); /* find first address of the right type */
|
||||
}
|
||||
|
||||
ainext(conn, 1, FALSE); /* assigns conn->tempaddr[1] accordingly */
|
||||
|
||||
DEBUGF(infof(data, "family0 == %s, family1 == %s\n",
|
||||
|
|
|
|||
18
lib/doh.c
18
lib/doh.c
|
|
@ -420,17 +420,15 @@ struct Curl_addrinfo *Curl_doh(struct Curl_easy *data,
|
|||
if(!dohp->headers)
|
||||
goto error;
|
||||
|
||||
if(conn->ip_version != CURL_IPRESOLVE_V6) {
|
||||
/* create IPv4 DOH request */
|
||||
result = dohprobe(data, &dohp->probe[DOH_PROBE_SLOT_IPADDR_V4],
|
||||
DNS_TYPE_A, hostname, data->set.str[STRING_DOH],
|
||||
data->multi, dohp->headers);
|
||||
if(result)
|
||||
goto error;
|
||||
dohp->pending++;
|
||||
}
|
||||
/* create IPv4 DOH request */
|
||||
result = dohprobe(data, &dohp->probe[DOH_PROBE_SLOT_IPADDR_V4],
|
||||
DNS_TYPE_A, hostname, data->set.str[STRING_DOH],
|
||||
data->multi, dohp->headers);
|
||||
if(result)
|
||||
goto error;
|
||||
dohp->pending++;
|
||||
|
||||
if(conn->ip_version != CURL_IPRESOLVE_V4) {
|
||||
if(Curl_ipv6works(data)) {
|
||||
/* create IPv6 DOH request */
|
||||
result = dohprobe(data, &dohp->probe[DOH_PROBE_SLOT_IPADDR_V6],
|
||||
DNS_TYPE_AAAA, hostname, data->set.str[STRING_DOH],
|
||||
|
|
|
|||
|
|
@ -140,26 +140,13 @@ struct Curl_addrinfo *Curl_getaddrinfo(struct Curl_easy *data,
|
|||
#ifndef USE_RESOLVE_ON_IPS
|
||||
char addrbuf[128];
|
||||
#endif
|
||||
int pf;
|
||||
int pf = PF_INET;
|
||||
|
||||
*waitp = 0; /* synchronous response only */
|
||||
|
||||
/* Check if a limited name resolve has been requested */
|
||||
switch(data->set.ipver) {
|
||||
case CURL_IPRESOLVE_V4:
|
||||
pf = PF_INET;
|
||||
break;
|
||||
case CURL_IPRESOLVE_V6:
|
||||
pf = PF_INET6;
|
||||
break;
|
||||
default:
|
||||
if(Curl_ipv6works(data))
|
||||
/* The stack seems to be IPv6-enabled */
|
||||
pf = PF_UNSPEC;
|
||||
break;
|
||||
}
|
||||
|
||||
if((pf != PF_INET) && !Curl_ipv6works(data))
|
||||
/* The stack seems to be a non-IPv6 one */
|
||||
pf = PF_INET;
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = pf;
|
||||
|
|
|
|||
|
|
@ -1172,6 +1172,12 @@ ConnectionExists(struct Curl_easy *data,
|
|||
continue;
|
||||
}
|
||||
|
||||
if(data->set.ipver != CURL_IPRESOLVE_WHATEVER
|
||||
&& data->set.ipver != check->ip_version) {
|
||||
/* skip because the connection is not via the requested IP version */
|
||||
continue;
|
||||
}
|
||||
|
||||
if(bundle->multiuse == BUNDLE_MULTIPLEX)
|
||||
multiplexed = CONN_INUSE(check);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue