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,
|
caching, or set to -1 to make the cached entries remain forever. By default,
|
||||||
libcurl caches this info for 60 seconds.
|
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
|
The name resolve functions of various libc implementations do not re-read name
|
||||||
server information unless explicitly told so (for example, by calling
|
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
|
\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
|
if DHCP has updated the server info, and this may look like a DNS cache issue
|
||||||
to the casual libcurl-app user.
|
to the casual libcurl-app user.
|
||||||
|
|
||||||
Note that DNS entries have a "TTL" property but libcurl does not use that. This
|
DNS entries have a "TTL" property but libcurl does not use that. This DNS
|
||||||
DNS cache timeout is entirely speculative that a name will resolve to the same
|
cache timeout is entirely speculative that a name will resolve to the same
|
||||||
address for a certain small amount of time into the future.
|
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
|
.SH DEFAULT
|
||||||
60
|
60
|
||||||
.SH PROTOCOLS
|
.SH PROTOCOLS
|
||||||
|
|||||||
41
lib/hostip.c
41
lib/hostip.c
@ -85,6 +85,8 @@
|
|||||||
|
|
||||||
#define MAX_HOSTCACHE_LEN (255 + 7) /* max FQDN + colon + port number + zero */
|
#define MAX_HOSTCACHE_LEN (255 + 7) /* max FQDN + colon + port number + zero */
|
||||||
|
|
||||||
|
#define MAX_DNS_CACHE_SIZE 29999
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* hostip.c explained
|
* hostip.c explained
|
||||||
* ==================
|
* ==================
|
||||||
@ -198,6 +200,7 @@ create_hostcache_id(const char *name,
|
|||||||
struct hostcache_prune_data {
|
struct hostcache_prune_data {
|
||||||
time_t now;
|
time_t now;
|
||||||
int cache_timeout;
|
int cache_timeout;
|
||||||
|
int oldest; /* oldest time in cache not pruned */
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -210,28 +213,39 @@ struct hostcache_prune_data {
|
|||||||
static int
|
static int
|
||||||
hostcache_timestamp_remove(void *datap, void *hc)
|
hostcache_timestamp_remove(void *datap, void *hc)
|
||||||
{
|
{
|
||||||
struct hostcache_prune_data *data =
|
struct hostcache_prune_data *prune =
|
||||||
(struct hostcache_prune_data *) datap;
|
(struct hostcache_prune_data *) datap;
|
||||||
struct Curl_dns_entry *c = (struct Curl_dns_entry *) hc;
|
struct Curl_dns_entry *c = (struct Curl_dns_entry *) hc;
|
||||||
|
|
||||||
return (0 != c->timestamp)
|
if(c->timestamp) {
|
||||||
&& (data->now - c->timestamp >= data->cache_timeout);
|
/* 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.
|
* 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)
|
hostcache_prune(struct Curl_hash *hostcache, int cache_timeout, time_t now)
|
||||||
{
|
{
|
||||||
struct hostcache_prune_data user;
|
struct hostcache_prune_data user;
|
||||||
|
|
||||||
user.cache_timeout = cache_timeout;
|
user.cache_timeout = cache_timeout;
|
||||||
user.now = now;
|
user.now = now;
|
||||||
|
user.oldest = 0;
|
||||||
|
|
||||||
Curl_hash_clean_with_criterium(hostcache,
|
Curl_hash_clean_with_criterium(hostcache,
|
||||||
(void *) &user,
|
(void *) &user,
|
||||||
hostcache_timestamp_remove);
|
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)
|
void Curl_hostcache_prune(struct Curl_easy *data)
|
||||||
{
|
{
|
||||||
time_t now;
|
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)
|
if(!data->dns.hostcache)
|
||||||
/* cache forever means never prune, and NULL hostcache means
|
/* NULL hostcache means we can't do it */
|
||||||
we can't do it */
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if(data->share)
|
if(data->share)
|
||||||
@ -252,10 +267,15 @@ void Curl_hostcache_prune(struct Curl_easy *data)
|
|||||||
|
|
||||||
time(&now);
|
time(&now);
|
||||||
|
|
||||||
|
do {
|
||||||
/* Remove outdated and unused entries from the hostcache */
|
/* Remove outdated and unused entries from the hostcache */
|
||||||
hostcache_prune(data->dns.hostcache,
|
int oldest = hostcache_prune(data->dns.hostcache, timeout, now);
|
||||||
data->set.dns_cache_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)
|
if(data->share)
|
||||||
Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
|
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);
|
time(&user.now);
|
||||||
user.cache_timeout = data->set.dns_cache_timeout;
|
user.cache_timeout = data->set.dns_cache_timeout;
|
||||||
|
user.oldest = 0;
|
||||||
|
|
||||||
if(hostcache_timestamp_remove(&user, dns)) {
|
if(hostcache_timestamp_remove(&user, dns)) {
|
||||||
infof(data, "Hostname in DNS cache was stale, zapped");
|
infof(data, "Hostname in DNS cache was stale, zapped");
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user