mirror of
https://github.com/curl/curl.git
synced 2024-12-09 06:30:06 +08:00
hostip: enforce a maximum DNS cache size independent of timeout value
To reduce the damage an application can cause if using -1 or other ridiculous timeout values and letting the cache live long times. The maximum number of entries in the DNS cache is now totally arbitrarily and hard-coded set to 29999. Closes #11084
This commit is contained in:
parent
f62557276a
commit
9ed7d56e04
@ -37,15 +37,23 @@ memory and used for this number of seconds. Set to zero to completely disable
|
||||
caching, or set to -1 to make the cached entries remain forever. By default,
|
||||
libcurl caches this info for 60 seconds.
|
||||
|
||||
We recommend users not to tamper with this option unless strictly necessary.
|
||||
If you do, be careful of using large values that can make the cache size grow
|
||||
significantly if many different host names are used within that timeout
|
||||
period.
|
||||
|
||||
The name resolve functions of various libc implementations do not re-read name
|
||||
server information unless explicitly told so (for example, by calling
|
||||
\fIres_init(3)\fP). This may cause libcurl to keep using the older server even
|
||||
if DHCP has updated the server info, and this may look like a DNS cache issue
|
||||
to the casual libcurl-app user.
|
||||
|
||||
Note that DNS entries have a "TTL" property but libcurl does not use that. This
|
||||
DNS cache timeout is entirely speculative that a name will resolve to the same
|
||||
DNS entries have a "TTL" property but libcurl does not use that. This DNS
|
||||
cache timeout is entirely speculative that a name will resolve to the same
|
||||
address for a certain small amount of time into the future.
|
||||
|
||||
Since version 8.1.0, libcurl prunes entries from the DNS cache if it excceeds
|
||||
30,000 entries no matter which timeout value is used.
|
||||
.SH DEFAULT
|
||||
60
|
||||
.SH PROTOCOLS
|
||||
|
43
lib/hostip.c
43
lib/hostip.c
@ -85,6 +85,8 @@
|
||||
|
||||
#define MAX_HOSTCACHE_LEN (255 + 7) /* max FQDN + colon + port number + zero */
|
||||
|
||||
#define MAX_DNS_CACHE_SIZE 29999
|
||||
|
||||
/*
|
||||
* hostip.c explained
|
||||
* ==================
|
||||
@ -198,6 +200,7 @@ create_hostcache_id(const char *name,
|
||||
struct hostcache_prune_data {
|
||||
time_t now;
|
||||
int cache_timeout;
|
||||
int oldest; /* oldest time in cache not pruned */
|
||||
};
|
||||
|
||||
/*
|
||||
@ -210,28 +213,39 @@ struct hostcache_prune_data {
|
||||
static int
|
||||
hostcache_timestamp_remove(void *datap, void *hc)
|
||||
{
|
||||
struct hostcache_prune_data *data =
|
||||
struct hostcache_prune_data *prune =
|
||||
(struct hostcache_prune_data *) datap;
|
||||
struct Curl_dns_entry *c = (struct Curl_dns_entry *) hc;
|
||||
|
||||
return (0 != c->timestamp)
|
||||
&& (data->now - c->timestamp >= data->cache_timeout);
|
||||
if(c->timestamp) {
|
||||
/* age in seconds */
|
||||
time_t age = prune->now - c->timestamp;
|
||||
if(age >= prune->cache_timeout)
|
||||
return TRUE;
|
||||
if(age > prune->oldest)
|
||||
prune->oldest = (int)age;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Prune the DNS cache. This assumes that a lock has already been taken.
|
||||
* Returns the 'age' of the oldest still kept entry.
|
||||
*/
|
||||
static void
|
||||
static int
|
||||
hostcache_prune(struct Curl_hash *hostcache, int cache_timeout, time_t now)
|
||||
{
|
||||
struct hostcache_prune_data user;
|
||||
|
||||
user.cache_timeout = cache_timeout;
|
||||
user.now = now;
|
||||
user.oldest = 0;
|
||||
|
||||
Curl_hash_clean_with_criterium(hostcache,
|
||||
(void *) &user,
|
||||
hostcache_timestamp_remove);
|
||||
|
||||
return user.oldest;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -241,10 +255,11 @@ hostcache_prune(struct Curl_hash *hostcache, int cache_timeout, time_t now)
|
||||
void Curl_hostcache_prune(struct Curl_easy *data)
|
||||
{
|
||||
time_t now;
|
||||
/* the timeout may be set -1 (forever) */
|
||||
int timeout = data->set.dns_cache_timeout;
|
||||
|
||||
if((data->set.dns_cache_timeout == -1) || !data->dns.hostcache)
|
||||
/* cache forever means never prune, and NULL hostcache means
|
||||
we can't do it */
|
||||
if(!data->dns.hostcache)
|
||||
/* NULL hostcache means we can't do it */
|
||||
return;
|
||||
|
||||
if(data->share)
|
||||
@ -252,10 +267,15 @@ void Curl_hostcache_prune(struct Curl_easy *data)
|
||||
|
||||
time(&now);
|
||||
|
||||
/* Remove outdated and unused entries from the hostcache */
|
||||
hostcache_prune(data->dns.hostcache,
|
||||
data->set.dns_cache_timeout,
|
||||
now);
|
||||
do {
|
||||
/* Remove outdated and unused entries from the hostcache */
|
||||
int oldest = hostcache_prune(data->dns.hostcache, timeout, now);
|
||||
|
||||
timeout = oldest;
|
||||
|
||||
/* if the cache size is still too big, use the oldest age as new
|
||||
prune limit */
|
||||
} while(timeout && (data->dns.hostcache->size > MAX_DNS_CACHE_SIZE));
|
||||
|
||||
if(data->share)
|
||||
Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
|
||||
@ -298,6 +318,7 @@ static struct Curl_dns_entry *fetch_addr(struct Curl_easy *data,
|
||||
|
||||
time(&user.now);
|
||||
user.cache_timeout = data->set.dns_cache_timeout;
|
||||
user.oldest = 0;
|
||||
|
||||
if(hostcache_timestamp_remove(&user, dns)) {
|
||||
infof(data, "Hostname in DNS cache was stale, zapped");
|
||||
|
Loading…
Reference in New Issue
Block a user