mirror of
https://github.com/curl/curl.git
synced 2025-09-10 14:12:41 +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
|
||||
Example:
|
||||
- --resolve example.com:443:127.0.0.1 $URL
|
||||
- --resolve example.com:443:[2001:db8::252f:efd6] $URL
|
||||
---
|
||||
|
||||
# `--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
|
||||
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
|
||||
the number used for the specific protocol the host is used for. It means
|
||||
you need several entries if you want to provide address for the same host but
|
||||
the number used for the specific protocol the host is used for. It means you
|
||||
need several entries if you want to provide addresses for the same host but
|
||||
different ports.
|
||||
|
||||
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
|
||||
expired.
|
||||
|
||||
Provide IPv6 addresses within [brackets].
|
||||
|
||||
To redirect connects from a specific hostname or any hostname, independently
|
||||
of port number, consider the --connect-to option.
|
||||
|
||||
Support for resolving with wildcard was added in 7.64.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
|
||||
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
|
||||
ones. Set it to NULL to disable its use again.
|
||||
|
||||
|
@ -90,6 +92,7 @@ int main(void)
|
|||
CURL *curl;
|
||||
struct curl_slist *host = NULL;
|
||||
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();
|
||||
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
|
||||
7.75.0.
|
||||
|
||||
Support for specifying the host component as an IPv6 address was added in 8.13.0.
|
||||
|
||||
# %AVAILABILITY%
|
||||
|
||||
# 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)
|
||||
{
|
||||
struct curl_slist *hostp;
|
||||
const char *host_end;
|
||||
|
||||
/* Default is no wildcard found */
|
||||
data->state.wildcard_resolve = FALSE;
|
||||
|
||||
for(hostp = data->state.resolve; hostp; hostp = hostp->next) {
|
||||
char entry_id[MAX_HOSTCACHE_LEN];
|
||||
if(!hostp->data)
|
||||
const char *host = hostp->data;
|
||||
struct Curl_str source;
|
||||
if(!host)
|
||||
continue;
|
||||
if(hostp->data[0] == '-') {
|
||||
if(*host == '-') {
|
||||
curl_off_t num = 0;
|
||||
size_t entry_len;
|
||||
size_t hlen = 0;
|
||||
host_end = strchr(&hostp->data[1], ':');
|
||||
|
||||
if(host_end) {
|
||||
hlen = host_end - &hostp->data[1];
|
||||
host_end++;
|
||||
if(Curl_str_number(&host_end, &num, 0xffff))
|
||||
host_end = NULL;
|
||||
host++;
|
||||
if(!Curl_str_single(&host, '[')) {
|
||||
if(Curl_str_until(&host, &source, MAX_IPADR_LEN, ']') ||
|
||||
Curl_str_single(&host, ']') ||
|
||||
Curl_str_single(&host, ':'))
|
||||
continue;
|
||||
}
|
||||
if(!host_end) {
|
||||
infof(data, "Bad syntax CURLOPT_RESOLVE removal entry '%s'",
|
||||
hostp->data);
|
||||
continue;
|
||||
else {
|
||||
if(Curl_str_until(&host, &source, 4096, ':') ||
|
||||
Curl_str_single(&host, ':')) {
|
||||
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 */
|
||||
Curl_hash_delete(data->dns.hostcache, entry_id, entry_len + 1);
|
||||
if(!Curl_str_number(&host, &num, 0xffff)) {
|
||||
/* 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)
|
||||
Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
|
||||
/* delete entry, ignore if it did not exist */
|
||||
Curl_hash_delete(data->dns.hostcache, entry_id, entry_len + 1);
|
||||
|
||||
if(data->share)
|
||||
Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
|
||||
}
|
||||
}
|
||||
else {
|
||||
struct Curl_dns_entry *dns;
|
||||
|
@ -1170,71 +1173,66 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
|
|||
#if !defined(CURL_DISABLE_VERBOSE_STRINGS)
|
||||
const char *addresses = NULL;
|
||||
#endif
|
||||
const char *addr_begin;
|
||||
const char *addr_end;
|
||||
const char *port_ptr;
|
||||
curl_off_t port = 0;
|
||||
const char *end_ptr;
|
||||
bool permanent = TRUE;
|
||||
bool error = TRUE;
|
||||
char *host_begin = hostp->data;
|
||||
size_t hlen = 0;
|
||||
|
||||
if(host_begin[0] == '+') {
|
||||
host_begin++;
|
||||
if(*host == '+') {
|
||||
host++;
|
||||
permanent = FALSE;
|
||||
}
|
||||
host_end = strchr(host_begin, ':');
|
||||
if(!host_end)
|
||||
if(!Curl_str_single(&host, '[')) {
|
||||
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;
|
||||
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)
|
||||
addresses = end_ptr + 1;
|
||||
addresses = host;
|
||||
#endif
|
||||
|
||||
while(*end_ptr) {
|
||||
size_t alen;
|
||||
/* start the address section */
|
||||
while(*host) {
|
||||
struct Curl_str target;
|
||||
struct Curl_addrinfo *ai;
|
||||
|
||||
addr_begin = end_ptr + 1;
|
||||
addr_end = strchr(addr_begin, ',');
|
||||
if(!addr_end)
|
||||
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) != ']')
|
||||
if(!Curl_str_single(&host, '[')) {
|
||||
if(Curl_str_until(&host, &target, MAX_IPADR_LEN, ']') ||
|
||||
Curl_str_single(&host, ']'))
|
||||
goto err;
|
||||
++addr_begin;
|
||||
--addr_end;
|
||||
}
|
||||
|
||||
alen = addr_end - addr_begin;
|
||||
if(!alen)
|
||||
continue;
|
||||
|
||||
if(alen >= sizeof(address))
|
||||
goto err;
|
||||
|
||||
memcpy(address, addr_begin, alen);
|
||||
address[alen] = '\0';
|
||||
|
||||
else {
|
||||
if(Curl_str_until(&host, &target, 4096, ',')) {
|
||||
if(Curl_str_single(&host, ','))
|
||||
goto err;
|
||||
/* survive nothing but just a comma */
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#ifndef USE_IPV6
|
||||
if(strchr(address, ':')) {
|
||||
if(memchr(target.str, ':', target.len)) {
|
||||
infof(data, "Ignoring resolve address '%s', missing IPv6 support.",
|
||||
address);
|
||||
if(Curl_str_single(&host, ','))
|
||||
goto err;
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
if(target.len >= sizeof(address))
|
||||
goto err;
|
||||
|
||||
memcpy(address, target.str, target.len);
|
||||
address[target.len] = '\0';
|
||||
|
||||
ai = Curl_str2addr(address, (int)port);
|
||||
if(!ai) {
|
||||
infof(data, "Resolve address '%s' found illegal", address);
|
||||
|
@ -1248,6 +1246,8 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
|
|||
else {
|
||||
head = tail = ai;
|
||||
}
|
||||
if(Curl_str_single(&host, ','))
|
||||
break;
|
||||
}
|
||||
|
||||
if(!head)
|
||||
|
@ -1263,7 +1263,7 @@ err:
|
|||
}
|
||||
|
||||
/* 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));
|
||||
|
||||
if(data->share)
|
||||
|
@ -1274,7 +1274,7 @@ err:
|
|||
|
||||
if(dns) {
|
||||
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
|
||||
1. old entry may have different addresses.
|
||||
2. even if entry with correct addresses is already in the cache,
|
||||
|
@ -1290,7 +1290,7 @@ err:
|
|||
}
|
||||
|
||||
/* 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);
|
||||
if(dns) {
|
||||
/* release the returned reference; the cache itself will keep the
|
||||
|
@ -1307,12 +1307,12 @@ err:
|
|||
}
|
||||
#ifndef CURL_DISABLE_VERBOSE_STRINGS
|
||||
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)");
|
||||
#endif
|
||||
|
||||
/* 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",
|
||||
port);
|
||||
data->state.wildcard_resolve = TRUE;
|
||||
|
|
Loading…
Reference in New Issue
Block a user