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:
Paul Groke 2020-12-10 17:38:14 +01:00 committed by Daniel Stenberg
parent 68dde8e330
commit 8324dc8b1a
No known key found for this signature in database
GPG key ID: 5CC908FDB71E12C2
6 changed files with 82 additions and 40 deletions

View file

@ -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') {

View file

@ -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;

View file

@ -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 *);