diff --git a/src/resolve/resolved-dns-cache.c b/src/resolve/resolved-dns-cache.c index 49d5090d36..413e1080d9 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 57093ad80c..94543fef3a 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 04d442bf03..d479de7125 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 95d260f7aa..fccc4dba6a 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;