]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
resolved: use RRSIG expiry and original TTL for cache management
authorLennart Poettering <lennart@poettering.net>
Sun, 27 Dec 2015 23:30:56 +0000 (00:30 +0100)
committerLennart Poettering <lennart@poettering.net>
Mon, 28 Dec 2015 13:46:39 +0000 (14:46 +0100)
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.

src/resolve/resolved-dns-cache.c
src/resolve/resolved-dns-dnssec.c
src/resolve/resolved-dns-rr.c
src/resolve/resolved-dns-rr.h

index 49d5090d3670546ee92bc1f5eda60f962844504f..413e1080d9be9f9b83a086a6cd464f1066e070b8 100644 (file)
@@ -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;
index 57093ad80cf9261b13f300d4d98d39d0988303b8..94543fef3ac60e78e2e509b6742a0a2cb3ee3a6e 100644 (file)
@@ -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;
 
index 04d442bf0322e22cdef34b6e2bf437ce48069484..d479de7125e3c8a47444b7e4a67794caea6b41bd 100644 (file)
@@ -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;
 }
index 95d260f7aa63646a0c57c96786fe9972ce3e3c17..fccc4dba6a1041532aa34f9a30319106dfe8184d 100644 (file)
@@ -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;