mirror of
https://github.com/moparisthebest/curl
synced 2024-11-14 21:45:13 -05:00
dns: extend CURLOPT_RESOLVE syntax for adding non-permanent entries
Extend the syntax of CURLOPT_RESOLVE strings: allow using a '+' prefix (similar to the existing '-' prefix for removing entries) to add DNS cache entries that will time out just like entries that are added by libcurl itself. Append " (non-permanent)" to info log message in case a non-permanent entry is added. Adjust relevant comments to reflect the new behavior. Adjust documentation. Extend unit1607 to test the new functionality. Closes #6294
This commit is contained in:
parent
68dde8e330
commit
8324dc8b1a
@ -1,5 +1,5 @@
|
|||||||
Long: resolve
|
Long: resolve
|
||||||
Arg: <host:port:addr[,addr]...>
|
Arg: <[+]host:port:addr[,addr]...>
|
||||||
Help: Resolve the host+port to this address
|
Help: Resolve the host+port to this address
|
||||||
Added: 7.21.3
|
Added: 7.21.3
|
||||||
Category: connection
|
Category: connection
|
||||||
@ -19,10 +19,18 @@ with a specific host and port will be used first.
|
|||||||
The provided address set by this option will be used even if --ipv4 or --ipv6
|
The provided address set by this option will be used even if --ipv4 or --ipv6
|
||||||
is set to make curl use another IP version.
|
is set to make curl use another IP version.
|
||||||
|
|
||||||
|
By prefixing the host with a '+' you can make the entry time out after curl's
|
||||||
|
default timeout (1 minute). Note that this will only make sense for long
|
||||||
|
running parallel transfers with a lot of files. In such cases, if this option
|
||||||
|
is used curl will try to resolve the host as it normally would once the
|
||||||
|
timeout has expired.
|
||||||
|
|
||||||
Support for providing the IP address within [brackets] was added in 7.57.0.
|
Support for providing the IP address within [brackets] was added in 7.57.0.
|
||||||
|
|
||||||
Support for providing multiple IP addresses per entry was added in 7.59.0.
|
Support for providing multiple IP addresses per entry was added in 7.59.0.
|
||||||
|
|
||||||
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 was added in 7.75.0.
|
||||||
|
|
||||||
This option can be used many times to add many host names to resolve.
|
This option can be used many times to add many host names to resolve.
|
||||||
|
@ -37,7 +37,7 @@ list of \fBstruct curl_slist\fP structs properly filled in. Use
|
|||||||
to clean up an entire list.
|
to clean up an entire list.
|
||||||
|
|
||||||
Each single name resolve string should be written using the format
|
Each single name resolve string should be written using the format
|
||||||
HOST:PORT:ADDRESS[,ADDRESS]... where HOST is the name libcurl will try
|
[+]HOST:PORT:ADDRESS[,ADDRESS]... where HOST is the name libcurl will try
|
||||||
to resolve, PORT is the port number of the service where libcurl wants
|
to resolve, PORT is the port number of the service where libcurl wants
|
||||||
to connect to the HOST and ADDRESS is one or more numerical IP
|
to connect to the HOST and ADDRESS is one or more numerical IP
|
||||||
addresses. If you specify multiple ip addresses they need to be
|
addresses. If you specify multiple ip addresses they need to be
|
||||||
@ -46,14 +46,16 @@ ADDRESS entries can of course be either IPv4 or IPv6 style addressing.
|
|||||||
|
|
||||||
This option effectively pre-populates the DNS cache with entries for the
|
This option effectively pre-populates the DNS cache with entries for the
|
||||||
host+port pair so redirects and everything that operations against the
|
host+port pair so redirects and everything that operations against the
|
||||||
HOST+PORT will instead use your provided ADDRESS. Addresses set with
|
HOST+PORT will instead use your provided ADDRESS.
|
||||||
\fICURLOPT_RESOLVE(3)\fP will not time-out from the DNS cache like ordinary
|
|
||||||
entries.
|
|
||||||
|
|
||||||
If the DNS cache already have an entry for the given host+port pair, then
|
The optional leading "+" signifies whether the new entry should time-out or
|
||||||
|
not. Entires added with "HOST:..." will never time-out whereas entries added
|
||||||
|
with "+HOST:..." will time-out just like ordinary DNS cache entries.
|
||||||
|
|
||||||
|
If the DNS cache already has an entry for the given host+port pair, then
|
||||||
this entry will be removed and a new entry will be created. This is because
|
this entry will be removed and a new entry will be created. This is because
|
||||||
old entry may have have different addresses or be ordinary entries with
|
the old entry may have have different addresses or a different time-out
|
||||||
time-outs.
|
setting.
|
||||||
|
|
||||||
The provided ADDRESS set by this option will be used even if
|
The provided ADDRESS set by this option will be used even if
|
||||||
\fICURLOPT_IPRESOLVE(3)\fP is set to make libcurl use another IP version.
|
\fICURLOPT_IPRESOLVE(3)\fP is set to make libcurl use another IP version.
|
||||||
@ -66,6 +68,9 @@ and port number must exactly match what was already added previously.
|
|||||||
Support for providing the ADDRESS within [brackets] was added in 7.57.0.
|
Support for providing the ADDRESS within [brackets] was added in 7.57.0.
|
||||||
|
|
||||||
Support for providing multiple IP addresses per entry was added in 7.59.0.
|
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.
|
||||||
.SH DEFAULT
|
.SH DEFAULT
|
||||||
NULL
|
NULL
|
||||||
.SH PROTOCOLS
|
.SH PROTOCOLS
|
||||||
|
34
lib/hostip.c
34
lib/hostip.c
@ -444,7 +444,7 @@ Curl_cache_addr(struct Curl_easy *data,
|
|||||||
dns->addr = addr; /* this is the address(es) */
|
dns->addr = addr; /* this is the address(es) */
|
||||||
time(&dns->timestamp);
|
time(&dns->timestamp);
|
||||||
if(dns->timestamp == 0)
|
if(dns->timestamp == 0)
|
||||||
dns->timestamp = 1; /* zero indicates CURLOPT_RESOLVE entry */
|
dns->timestamp = 1; /* zero indicates permanent CURLOPT_RESOLVE entry */
|
||||||
|
|
||||||
/* Store the resolved data in our DNS cache. */
|
/* Store the resolved data in our DNS cache. */
|
||||||
dns2 = Curl_hash_add(data->dns.hostcache, entry_id, entry_len + 1,
|
dns2 = Curl_hash_add(data->dns.hostcache, entry_id, entry_len + 1,
|
||||||
@ -916,17 +916,24 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
|
|||||||
char *addr_end;
|
char *addr_end;
|
||||||
char *port_ptr;
|
char *port_ptr;
|
||||||
char *end_ptr;
|
char *end_ptr;
|
||||||
|
bool permanent = TRUE;
|
||||||
|
char *host_begin;
|
||||||
char *host_end;
|
char *host_end;
|
||||||
unsigned long tmp_port;
|
unsigned long tmp_port;
|
||||||
bool error = true;
|
bool error = true;
|
||||||
|
|
||||||
host_end = strchr(hostp->data, ':');
|
host_begin = hostp->data;
|
||||||
|
if(host_begin[0] == '+') {
|
||||||
|
host_begin++;
|
||||||
|
permanent = FALSE;
|
||||||
|
}
|
||||||
|
host_end = strchr(host_begin, ':');
|
||||||
if(!host_end ||
|
if(!host_end ||
|
||||||
((host_end - hostp->data) >= (ptrdiff_t)sizeof(hostname)))
|
((host_end - host_begin) >= (ptrdiff_t)sizeof(hostname)))
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
memcpy(hostname, hostp->data, host_end - hostp->data);
|
memcpy(hostname, host_begin, host_end - host_begin);
|
||||||
hostname[host_end - hostp->data] = '\0';
|
hostname[host_end - host_begin] = '\0';
|
||||||
|
|
||||||
port_ptr = host_end + 1;
|
port_ptr = host_end + 1;
|
||||||
tmp_port = strtoul(port_ptr, &end_ptr, 10);
|
tmp_port = strtoul(port_ptr, &end_ptr, 10);
|
||||||
@ -1008,18 +1015,22 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
|
|||||||
if(data->share)
|
if(data->share)
|
||||||
Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
|
Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
|
||||||
|
|
||||||
/* See if its already in our dns cache */
|
/* See if it's already in our dns cache */
|
||||||
dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len + 1);
|
dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len + 1);
|
||||||
|
|
||||||
if(dns) {
|
if(dns) {
|
||||||
infof(data, "RESOLVE %s:%d is - old addresses discarded!\n",
|
infof(data, "RESOLVE %s:%d is - old addresses discarded!\n",
|
||||||
hostname, port);
|
hostname, port);
|
||||||
/* delete old entry 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,
|
||||||
but if it is close to expire, then by the time next http
|
but if it is close to expire, then by the time next http
|
||||||
request is made, it can get expired and pruned because old
|
request is made, it can get expired and pruned because old
|
||||||
entry is not necessarily marked as added by CURLOPT_RESOLVE. */
|
entry is not necessarily marked as permanent.
|
||||||
|
3. when adding a non-permanent entry, we want it to remove and
|
||||||
|
replace an existing permanent entry.
|
||||||
|
4. when adding a non-permanent entry, we want it to get a "fresh"
|
||||||
|
timeout that starts _now_. */
|
||||||
|
|
||||||
Curl_hash_delete(data->dns.hostcache, entry_id, entry_len + 1);
|
Curl_hash_delete(data->dns.hostcache, entry_id, entry_len + 1);
|
||||||
}
|
}
|
||||||
@ -1027,7 +1038,8 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
|
|||||||
/* put this new host in the cache */
|
/* put this new host in the cache */
|
||||||
dns = Curl_cache_addr(data, head, hostname, port);
|
dns = Curl_cache_addr(data, head, hostname, port);
|
||||||
if(dns) {
|
if(dns) {
|
||||||
dns->timestamp = 0; /* mark as added by CURLOPT_RESOLVE */
|
if(permanent)
|
||||||
|
dns->timestamp = 0; /* mark as permanent */
|
||||||
/* release the returned reference; the cache itself will keep the
|
/* release the returned reference; the cache itself will keep the
|
||||||
* entry alive: */
|
* entry alive: */
|
||||||
dns->inuse--;
|
dns->inuse--;
|
||||||
@ -1040,8 +1052,8 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
|
|||||||
Curl_freeaddrinfo(head);
|
Curl_freeaddrinfo(head);
|
||||||
return CURLE_OUT_OF_MEMORY;
|
return CURLE_OUT_OF_MEMORY;
|
||||||
}
|
}
|
||||||
infof(data, "Added %s:%d:%s to DNS cache\n",
|
infof(data, "Added %s:%d:%s to DNS cache%s\n",
|
||||||
hostname, port, addresses);
|
hostname, port, addresses, permanent ? "" : " (non-permanent)");
|
||||||
|
|
||||||
/* Wildcard hostname */
|
/* Wildcard hostname */
|
||||||
if(hostname[0] == '*' && hostname[1] == '\0') {
|
if(hostname[0] == '*' && hostname[1] == '\0') {
|
||||||
|
@ -65,7 +65,7 @@ struct Curl_hash *Curl_global_host_cache_init(void);
|
|||||||
|
|
||||||
struct Curl_dns_entry {
|
struct Curl_dns_entry {
|
||||||
struct Curl_addrinfo *addr;
|
struct Curl_addrinfo *addr;
|
||||||
/* timestamp == 0 -- CURLOPT_RESOLVE entry, doesn't timeout */
|
/* timestamp == 0 -- permanent CURLOPT_RESOLVE entry (doesn't time out) */
|
||||||
time_t timestamp;
|
time_t timestamp;
|
||||||
/* use-counter, use Curl_resolv_unlock to release reference */
|
/* use-counter, use Curl_resolv_unlock to release reference */
|
||||||
long inuse;
|
long inuse;
|
||||||
|
13
lib/setopt.c
13
lib/setopt.c
@ -1460,13 +1460,16 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
|
|||||||
break;
|
break;
|
||||||
case CURLOPT_RESOLVE:
|
case CURLOPT_RESOLVE:
|
||||||
/*
|
/*
|
||||||
* List of NAME:[address] names to populate the DNS cache with
|
* List of HOST:PORT:[addresses] strings to populate the DNS cache with
|
||||||
* Prefix the NAME with dash (-) to _remove_ the name from the cache.
|
* Entries added this way will remain in the cache until explicitly
|
||||||
*
|
|
||||||
* Names added with this API will remain in the cache until explicitly
|
|
||||||
* removed or the handle is cleaned up.
|
* removed or the handle is cleaned up.
|
||||||
*
|
*
|
||||||
* This API can remove any name from the DNS cache, but only entries
|
* Prefix the HOST with plus sign (+) to have the entry expire just like
|
||||||
|
* automatically added entries.
|
||||||
|
*
|
||||||
|
* Prefix the HOST with dash (-) to _remove_ the entry from the cache.
|
||||||
|
*
|
||||||
|
* This API can remove any entry from the DNS cache, but only entries
|
||||||
* that aren't actually in use right now will be pruned immediately.
|
* that aren't actually in use right now will be pruned immediately.
|
||||||
*/
|
*/
|
||||||
data->set.resolve = va_arg(param, struct curl_slist *);
|
data->set.resolve = va_arg(param, struct curl_slist *);
|
||||||
|
@ -49,6 +49,9 @@ struct testcase {
|
|||||||
const char *host;
|
const char *host;
|
||||||
int port;
|
int port;
|
||||||
|
|
||||||
|
/* whether we expect a permanent or non-permanent cache entry */
|
||||||
|
bool permanent;
|
||||||
|
|
||||||
/* 0 to 9 addresses expected from hostcache */
|
/* 0 to 9 addresses expected from hostcache */
|
||||||
const char *address[10];
|
const char *address[10];
|
||||||
};
|
};
|
||||||
@ -67,34 +70,37 @@ static const char skip = 0;
|
|||||||
static const struct testcase tests[] = {
|
static const struct testcase tests[] = {
|
||||||
/* spaces aren't allowed, for now */
|
/* spaces aren't allowed, for now */
|
||||||
{ "test.com:80:127.0.0.1, 127.0.0.2",
|
{ "test.com:80:127.0.0.1, 127.0.0.2",
|
||||||
"test.com", 80, { NULL, }
|
"test.com", 80, TRUE, { NULL, }
|
||||||
},
|
},
|
||||||
{ "TEST.com:80:,,127.0.0.1,,,127.0.0.2,,,,::1,,,",
|
{ "TEST.com:80:,,127.0.0.1,,,127.0.0.2,,,,::1,,,",
|
||||||
"test.com", 80, { "127.0.0.1", "127.0.0.2", IPV6ONLY("::1"), }
|
"test.com", 80, TRUE, { "127.0.0.1", "127.0.0.2", IPV6ONLY("::1"), }
|
||||||
},
|
},
|
||||||
{ "test.com:80:::1,127.0.0.1",
|
{ "test.com:80:::1,127.0.0.1",
|
||||||
"test.com", 80, { IPV6ONLY("::1"), "127.0.0.1", }
|
"test.com", 80, TRUE, { IPV6ONLY("::1"), "127.0.0.1", }
|
||||||
},
|
},
|
||||||
{ "test.com:80:[::1],127.0.0.1",
|
{ "test.com:80:[::1],127.0.0.1",
|
||||||
"test.com", 80, { IPV6ONLY("::1"), "127.0.0.1", }
|
"test.com", 80, TRUE, { IPV6ONLY("::1"), "127.0.0.1", }
|
||||||
},
|
},
|
||||||
{ "test.com:80:::1",
|
{ "test.com:80:::1",
|
||||||
"test.com", 80, { IPV6ONLY("::1"), }
|
"test.com", 80, TRUE, { IPV6ONLY("::1"), }
|
||||||
},
|
},
|
||||||
{ "test.com:80:[::1]",
|
{ "test.com:80:[::1]",
|
||||||
"test.com", 80, { IPV6ONLY("::1"), }
|
"test.com", 80, TRUE, { IPV6ONLY("::1"), }
|
||||||
},
|
},
|
||||||
{ "test.com:80:127.0.0.1",
|
{ "test.com:80:127.0.0.1",
|
||||||
"test.com", 80, { "127.0.0.1", }
|
"test.com", 80, TRUE, { "127.0.0.1", }
|
||||||
},
|
},
|
||||||
{ "test.com:80:,127.0.0.1",
|
{ "test.com:80:,127.0.0.1",
|
||||||
"test.com", 80, { "127.0.0.1", }
|
"test.com", 80, TRUE, { "127.0.0.1", }
|
||||||
},
|
},
|
||||||
{ "test.com:80:127.0.0.1,",
|
{ "test.com:80:127.0.0.1,",
|
||||||
"test.com", 80, { "127.0.0.1", }
|
"test.com", 80, TRUE, { "127.0.0.1", }
|
||||||
},
|
},
|
||||||
{ "test.com:0:127.0.0.1",
|
{ "test.com:0:127.0.0.1",
|
||||||
"test.com", 0, { "127.0.0.1", }
|
"test.com", 0, TRUE, { "127.0.0.1", }
|
||||||
|
},
|
||||||
|
{ "+test.com:80:127.0.0.1,",
|
||||||
|
"test.com", 80, FALSE, { "127.0.0.1", }
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -188,10 +194,18 @@ UNITTEST_START
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(dns->timestamp != 0) {
|
if(dns->timestamp != 0 && tests[i].permanent) {
|
||||||
fprintf(stderr, "%s:%d tests[%d] failed. the timestamp is not zero. "
|
fprintf(stderr, "%s:%d tests[%d] failed. the timestamp is not zero "
|
||||||
"for tests[%d].address[%d\n",
|
"but tests[%d].permanent is TRUE\n",
|
||||||
__FILE__, __LINE__, i, i, j);
|
__FILE__, __LINE__, i, i);
|
||||||
|
problem = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(dns->timestamp == 0 && !tests[i].permanent) {
|
||||||
|
fprintf(stderr, "%s:%d tests[%d] failed. the timestamp is zero "
|
||||||
|
"but tests[%d].permanent is FALSE\n",
|
||||||
|
__FILE__, __LINE__, i, i);
|
||||||
problem = true;
|
problem = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user