From: Lennart Poettering Date: Sun, 27 Dec 2015 23:30:56 +0000 (+0100) Subject: resolved: use RRSIG expiry and original TTL for cache management X-Git-Tag: v229~187^2~2 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=ee3d6aff9bd73c1b23e29d1fa1fa6f7a1ef0533b;p=thirdparty%2Fsystemd.git resolved: use RRSIG expiry and original TTL for cache management When we verified a signature, fix up the RR's TTL to the original TTL mentioned in the signature, and store the signature expiry information in the RR, too. Then, use that when adding RRs to the cache. --- diff --git a/src/resolve/resolved-dns-cache.c b/src/resolve/resolved-dns-cache.c index 49d5090d367..413e1080d9b 100644 --- a/src/resolve/resolved-dns-cache.c +++ b/src/resolve/resolved-dns-cache.c @@ -272,6 +272,30 @@ static DnsCacheItem* dns_cache_get(DnsCache *c, DnsResourceRecord *rr) { return NULL; } +static usec_t calculate_until(DnsResourceRecord *rr, usec_t timestamp) { + usec_t ttl; + + assert(rr); + + ttl = rr->ttl * USEC_PER_SEC; + + if (ttl > CACHE_TTL_MAX_USEC) + ttl = 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 (ttl > left) + ttl = left; + } + + return timestamp + ttl; +} + static void dns_cache_item_update_positive( DnsCache *c, DnsCacheItem *i, @@ -302,7 +326,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); i->authenticated = authenticated; i->shared_owner = shared_owner; @@ -383,7 +407,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); i->authenticated = authenticated; i->shared_owner = shared_owner; i->owner_family = owner_family; diff --git a/src/resolve/resolved-dns-dnssec.c b/src/resolve/resolved-dns-dnssec.c index 57093ad80cf..94543fef3ac 100644 --- a/src/resolve/resolved-dns-dnssec.c +++ b/src/resolve/resolved-dns-dnssec.c @@ -701,6 +701,30 @@ int dnssec_key_match_rrsig(const DnsResourceKey *key, DnsResourceRecord *rrsig) return dns_name_equal(DNS_RESOURCE_KEY_NAME(rrsig->key), DNS_RESOURCE_KEY_NAME(key)); } +static int dnssec_fix_rrset_ttl(DnsAnswer *a, const DnsResourceKey *key, DnsResourceRecord *rrsig, usec_t realtime) { + DnsResourceRecord *rr; + int r; + + assert(key); + assert(rrsig); + + DNS_ANSWER_FOREACH(rr, a) { + r = dns_resource_key_equal(key, rr->key); + if (r < 0) + return r; + if (r == 0) + continue; + + /* Pick the TTL as the minimum of the RR's TTL, the + * RR's original TTL according to the RRSIG and the + * RRSIG's own TTL, see RFC 4035, Section 5.3.3 */ + rr->ttl = MIN3(rr->ttl, rrsig->rrsig.original_ttl, rrsig->ttl); + rr->expiry = rrsig->rrsig.expiration * USEC_PER_SEC; + } + + return 0; +} + int dnssec_verify_rrset_search( DnsAnswer *a, DnsResourceKey *key, @@ -767,7 +791,11 @@ int dnssec_verify_rrset_search( case DNSSEC_VALIDATED: /* Yay, the RR has been validated, - * return immediately. */ + * return immediately, but fix up the expiry */ + r = dnssec_fix_rrset_ttl(a, key, rrsig, realtime); + if (r < 0) + return r; + *result = DNSSEC_VALIDATED; return 0; diff --git a/src/resolve/resolved-dns-rr.c b/src/resolve/resolved-dns-rr.c index 04d442bf032..d479de7125e 100644 --- a/src/resolve/resolved-dns-rr.c +++ b/src/resolve/resolved-dns-rr.c @@ -339,6 +339,7 @@ DnsResourceRecord* dns_resource_record_new(DnsResourceKey *key) { rr->n_ref = 1; rr->key = dns_resource_key_ref(key); + rr->expiry = USEC_INFINITY; return rr; } diff --git a/src/resolve/resolved-dns-rr.h b/src/resolve/resolved-dns-rr.h index 95d260f7aa6..fccc4dba6a1 100644 --- a/src/resolve/resolved-dns-rr.h +++ b/src/resolve/resolved-dns-rr.h @@ -100,6 +100,7 @@ struct DnsResourceRecord { DnsResourceKey *key; char *to_string; uint32_t ttl; + usec_t expiry; /* RRSIG signature expiry */ bool unparseable:1; bool wire_format_canonical:1; void *wire_format;