mirror of
https://github.com/moparisthebest/curl
synced 2024-08-13 17:03:50 -04: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
|
||||
Arg: <host:port:addr[,addr]...>
|
||||
Arg: <[+]host:port:addr[,addr]...>
|
||||
Help: Resolve the host+port to this address
|
||||
Added: 7.21.3
|
||||
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
|
||||
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 multiple IP addresses per entry was added in 7.59.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.
|
||||
|
@ -37,7 +37,7 @@ list of \fBstruct curl_slist\fP structs properly filled in. Use
|
||||
to clean up an entire list.
|
||||
|
||||
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 connect to the HOST and ADDRESS is one or more numerical IP
|
||||
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
|
||||
host+port pair so redirects and everything that operations against the
|
||||
HOST+PORT will instead use your provided ADDRESS. Addresses set with
|
||||
\fICURLOPT_RESOLVE(3)\fP will not time-out from the DNS cache like ordinary
|
||||
entries.
|
||||
HOST+PORT will instead use your provided ADDRESS.
|
||||
|
||||
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
|
||||
old entry may have have different addresses or be ordinary entries with
|
||||
time-outs.
|
||||
the old entry may have have different addresses or a different time-out
|
||||
setting.
|
||||
|
||||
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.
|
||||
@ -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 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
|
||||
NULL
|
||||
.SH PROTOCOLS
|
||||
|
36
lib/hostip.c
36
lib/hostip.c
@ -444,7 +444,7 @@ Curl_cache_addr(struct Curl_easy *data,
|
||||
dns->addr = addr; /* this is the address(es) */
|
||||
time(&dns->timestamp);
|
||||
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. */
|
||||
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 *port_ptr;
|
||||
char *end_ptr;
|
||||
bool permanent = TRUE;
|
||||
char *host_begin;
|
||||
char *host_end;
|
||||
unsigned long tmp_port;
|
||||
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 ||
|
||||
((host_end - hostp->data) >= (ptrdiff_t)sizeof(hostname)))
|
||||
((host_end - host_begin) >= (ptrdiff_t)sizeof(hostname)))
|
||||
goto err;
|
||||
|
||||
memcpy(hostname, hostp->data, host_end - hostp->data);
|
||||
hostname[host_end - hostp->data] = '\0';
|
||||
memcpy(hostname, host_begin, host_end - host_begin);
|
||||
hostname[host_end - host_begin] = '\0';
|
||||
|
||||
port_ptr = host_end + 1;
|
||||
tmp_port = strtoul(port_ptr, &end_ptr, 10);
|
||||
@ -1008,18 +1015,22 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
|
||||
if(data->share)
|
||||
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);
|
||||
|
||||
if(dns) {
|
||||
infof(data, "RESOLVE %s:%d is - old addresses discarded!\n",
|
||||
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.
|
||||
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
|
||||
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);
|
||||
}
|
||||
@ -1027,10 +1038,11 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
|
||||
/* put this new host in the cache */
|
||||
dns = Curl_cache_addr(data, head, hostname, port);
|
||||
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
|
||||
* entry alive: */
|
||||
dns->inuse--;
|
||||
dns->inuse--;
|
||||
}
|
||||
|
||||
if(data->share)
|
||||
@ -1040,8 +1052,8 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
|
||||
Curl_freeaddrinfo(head);
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
infof(data, "Added %s:%d:%s to DNS cache\n",
|
||||
hostname, port, addresses);
|
||||
infof(data, "Added %s:%d:%s to DNS cache%s\n",
|
||||
hostname, port, addresses, permanent ? "" : " (non-permanent)");
|
||||
|
||||
/* Wildcard hostname */
|
||||
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_addrinfo *addr;
|
||||
/* timestamp == 0 -- CURLOPT_RESOLVE entry, doesn't timeout */
|
||||
/* timestamp == 0 -- permanent CURLOPT_RESOLVE entry (doesn't time out) */
|
||||
time_t timestamp;
|
||||
/* use-counter, use Curl_resolv_unlock to release reference */
|
||||
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;
|
||||
case CURLOPT_RESOLVE:
|
||||
/*
|
||||
* List of NAME:[address] names to populate the DNS cache with
|
||||
* Prefix the NAME with dash (-) to _remove_ the name from the cache.
|
||||
*
|
||||
* Names added with this API will remain in the cache until explicitly
|
||||
* List of HOST:PORT:[addresses] strings to populate the DNS cache with
|
||||
* Entries added this way will remain in the cache until explicitly
|
||||
* 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.
|
||||
*/
|
||||
data->set.resolve = va_arg(param, struct curl_slist *);
|
||||
|
@ -49,6 +49,9 @@ struct testcase {
|
||||
const char *host;
|
||||
int port;
|
||||
|
||||
/* whether we expect a permanent or non-permanent cache entry */
|
||||
bool permanent;
|
||||
|
||||
/* 0 to 9 addresses expected from hostcache */
|
||||
const char *address[10];
|
||||
};
|
||||
@ -67,34 +70,37 @@ static const char skip = 0;
|
||||
static const struct testcase tests[] = {
|
||||
/* spaces aren't allowed, for now */
|
||||
{ "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", 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, { 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, { IPV6ONLY("::1"), "127.0.0.1", }
|
||||
"test.com", 80, TRUE, { IPV6ONLY("::1"), "127.0.0.1", }
|
||||
},
|
||||
{ "test.com:80:::1",
|
||||
"test.com", 80, { IPV6ONLY("::1"), }
|
||||
"test.com", 80, TRUE, { IPV6ONLY("::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, TRUE, { "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, TRUE, { "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;
|
||||
}
|
||||
|
||||
if(dns->timestamp != 0) {
|
||||
fprintf(stderr, "%s:%d tests[%d] failed. the timestamp is not zero. "
|
||||
"for tests[%d].address[%d\n",
|
||||
__FILE__, __LINE__, i, i, j);
|
||||
if(dns->timestamp != 0 && tests[i].permanent) {
|
||||
fprintf(stderr, "%s:%d tests[%d] failed. the timestamp is not zero "
|
||||
"but tests[%d].permanent is TRUE\n",
|
||||
__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;
|
||||
break;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user