mirror of
https://github.com/curl/curl.git
synced 2025-09-10 22:22:43 +03:00
hostip: make CURLOPT_RESOLVE support replacing IPv6 addresses
This also applies to --resolve of course. Applied strparse functions on the function. Fixes #16357 Reported-by: rmg-x on github Closes #16358 Assisted-by: Jay Satiro
This commit is contained in:
parent
61f85bf967
commit
2f4dc6525c
|
@ -12,6 +12,7 @@ See-also:
|
||||||
- alt-svc
|
- alt-svc
|
||||||
Example:
|
Example:
|
||||||
- --resolve example.com:443:127.0.0.1 $URL
|
- --resolve example.com:443:127.0.0.1 $URL
|
||||||
|
- --resolve example.com:443:[2001:db8::252f:efd6] $URL
|
||||||
---
|
---
|
||||||
|
|
||||||
# `--resolve`
|
# `--resolve`
|
||||||
|
@ -20,8 +21,8 @@ Provide a custom address for a specific host and port pair. Using this, you
|
||||||
can make the curl requests(s) use a specified address and prevent the
|
can make the curl requests(s) use a specified address and prevent the
|
||||||
otherwise normally resolved address to be used. Consider it a sort of
|
otherwise normally resolved address to be used. Consider it a sort of
|
||||||
/etc/hosts alternative provided on the command line. The port number should be
|
/etc/hosts alternative provided on the command line. The port number should be
|
||||||
the number used for the specific protocol the host is used for. It means
|
the number used for the specific protocol the host is used for. It means you
|
||||||
you need several entries if you want to provide address for the same host but
|
need several entries if you want to provide addresses for the same host but
|
||||||
different ports.
|
different ports.
|
||||||
|
|
||||||
By specifying `*` as host you can tell curl to resolve any host and specific
|
By specifying `*` as host you can tell curl to resolve any host and specific
|
||||||
|
@ -37,9 +38,13 @@ parallel transfers with a lot of files. In such cases, if this option is used
|
||||||
curl tries to resolve the host as it normally would once the timeout has
|
curl tries to resolve the host as it normally would once the timeout has
|
||||||
expired.
|
expired.
|
||||||
|
|
||||||
|
Provide IPv6 addresses within [brackets].
|
||||||
|
|
||||||
To redirect connects from a specific hostname or any hostname, independently
|
To redirect connects from a specific hostname or any hostname, independently
|
||||||
of port number, consider the --connect-to option.
|
of port number, consider the --connect-to option.
|
||||||
|
|
||||||
Support for resolving with wildcard was added in 7.64.0.
|
Support for resolving with wildcard was added in 7.64.0.
|
||||||
|
|
||||||
Support for the '+' prefix was added in 7.75.0.
|
Support for the '+' prefix was added in 7.75.0.
|
||||||
|
|
||||||
|
Support for specifying the host component as an IPv6 address was added in 8.13.0.
|
||||||
|
|
|
@ -73,6 +73,8 @@ resolves, include a string in the linked list that uses the format
|
||||||
The entry to remove must be prefixed with a dash, and the hostname and port
|
The entry to remove must be prefixed with a dash, and the hostname and port
|
||||||
number must exactly match what was added previously.
|
number must exactly match what was added previously.
|
||||||
|
|
||||||
|
Provide IPv6 addresses within [brackets].
|
||||||
|
|
||||||
Using this option multiple times makes the last set list override the previous
|
Using this option multiple times makes the last set list override the previous
|
||||||
ones. Set it to NULL to disable its use again.
|
ones. Set it to NULL to disable its use again.
|
||||||
|
|
||||||
|
@ -90,6 +92,7 @@ int main(void)
|
||||||
CURL *curl;
|
CURL *curl;
|
||||||
struct curl_slist *host = NULL;
|
struct curl_slist *host = NULL;
|
||||||
host = curl_slist_append(NULL, "example.com:443:127.0.0.1");
|
host = curl_slist_append(NULL, "example.com:443:127.0.0.1");
|
||||||
|
host = curl_slist_append(host, "example.com:443:[2001:db8::252f:efd6]");
|
||||||
|
|
||||||
curl = curl_easy_init();
|
curl = curl_easy_init();
|
||||||
if(curl) {
|
if(curl) {
|
||||||
|
@ -117,6 +120,8 @@ Support for providing multiple IP addresses per entry was added in 7.59.0.
|
||||||
Support for adding non-permanent entries by using the "+" prefix was added in
|
Support for adding non-permanent entries by using the "+" prefix was added in
|
||||||
7.75.0.
|
7.75.0.
|
||||||
|
|
||||||
|
Support for specifying the host component as an IPv6 address was added in 8.13.0.
|
||||||
|
|
||||||
# %AVAILABILITY%
|
# %AVAILABILITY%
|
||||||
|
|
||||||
# RETURN VALUE
|
# RETURN VALUE
|
||||||
|
|
144
lib/hostip.c
144
lib/hostip.c
|
@ -1124,43 +1124,46 @@ void Curl_hostcache_clean(struct Curl_easy *data,
|
||||||
CURLcode Curl_loadhostpairs(struct Curl_easy *data)
|
CURLcode Curl_loadhostpairs(struct Curl_easy *data)
|
||||||
{
|
{
|
||||||
struct curl_slist *hostp;
|
struct curl_slist *hostp;
|
||||||
const char *host_end;
|
|
||||||
|
|
||||||
/* Default is no wildcard found */
|
/* Default is no wildcard found */
|
||||||
data->state.wildcard_resolve = FALSE;
|
data->state.wildcard_resolve = FALSE;
|
||||||
|
|
||||||
for(hostp = data->state.resolve; hostp; hostp = hostp->next) {
|
for(hostp = data->state.resolve; hostp; hostp = hostp->next) {
|
||||||
char entry_id[MAX_HOSTCACHE_LEN];
|
char entry_id[MAX_HOSTCACHE_LEN];
|
||||||
if(!hostp->data)
|
const char *host = hostp->data;
|
||||||
|
struct Curl_str source;
|
||||||
|
if(!host)
|
||||||
continue;
|
continue;
|
||||||
if(hostp->data[0] == '-') {
|
if(*host == '-') {
|
||||||
curl_off_t num = 0;
|
curl_off_t num = 0;
|
||||||
size_t entry_len;
|
size_t entry_len;
|
||||||
size_t hlen = 0;
|
host++;
|
||||||
host_end = strchr(&hostp->data[1], ':');
|
if(!Curl_str_single(&host, '[')) {
|
||||||
|
if(Curl_str_until(&host, &source, MAX_IPADR_LEN, ']') ||
|
||||||
if(host_end) {
|
Curl_str_single(&host, ']') ||
|
||||||
hlen = host_end - &hostp->data[1];
|
Curl_str_single(&host, ':'))
|
||||||
host_end++;
|
continue;
|
||||||
if(Curl_str_number(&host_end, &num, 0xffff))
|
|
||||||
host_end = NULL;
|
|
||||||
}
|
}
|
||||||
if(!host_end) {
|
else {
|
||||||
infof(data, "Bad syntax CURLOPT_RESOLVE removal entry '%s'",
|
if(Curl_str_until(&host, &source, 4096, ':') ||
|
||||||
hostp->data);
|
Curl_str_single(&host, ':')) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/* Create an entry id, based upon the hostname and port */
|
|
||||||
entry_len = create_hostcache_id(&hostp->data[1], hlen, (int)num,
|
|
||||||
entry_id, sizeof(entry_id));
|
|
||||||
if(data->share)
|
|
||||||
Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
|
|
||||||
|
|
||||||
/* delete entry, ignore if it did not exist */
|
if(!Curl_str_number(&host, &num, 0xffff)) {
|
||||||
Curl_hash_delete(data->dns.hostcache, entry_id, entry_len + 1);
|
/* Create an entry id, based upon the hostname and port */
|
||||||
|
entry_len = create_hostcache_id(source.str, source.len, (int)num,
|
||||||
|
entry_id, sizeof(entry_id));
|
||||||
|
if(data->share)
|
||||||
|
Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
|
||||||
|
|
||||||
if(data->share)
|
/* delete entry, ignore if it did not exist */
|
||||||
Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
|
Curl_hash_delete(data->dns.hostcache, entry_id, entry_len + 1);
|
||||||
|
|
||||||
|
if(data->share)
|
||||||
|
Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
struct Curl_dns_entry *dns;
|
struct Curl_dns_entry *dns;
|
||||||
|
@ -1170,71 +1173,66 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
|
||||||
#if !defined(CURL_DISABLE_VERBOSE_STRINGS)
|
#if !defined(CURL_DISABLE_VERBOSE_STRINGS)
|
||||||
const char *addresses = NULL;
|
const char *addresses = NULL;
|
||||||
#endif
|
#endif
|
||||||
const char *addr_begin;
|
|
||||||
const char *addr_end;
|
|
||||||
const char *port_ptr;
|
|
||||||
curl_off_t port = 0;
|
curl_off_t port = 0;
|
||||||
const char *end_ptr;
|
|
||||||
bool permanent = TRUE;
|
bool permanent = TRUE;
|
||||||
bool error = TRUE;
|
bool error = TRUE;
|
||||||
char *host_begin = hostp->data;
|
|
||||||
size_t hlen = 0;
|
|
||||||
|
|
||||||
if(host_begin[0] == '+') {
|
if(*host == '+') {
|
||||||
host_begin++;
|
host++;
|
||||||
permanent = FALSE;
|
permanent = FALSE;
|
||||||
}
|
}
|
||||||
host_end = strchr(host_begin, ':');
|
if(!Curl_str_single(&host, '[')) {
|
||||||
if(!host_end)
|
if(Curl_str_until(&host, &source, MAX_IPADR_LEN, ']') ||
|
||||||
|
Curl_str_single(&host, ']'))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if(Curl_str_until(&host, &source, 4096, ':'))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(Curl_str_single(&host, ':') ||
|
||||||
|
Curl_str_number(&host, &port, 0xffff) ||
|
||||||
|
Curl_str_single(&host, ':'))
|
||||||
goto err;
|
goto err;
|
||||||
hlen = host_end - host_begin;
|
|
||||||
|
|
||||||
port_ptr = host_end + 1;
|
|
||||||
if(Curl_str_number(&port_ptr, &port, 0xffff) ||
|
|
||||||
(*port_ptr != ':'))
|
|
||||||
goto err;
|
|
||||||
end_ptr = port_ptr;
|
|
||||||
|
|
||||||
#if !defined(CURL_DISABLE_VERBOSE_STRINGS)
|
#if !defined(CURL_DISABLE_VERBOSE_STRINGS)
|
||||||
addresses = end_ptr + 1;
|
addresses = host;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
while(*end_ptr) {
|
/* start the address section */
|
||||||
size_t alen;
|
while(*host) {
|
||||||
|
struct Curl_str target;
|
||||||
struct Curl_addrinfo *ai;
|
struct Curl_addrinfo *ai;
|
||||||
|
|
||||||
addr_begin = end_ptr + 1;
|
if(!Curl_str_single(&host, '[')) {
|
||||||
addr_end = strchr(addr_begin, ',');
|
if(Curl_str_until(&host, &target, MAX_IPADR_LEN, ']') ||
|
||||||
if(!addr_end)
|
Curl_str_single(&host, ']'))
|
||||||
addr_end = addr_begin + strlen(addr_begin);
|
|
||||||
end_ptr = addr_end;
|
|
||||||
|
|
||||||
/* allow IP(v6) address within [brackets] */
|
|
||||||
if(*addr_begin == '[') {
|
|
||||||
if(addr_end == addr_begin || *(addr_end - 1) != ']')
|
|
||||||
goto err;
|
goto err;
|
||||||
++addr_begin;
|
|
||||||
--addr_end;
|
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
alen = addr_end - addr_begin;
|
if(Curl_str_until(&host, &target, 4096, ',')) {
|
||||||
if(!alen)
|
if(Curl_str_single(&host, ','))
|
||||||
continue;
|
goto err;
|
||||||
|
/* survive nothing but just a comma */
|
||||||
if(alen >= sizeof(address))
|
continue;
|
||||||
goto err;
|
}
|
||||||
|
}
|
||||||
memcpy(address, addr_begin, alen);
|
|
||||||
address[alen] = '\0';
|
|
||||||
|
|
||||||
#ifndef USE_IPV6
|
#ifndef USE_IPV6
|
||||||
if(strchr(address, ':')) {
|
if(memchr(target.str, ':', target.len)) {
|
||||||
infof(data, "Ignoring resolve address '%s', missing IPv6 support.",
|
infof(data, "Ignoring resolve address '%s', missing IPv6 support.",
|
||||||
address);
|
address);
|
||||||
|
if(Curl_str_single(&host, ','))
|
||||||
|
goto err;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if(target.len >= sizeof(address))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
memcpy(address, target.str, target.len);
|
||||||
|
address[target.len] = '\0';
|
||||||
|
|
||||||
ai = Curl_str2addr(address, (int)port);
|
ai = Curl_str2addr(address, (int)port);
|
||||||
if(!ai) {
|
if(!ai) {
|
||||||
infof(data, "Resolve address '%s' found illegal", address);
|
infof(data, "Resolve address '%s' found illegal", address);
|
||||||
|
@ -1248,6 +1246,8 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
|
||||||
else {
|
else {
|
||||||
head = tail = ai;
|
head = tail = ai;
|
||||||
}
|
}
|
||||||
|
if(Curl_str_single(&host, ','))
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!head)
|
if(!head)
|
||||||
|
@ -1263,7 +1263,7 @@ err:
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create an entry id, based upon the hostname and port */
|
/* Create an entry id, based upon the hostname and port */
|
||||||
entry_len = create_hostcache_id(host_begin, hlen, (int)port,
|
entry_len = create_hostcache_id(source.str, source.len, (int)port,
|
||||||
entry_id, sizeof(entry_id));
|
entry_id, sizeof(entry_id));
|
||||||
|
|
||||||
if(data->share)
|
if(data->share)
|
||||||
|
@ -1274,7 +1274,7 @@ err:
|
||||||
|
|
||||||
if(dns) {
|
if(dns) {
|
||||||
infof(data, "RESOLVE %.*s:%" CURL_FORMAT_CURL_OFF_T
|
infof(data, "RESOLVE %.*s:%" CURL_FORMAT_CURL_OFF_T
|
||||||
" - old addresses discarded", (int)hlen, host_begin, port);
|
" - old addresses discarded", (int)source.len, source.str, port);
|
||||||
/* delete old entry, there are two reasons for this
|
/* delete old entry, there are two reasons for this
|
||||||
1. old entry may have different addresses.
|
1. old entry may have different addresses.
|
||||||
2. even if entry with correct addresses is already in the cache,
|
2. even if entry with correct addresses is already in the cache,
|
||||||
|
@ -1290,7 +1290,7 @@ err:
|
||||||
}
|
}
|
||||||
|
|
||||||
/* put this new host in the cache */
|
/* put this new host in the cache */
|
||||||
dns = Curl_cache_addr(data, head, host_begin, hlen, (int)port,
|
dns = Curl_cache_addr(data, head, source.str, source.len, (int)port,
|
||||||
permanent);
|
permanent);
|
||||||
if(dns) {
|
if(dns) {
|
||||||
/* release the returned reference; the cache itself will keep the
|
/* release the returned reference; the cache itself will keep the
|
||||||
|
@ -1307,12 +1307,12 @@ err:
|
||||||
}
|
}
|
||||||
#ifndef CURL_DISABLE_VERBOSE_STRINGS
|
#ifndef CURL_DISABLE_VERBOSE_STRINGS
|
||||||
infof(data, "Added %.*s:%" CURL_FORMAT_CURL_OFF_T ":%s to DNS cache%s",
|
infof(data, "Added %.*s:%" CURL_FORMAT_CURL_OFF_T ":%s to DNS cache%s",
|
||||||
(int)hlen, host_begin, port, addresses,
|
(int)source.len, source.str, port, addresses,
|
||||||
permanent ? "" : " (non-permanent)");
|
permanent ? "" : " (non-permanent)");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Wildcard hostname */
|
/* Wildcard hostname */
|
||||||
if((hlen == 1) && (host_begin[0] == '*')) {
|
if((source.len == 1) && (source.str[0] == '*')) {
|
||||||
infof(data, "RESOLVE *:%" CURL_FORMAT_CURL_OFF_T " using wildcard",
|
infof(data, "RESOLVE *:%" CURL_FORMAT_CURL_OFF_T " using wildcard",
|
||||||
port);
|
port);
|
||||||
data->state.wildcard_resolve = TRUE;
|
data->state.wildcard_resolve = TRUE;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user