summaryrefslogtreecommitdiffstats
path: root/Utilities/cmcurl/lib/hostip.c
diff options
context:
space:
mode:
Diffstat (limited to 'Utilities/cmcurl/lib/hostip.c')
-rw-r--r--Utilities/cmcurl/lib/hostip.c83
1 files changed, 62 insertions, 21 deletions
diff --git a/Utilities/cmcurl/lib/hostip.c b/Utilities/cmcurl/lib/hostip.c
index d0dc2e8..d721403 100644
--- a/Utilities/cmcurl/lib/hostip.c
+++ b/Utilities/cmcurl/lib/hostip.c
@@ -61,6 +61,7 @@
#include "doh.h"
#include "warnless.h"
#include "strcase.h"
+#include "easy_lock.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
#include "curl_memory.h"
@@ -70,14 +71,19 @@
#include <SystemConfiguration/SCDynamicStoreCopySpecific.h>
#endif
-#if defined(CURLRES_SYNCH) && \
- defined(HAVE_ALARM) && defined(SIGALRM) && defined(HAVE_SIGSETJMP)
+#if defined(CURLRES_SYNCH) && \
+ defined(HAVE_ALARM) && \
+ defined(SIGALRM) && \
+ defined(HAVE_SIGSETJMP) && \
+ defined(GLOBAL_INIT_IS_THREADSAFE)
/* alarm-based timeouts can only be used with all the dependencies satisfied */
#define USE_ALARM_TIMEOUT
#endif
#define MAX_HOSTCACHE_LEN (255 + 7) /* max FQDN + colon + port number + zero */
+#define MAX_DNS_CACHE_SIZE 29999
+
/*
* hostip.c explained
* ==================
@@ -122,7 +128,7 @@ static void freednsentry(void *freethis);
/*
* Return # of addresses in a Curl_addrinfo struct
*/
-int Curl_num_addresses(const struct Curl_addrinfo *addr)
+static int num_addresses(const struct Curl_addrinfo *addr)
{
int i = 0;
while(addr) {
@@ -189,8 +195,9 @@ create_hostcache_id(const char *name,
}
struct hostcache_prune_data {
- long cache_timeout;
time_t now;
+ time_t oldest; /* oldest time in cache not pruned. */
+ int cache_timeout;
};
/*
@@ -203,28 +210,40 @@ 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 = 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
-hostcache_prune(struct Curl_hash *hostcache, long cache_timeout, time_t now)
+static time_t
+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;
}
/*
@@ -234,10 +253,11 @@ hostcache_prune(struct Curl_hash *hostcache, long 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)
@@ -245,20 +265,29 @@ 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 */
+ time_t oldest = hostcache_prune(data->dns.hostcache, timeout, now);
+
+ if(oldest < INT_MAX)
+ timeout = (int)oldest; /* we know it fits */
+ else
+ timeout = INT_MAX - 1;
+
+ /* 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);
}
-#ifdef HAVE_SIGSETJMP
+#ifdef USE_ALARM_TIMEOUT
/* Beware this is a global and unique instance. This is used to store the
return address that we can jump back to from inside a signal handler. This
is not thread-safe stuff. */
-sigjmp_buf curl_jmpenv;
+static sigjmp_buf curl_jmpenv;
+static curl_simple_lock curl_jmpenv_lock;
#endif
/* lookup address, returns entry if found and not stale */
@@ -290,6 +319,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");
@@ -380,7 +410,7 @@ UNITTEST CURLcode Curl_shuffle_addr(struct Curl_easy *data,
struct Curl_addrinfo **addr)
{
CURLcode result = CURLE_OK;
- const int num_addrs = Curl_num_addresses(*addr);
+ const int num_addrs = num_addresses(*addr);
if(num_addrs > 1) {
struct Curl_addrinfo **nodes;
@@ -652,6 +682,14 @@ enum resolve_t Curl_resolv(struct Curl_easy *data,
CURLcode result;
enum resolve_t rc = CURLRESOLV_ERROR; /* default to failure */
struct connectdata *conn = data->conn;
+ /* We should intentionally error and not resolve .onion TLDs */
+ size_t hostname_len = strlen(hostname);
+ if(hostname_len >= 7 &&
+ (curl_strequal(&hostname[hostname_len - 6], ".onion") ||
+ curl_strequal(&hostname[hostname_len - 7], ".onion."))) {
+ failf(data, "Not resolving .onion address (RFC 7686)");
+ return CURLRESOLV_ERROR;
+ }
*entry = NULL;
#ifndef CURL_DISABLE_DOH
conn->bits.doh = FALSE; /* default is not */
@@ -824,7 +862,6 @@ enum resolve_t Curl_resolv(struct Curl_easy *data,
static
void alarmfunc(int sig)
{
- /* this is for "-ansi -Wall -pedantic" to stop complaining! (rabe) */
(void)sig;
siglongjmp(curl_jmpenv, 1);
}
@@ -904,6 +941,8 @@ enum resolve_t Curl_resolv_timeout(struct Curl_easy *data,
This should be the last thing we do before calling Curl_resolv(),
as otherwise we'd have to worry about variables that get modified
before we invoke Curl_resolv() (and thus use "volatile"). */
+ curl_simple_lock_lock(&curl_jmpenv_lock);
+
if(sigsetjmp(curl_jmpenv, 1)) {
/* this is coming from a siglongjmp() after an alarm signal */
failf(data, "name lookup timed out");
@@ -972,6 +1011,8 @@ clean_up:
#endif
#endif /* HAVE_SIGACTION */
+ curl_simple_lock_unlock(&curl_jmpenv_lock);
+
/* switch back the alarm() to either zero or to what it was before minus
the time we spent until now! */
if(prev_alarm) {
@@ -1196,7 +1237,7 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
goto err;
error = false;
- err:
+err:
if(error) {
failf(data, "Couldn't parse CURLOPT_RESOLVE entry '%s'",
hostp->data);