diff options
Diffstat (limited to 'src/resolve/resolved-dns-cache.c')
-rw-r--r-- | src/resolve/resolved-dns-cache.c | 102 |
1 files changed, 82 insertions, 20 deletions
diff --git a/src/resolve/resolved-dns-cache.c b/src/resolve/resolved-dns-cache.c index f50d780ebb..3193985542 100644 --- a/src/resolve/resolved-dns-cache.c +++ b/src/resolve/resolved-dns-cache.c @@ -272,6 +272,42 @@ static DnsCacheItem* dns_cache_get(DnsCache *c, DnsResourceRecord *rr) { return NULL; } +static usec_t calculate_until(DnsResourceRecord *rr, usec_t timestamp, bool use_soa_minimum) { + uint32_t ttl; + usec_t u; + + assert(rr); + + ttl = rr->ttl; + if (rr->key->type == DNS_TYPE_SOA && use_soa_minimum) { + /* If this is a SOA RR, and it is requested, clamp to + * the SOA's minimum field. This is used when we do + * negative caching, to determine the TTL for the + * negative caching entry. See RFC 2308, Section + * 5. */ + + if (ttl > rr->soa.minimum) + ttl = rr->soa.minimum; + } + + u = ttl * USEC_PER_SEC; + if (u > CACHE_TTL_MAX_USEC) + u = CACHE_TTL_MAX_USEC; + + if (rr->expiry != USEC_INFINITY) { + usec_t left; + + /* Make use of the DNSSEC RRSIG expiry info, if we + * have it */ + + left = LESS_BY(rr->expiry, now(CLOCK_REALTIME)); + if (u > left) + u = left; + } + + return timestamp + u; +} + static void dns_cache_item_update_positive( DnsCache *c, DnsCacheItem *i, @@ -302,7 +338,7 @@ static void dns_cache_item_update_positive( dns_resource_key_unref(i->key); i->key = dns_resource_key_ref(rr->key); - i->until = timestamp + MIN(rr->ttl * USEC_PER_SEC, CACHE_TTL_MAX_USEC); + i->until = calculate_until(rr, timestamp, false); i->authenticated = authenticated; i->shared_owner = shared_owner; @@ -383,7 +419,7 @@ static int dns_cache_put_positive( i->type = DNS_CACHE_POSITIVE; i->key = dns_resource_key_ref(rr->key); i->rr = dns_resource_record_ref(rr); - i->until = timestamp + MIN(i->rr->ttl * USEC_PER_SEC, CACHE_TTL_MAX_USEC); + i->until = calculate_until(rr, timestamp, false); i->authenticated = authenticated; i->shared_owner = shared_owner; i->owner_family = owner_family; @@ -412,7 +448,7 @@ static int dns_cache_put_negative( int rcode, bool authenticated, usec_t timestamp, - uint32_t soa_ttl, + DnsResourceRecord *soa, int owner_family, const union in_addr_union *owner_address) { @@ -422,6 +458,7 @@ static int dns_cache_put_negative( assert(c); assert(key); + assert(soa); assert(owner_address); /* Never cache pseudo RR keys. DNS_TYPE_ANY is particularly @@ -432,7 +469,7 @@ static int dns_cache_put_negative( if (dns_type_is_pseudo(key->type)) return 0; - if (soa_ttl <= 0) { + if (soa->soa.minimum <= 0 || soa->ttl <= 0) { if (log_get_max_level() >= LOG_DEBUG) { r = dns_resource_key_to_string(key, &key_str); if (r < 0) @@ -458,7 +495,7 @@ static int dns_cache_put_negative( return -ENOMEM; i->type = rcode == DNS_RCODE_SUCCESS ? DNS_CACHE_NODATA : DNS_CACHE_NXDOMAIN; - i->until = timestamp + MIN(soa_ttl * USEC_PER_SEC, CACHE_TTL_MAX_USEC); + i->until = calculate_until(soa, timestamp, true); i->authenticated = authenticated; i->owner_family = owner_family; i->owner_address = *owner_address; @@ -470,6 +507,14 @@ static int dns_cache_put_negative( i->key = dns_resource_key_new(key->class, DNS_TYPE_ANY, DNS_RESOURCE_KEY_NAME(key)); if (!i->key) return -ENOMEM; + + /* Make sure to remove any previous entry for this + * specific ANY key. (For non-ANY keys the cache data + * is already cleared by the caller.) Note that we + * don't bother removing positive or NODATA cache + * items in this case, because it would either be slow + * or require explicit indexing by name */ + dns_cache_remove_by_key(c, key); } else i->key = dns_resource_key_ref(key); @@ -607,7 +652,6 @@ int dns_cache_put( /* See https://tools.ietf.org/html/rfc2308, which say that a * matching SOA record in the packet is used to to enable * negative caching. */ - r = dns_answer_find_soa(answer, key, &soa, &flags); if (r < 0) goto fail; @@ -625,7 +669,7 @@ int dns_cache_put( rcode, authenticated, timestamp, - MIN(soa->soa.minimum, soa->ttl), + soa, owner_family, owner_address); if (r < 0) goto fail; @@ -672,11 +716,7 @@ static DnsCacheItem *dns_cache_get_by_key_follow_cname_dname_nsec(DnsCache *c, D if (i && i->type == DNS_CACHE_NXDOMAIN) return i; - /* The following record types should never be redirected. See - * <https://tools.ietf.org/html/rfc4035#section-2.5>. */ - if (!IN_SET(k->type, DNS_TYPE_CNAME, DNS_TYPE_DNAME, - DNS_TYPE_NSEC3, DNS_TYPE_NSEC, DNS_TYPE_RRSIG, - DNS_TYPE_NXT, DNS_TYPE_SIG, DNS_TYPE_KEY)) { + if (dns_type_may_redirect(k->type)) { /* Check if we have a CNAME record instead */ i = hashmap_get(c->by_key, &DNS_RESOURCE_KEY_CONST(k->class, DNS_TYPE_CNAME, n)); if (i) @@ -737,6 +777,8 @@ int dns_cache_lookup(DnsCache *c, DnsResourceKey *key, int *rcode, DnsAnswer **r log_debug("Ignoring cache for ANY lookup: %s", key_str); } + c->n_miss++; + *ret = NULL; *rcode = DNS_RCODE_SUCCESS; return 0; @@ -754,6 +796,8 @@ int dns_cache_lookup(DnsCache *c, DnsResourceKey *key, int *rcode, DnsAnswer **r log_debug("Cache miss for %s", key_str); } + c->n_miss++; + *ret = NULL; *rcode = DNS_RCODE_SUCCESS; return 0; @@ -791,9 +835,15 @@ int dns_cache_lookup(DnsCache *c, DnsResourceKey *key, int *rcode, DnsAnswer **r *rcode = DNS_RCODE_SUCCESS; *authenticated = nsec->authenticated; - return !bitmap_isset(nsec->rr->nsec.types, key->type) && - !bitmap_isset(nsec->rr->nsec.types, DNS_TYPE_CNAME) && - !bitmap_isset(nsec->rr->nsec.types, DNS_TYPE_DNAME); + if (!bitmap_isset(nsec->rr->nsec.types, key->type) && + !bitmap_isset(nsec->rr->nsec.types, DNS_TYPE_CNAME) && + !bitmap_isset(nsec->rr->nsec.types, DNS_TYPE_DNAME)) { + c->n_hit++; + return 1; + } + + c->n_miss++; + return 0; } if (log_get_max_level() >= LOG_DEBUG) { @@ -808,6 +858,8 @@ int dns_cache_lookup(DnsCache *c, DnsResourceKey *key, int *rcode, DnsAnswer **r } if (n <= 0) { + c->n_hit++; + *ret = NULL; *rcode = nxdomain ? DNS_RCODE_NXDOMAIN : DNS_RCODE_SUCCESS; *authenticated = have_authenticated && !have_non_authenticated; @@ -827,6 +879,8 @@ int dns_cache_lookup(DnsCache *c, DnsResourceKey *key, int *rcode, DnsAnswer **r return r; } + c->n_hit++; + *ret = answer; *rcode = DNS_RCODE_SUCCESS; *authenticated = have_authenticated && !have_non_authenticated; @@ -935,13 +989,13 @@ void dns_cache_dump(DnsCache *cache, FILE *f) { DnsCacheItem *j; LIST_FOREACH(by_key, j, i) { - _cleanup_free_ char *t = NULL; fputc('\t', f); if (j->rr) { - r = dns_resource_record_to_string(j->rr, &t); - if (r < 0) { + const char *t; + t = dns_resource_record_to_string(j->rr); + if (!t) { log_oom(); continue; } @@ -949,13 +1003,14 @@ void dns_cache_dump(DnsCache *cache, FILE *f) { fputs(t, f); fputc('\n', f); } else { - r = dns_resource_key_to_string(j->key, &t); + _cleanup_free_ char *z = NULL; + r = dns_resource_key_to_string(j->key, &z); if (r < 0) { log_oom(); continue; } - fputs(t, f); + fputs(z, f); fputs(" -- ", f); fputs(j->type == DNS_CACHE_NODATA ? "NODATA" : "NXDOMAIN", f); fputc('\n', f); @@ -970,3 +1025,10 @@ bool dns_cache_is_empty(DnsCache *cache) { return hashmap_isempty(cache->by_key); } + +unsigned dns_cache_size(DnsCache *cache) { + if (!cache) + return 0; + + return hashmap_size(cache->by_key); +} |