mirror of
https://github.com/moparisthebest/curl
synced 2024-08-13 17:03:50 -04: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
@ -494,7 +494,7 @@ Timeout for the connection phase. See \fICURLOPT_CONNECTTIMEOUT(3)\fP
|
|||||||
.IP CURLOPT_CONNECTTIMEOUT_MS
|
.IP CURLOPT_CONNECTTIMEOUT_MS
|
||||||
Millisecond timeout for the connection phase. See \fICURLOPT_CONNECTTIMEOUT_MS(3)\fP
|
Millisecond timeout for the connection phase. See \fICURLOPT_CONNECTTIMEOUT_MS(3)\fP
|
||||||
.IP CURLOPT_IPRESOLVE
|
.IP CURLOPT_IPRESOLVE
|
||||||
IP version to resolve to. See \fICURLOPT_IPRESOLVE(3)\fP
|
IP version to use. See \fICURLOPT_IPRESOLVE(3)\fP
|
||||||
.IP CURLOPT_CONNECT_ONLY
|
.IP CURLOPT_CONNECT_ONLY
|
||||||
Only connect, nothing else. See \fICURLOPT_CONNECT_ONLY(3)\fP
|
Only connect, nothing else. See \fICURLOPT_CONNECT_ONLY(3)\fP
|
||||||
.IP CURLOPT_USE_SSL
|
.IP CURLOPT_USE_SSL
|
||||||
|
@ -29,14 +29,15 @@ CURLOPT_IPRESOLVE \- specify which IP protocol version to use
|
|||||||
CURLcode curl_easy_setopt(CURL *handle, CURLOPT_IPRESOLVE, long resolve);
|
CURLcode curl_easy_setopt(CURL *handle, CURLOPT_IPRESOLVE, long resolve);
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
Allows an application to select what kind of IP addresses to use when
|
Allows an application to select what kind of IP addresses to use when
|
||||||
resolving host names. This is only interesting when using host names that
|
establishing a connection or choosing one from the connection pool. This is
|
||||||
resolve addresses using more than one version of IP. The allowed values are:
|
interesting when using host names that resolve addresses using more than
|
||||||
|
one version of IP. The allowed values are:
|
||||||
.IP CURL_IPRESOLVE_WHATEVER
|
.IP CURL_IPRESOLVE_WHATEVER
|
||||||
Default, resolves addresses to all IP versions that your system allows.
|
Default, can use addresses of all IP versions that your system allows.
|
||||||
.IP CURL_IPRESOLVE_V4
|
.IP CURL_IPRESOLVE_V4
|
||||||
Resolve to IPv4 addresses.
|
Uses only IPv4 addresses.
|
||||||
.IP CURL_IPRESOLVE_V6
|
.IP CURL_IPRESOLVE_V6
|
||||||
Resolve to IPv6 addresses.
|
Uses only IPv6 addresses.
|
||||||
.SH DEFAULT
|
.SH DEFAULT
|
||||||
CURL_IPRESOLVE_WHATEVER
|
CURL_IPRESOLVE_WHATEVER
|
||||||
.SH PROTOCOLS
|
.SH PROTOCOLS
|
||||||
@ -47,7 +48,7 @@ CURL *curl = curl_easy_init();
|
|||||||
if(curl) {
|
if(curl) {
|
||||||
curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/foo.bin");
|
curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/foo.bin");
|
||||||
|
|
||||||
/* resolve host name using IPv6-names only */
|
/* of all addresses example.com resolves to, only IPv6 ones are used */
|
||||||
curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6);
|
curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6);
|
||||||
|
|
||||||
ret = curl_easy_perform(curl);
|
ret = curl_easy_perform(curl);
|
||||||
|
@ -57,8 +57,8 @@ this entry will be removed and a new entry will be created. This is because
|
|||||||
the old entry may have have different addresses or a different time-out
|
the old entry may have have different addresses or a different time-out
|
||||||
setting.
|
setting.
|
||||||
|
|
||||||
The provided ADDRESS set by this option will be used even if
|
An ADDRESS provided by this option will only be use if not restricted by
|
||||||
\fICURLOPT_IPRESOLVE(3)\fP is set to make libcurl use another IP version.
|
the setting of \fICURLOPT_IPRESOLVE(3)\fP to a different IP version.
|
||||||
|
|
||||||
Remove names from the DNS cache again, to stop providing these fake resolves,
|
Remove names from the DNS cache again, to stop providing these fake resolves,
|
||||||
by including a string in the linked list that uses the format
|
by including a string in the linked list that uses the format
|
||||||
|
@ -1466,8 +1466,8 @@ typedef enum {
|
|||||||
#define CURLOPT_SERVER_RESPONSE_TIMEOUT CURLOPT_FTP_RESPONSE_TIMEOUT
|
#define CURLOPT_SERVER_RESPONSE_TIMEOUT CURLOPT_FTP_RESPONSE_TIMEOUT
|
||||||
|
|
||||||
/* Set this option to one of the CURL_IPRESOLVE_* defines (see below) to
|
/* Set this option to one of the CURL_IPRESOLVE_* defines (see below) to
|
||||||
tell libcurl to resolve names to those IP versions only. This only has
|
tell libcurl to use those IP versions only. This only has effect on
|
||||||
affect on systems with support for more than one, i.e IPv4 _and_ IPv6. */
|
systems with support for more than one, i.e IPv4 _and_ IPv6. */
|
||||||
CURLOPT(CURLOPT_IPRESOLVE, CURLOPTTYPE_VALUES, 113),
|
CURLOPT(CURLOPT_IPRESOLVE, CURLOPTTYPE_VALUES, 113),
|
||||||
|
|
||||||
/* Set this option to limit the size of a file that will be downloaded from
|
/* Set this option to limit the size of a file that will be downloaded from
|
||||||
@ -2135,10 +2135,10 @@ typedef enum {
|
|||||||
/* Below here follows defines for the CURLOPT_IPRESOLVE option. If a host
|
/* Below here follows defines for the CURLOPT_IPRESOLVE option. If a host
|
||||||
name resolves addresses using more than one IP protocol version, this
|
name resolves addresses using more than one IP protocol version, this
|
||||||
option might be handy to force libcurl to use a specific IP version. */
|
option might be handy to force libcurl to use a specific IP version. */
|
||||||
#define CURL_IPRESOLVE_WHATEVER 0 /* default, resolves addresses to all IP
|
#define CURL_IPRESOLVE_WHATEVER 0 /* default, uses addresses to all IP
|
||||||
versions that your system allows */
|
versions that your system allows */
|
||||||
#define CURL_IPRESOLVE_V4 1 /* resolve to IPv4 addresses */
|
#define CURL_IPRESOLVE_V4 1 /* uses only IPv4 addresses/connections */
|
||||||
#define CURL_IPRESOLVE_V6 2 /* resolve to IPv6 addresses */
|
#define CURL_IPRESOLVE_V6 2 /* uses only IPv6 addresses/connections */
|
||||||
|
|
||||||
/* three convenient "aliases" that follow the name scheme better */
|
/* three convenient "aliases" that follow the name scheme better */
|
||||||
#define CURLOPT_RTSPHEADER CURLOPT_HTTPHEADER
|
#define CURLOPT_RTSPHEADER CURLOPT_HTTPHEADER
|
||||||
|
@ -620,28 +620,9 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
|
|||||||
int *waitp)
|
int *waitp)
|
||||||
{
|
{
|
||||||
char *bufp;
|
char *bufp;
|
||||||
int family = PF_INET;
|
|
||||||
|
|
||||||
*waitp = 0; /* default to synchronous response */
|
*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);
|
bufp = strdup(hostname);
|
||||||
if(bufp) {
|
if(bufp) {
|
||||||
struct thread_data *res = NULL;
|
struct thread_data *res = NULL;
|
||||||
@ -661,9 +642,11 @@ 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;
|
||||||
#ifdef ENABLE_IPV6
|
|
||||||
if(family == PF_UNSPEC) {
|
#if ARES_VERSION >= 0x010601
|
||||||
|
/* IPv6 supported by c-ares since 1.6.1 */
|
||||||
if(Curl_ipv6works(data)) {
|
if(Curl_ipv6works(data)) {
|
||||||
|
/* The stack seems to be IPv6-enabled */
|
||||||
res->num_pending = 2;
|
res->num_pending = 2;
|
||||||
|
|
||||||
/* areschannel is already setup in the Curl_open() function */
|
/* areschannel is already setup in the Curl_open() function */
|
||||||
@ -672,22 +655,14 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
|
|||||||
ares_gethostbyname((ares_channel)data->state.async.resolver, hostname,
|
ares_gethostbyname((ares_channel)data->state.async.resolver, hostname,
|
||||||
PF_INET6, query_completed_cb, data);
|
PF_INET6, query_completed_cb, data);
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
res->num_pending = 1;
|
|
||||||
|
|
||||||
/* areschannel is already setup in the Curl_open() function */
|
|
||||||
ares_gethostbyname((ares_channel)data->state.async.resolver, hostname,
|
|
||||||
PF_INET, query_completed_cb, data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
#endif /* ENABLE_IPV6 */
|
#endif /* ARES_VERSION >= 0x010601 */
|
||||||
{
|
{
|
||||||
res->num_pending = 1;
|
res->num_pending = 1;
|
||||||
|
|
||||||
/* areschannel is already setup in the Curl_open() function */
|
/* areschannel is already setup in the Curl_open() function */
|
||||||
ares_gethostbyname((ares_channel)data->state.async.resolver,
|
ares_gethostbyname((ares_channel)data->state.async.resolver,
|
||||||
hostname, family,
|
hostname, PF_INET,
|
||||||
query_completed_cb, data);
|
query_completed_cb, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -701,24 +701,9 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
|
|||||||
*waitp = 0; /* default to synchronous response */
|
*waitp = 0; /* default to synchronous response */
|
||||||
|
|
||||||
#ifdef CURLRES_IPV6
|
#ifdef CURLRES_IPV6
|
||||||
/*
|
if(Curl_ipv6works(data))
|
||||||
* Check if a limited name resolve has been requested.
|
/* The stack seems to be IPv6-enabled */
|
||||||
*/
|
|
||||||
switch(data->set.ipver) {
|
|
||||||
case CURL_IPRESOLVE_V4:
|
|
||||||
pf = PF_INET;
|
|
||||||
break;
|
|
||||||
case CURL_IPRESOLVE_V6:
|
|
||||||
pf = PF_INET6;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
pf = PF_UNSPEC;
|
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 */
|
#endif /* CURLRES_IPV6 */
|
||||||
|
|
||||||
memset(&hints, 0, sizeof(hints));
|
memset(&hints, 0, sizeof(hints));
|
||||||
|
@ -1367,6 +1367,8 @@ CURLcode Curl_connecthost(struct Curl_easy *data,
|
|||||||
conn->timeoutms_per_addr[1] =
|
conn->timeoutms_per_addr[1] =
|
||||||
conn->tempaddr[1]->ai_next == NULL ? timeout_ms : timeout_ms / 2;
|
conn->tempaddr[1]->ai_next == NULL ? timeout_ms : timeout_ms / 2;
|
||||||
|
|
||||||
|
if(conn->ip_version == CURL_IPRESOLVE_WHATEVER) {
|
||||||
|
/* any IP version is allowed */
|
||||||
conn->tempfamily[0] = conn->tempaddr[0]?
|
conn->tempfamily[0] = conn->tempaddr[0]?
|
||||||
conn->tempaddr[0]->ai_family:0;
|
conn->tempaddr[0]->ai_family:0;
|
||||||
#ifdef ENABLE_IPV6
|
#ifdef ENABLE_IPV6
|
||||||
@ -1375,6 +1377,21 @@ CURLcode Curl_connecthost(struct Curl_easy *data,
|
|||||||
#else
|
#else
|
||||||
conn->tempfamily[1] = AF_UNSPEC;
|
conn->tempfamily[1] = AF_UNSPEC;
|
||||||
#endif
|
#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 */
|
ainext(conn, 1, FALSE); /* assigns conn->tempaddr[1] accordingly */
|
||||||
|
|
||||||
DEBUGF(infof(data, "family0 == %s, family1 == %s\n",
|
DEBUGF(infof(data, "family0 == %s, family1 == %s\n",
|
||||||
|
@ -420,7 +420,6 @@ struct Curl_addrinfo *Curl_doh(struct Curl_easy *data,
|
|||||||
if(!dohp->headers)
|
if(!dohp->headers)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
if(conn->ip_version != CURL_IPRESOLVE_V6) {
|
|
||||||
/* create IPv4 DOH request */
|
/* create IPv4 DOH request */
|
||||||
result = dohprobe(data, &dohp->probe[DOH_PROBE_SLOT_IPADDR_V4],
|
result = dohprobe(data, &dohp->probe[DOH_PROBE_SLOT_IPADDR_V4],
|
||||||
DNS_TYPE_A, hostname, data->set.str[STRING_DOH],
|
DNS_TYPE_A, hostname, data->set.str[STRING_DOH],
|
||||||
@ -428,9 +427,8 @@ struct Curl_addrinfo *Curl_doh(struct Curl_easy *data,
|
|||||||
if(result)
|
if(result)
|
||||||
goto error;
|
goto error;
|
||||||
dohp->pending++;
|
dohp->pending++;
|
||||||
}
|
|
||||||
|
|
||||||
if(conn->ip_version != CURL_IPRESOLVE_V4) {
|
if(Curl_ipv6works(data)) {
|
||||||
/* create IPv6 DOH request */
|
/* create IPv6 DOH request */
|
||||||
result = dohprobe(data, &dohp->probe[DOH_PROBE_SLOT_IPADDR_V6],
|
result = dohprobe(data, &dohp->probe[DOH_PROBE_SLOT_IPADDR_V6],
|
||||||
DNS_TYPE_AAAA, hostname, data->set.str[STRING_DOH],
|
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
|
#ifndef USE_RESOLVE_ON_IPS
|
||||||
char addrbuf[128];
|
char addrbuf[128];
|
||||||
#endif
|
#endif
|
||||||
int pf;
|
int pf = PF_INET;
|
||||||
|
|
||||||
*waitp = 0; /* synchronous response only */
|
*waitp = 0; /* synchronous response only */
|
||||||
|
|
||||||
/* Check if a limited name resolve has been requested */
|
if(Curl_ipv6works(data))
|
||||||
switch(data->set.ipver) {
|
/* The stack seems to be IPv6-enabled */
|
||||||
case CURL_IPRESOLVE_V4:
|
|
||||||
pf = PF_INET;
|
|
||||||
break;
|
|
||||||
case CURL_IPRESOLVE_V6:
|
|
||||||
pf = PF_INET6;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
pf = PF_UNSPEC;
|
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));
|
memset(&hints, 0, sizeof(hints));
|
||||||
hints.ai_family = pf;
|
hints.ai_family = pf;
|
||||||
|
@ -1172,6 +1172,12 @@ ConnectionExists(struct Curl_easy *data,
|
|||||||
continue;
|
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)
|
if(bundle->multiuse == BUNDLE_MULTIPLEX)
|
||||||
multiplexed = CONN_INUSE(check);
|
multiplexed = CONN_INUSE(check);
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ http
|
|||||||
HTTP GET with localhost --interface
|
HTTP GET with localhost --interface
|
||||||
</name>
|
</name>
|
||||||
<command>
|
<command>
|
||||||
http://%HOSTIP:%HTTPPORT/%TESTNUMBER -4 --interface localhost
|
http://%HOSTIP:%HTTPPORT/%TESTNUMBER -4 --interface 127.0.0.1
|
||||||
</command>
|
</command>
|
||||||
<precheck>
|
<precheck>
|
||||||
perl -e "print 'Test requires default test client host address' if ( '%CLIENTIP' ne '127.0.0.1' );"
|
perl -e "print 'Test requires default test client host address' if ( '%CLIENTIP' ne '127.0.0.1' );"
|
||||||
|
Loading…
Reference in New Issue
Block a user