From c8ca33f810e25e15296926f569c8e82420d5fdd3 Mon Sep 17 00:00:00 2001 From: Simon Kelley Date: Mon, 10 Feb 2014 10:35:42 +0000 Subject: [PATCH] Fix DNSSEC caching problems: incomplete RRSIG RRsets. --- src/cache.c | 2 +- src/dnssec.c | 1 + src/rfc1035.c | 120 ++++++++++++++++++++++++-------------------------- 3 files changed, 60 insertions(+), 63 deletions(-) diff --git a/src/cache.c b/src/cache.c index 66b52d2..9407636 100644 --- a/src/cache.c +++ b/src/cache.c @@ -460,7 +460,7 @@ struct crec *cache_insert(char *name, struct all_addr *addr, return NULL; /* First remove any expired entries and entries for the name/address we - are currently inserting. Fail is we attempt to delete a name from + are currently inserting. Fail if we attempt to delete a name from /etc/hosts or DHCP. */ if (!cache_scan_free(name, addr, now, flags)) { diff --git a/src/dnssec.c b/src/dnssec.c index 8263b3e..b97f47b 100644 --- a/src/dnssec.c +++ b/src/dnssec.c @@ -1168,6 +1168,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch type_covered == T_DNSKEY || type_covered == T_PTR)) { a.addr.dnssec.type = type_covered; + a.addr.dnssec.class = class1; algo = *p2++; p2 += 13; /* labels, orig_ttl, expiration, inception */ diff --git a/src/rfc1035.c b/src/rfc1035.c index 5515ea5..e0bf47e 100644 --- a/src/rfc1035.c +++ b/src/rfc1035.c @@ -1551,37 +1551,33 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, } #ifdef HAVE_DNSSEC - if (option_bool(OPT_DNSSEC_VALID) && (qtype == T_DNSKEY || qtype == T_DS || qtype == T_RRSIG)) + if (option_bool(OPT_DNSSEC_VALID) && (qtype == T_DNSKEY || qtype == T_DS)) { - int gotone = 0, have_rrsig = 0; + int gotone = 0; struct blockdata *keydata; /* Do we have RRSIG? Can't do DS or DNSKEY otherwise. */ - crecp = NULL; - while ((crecp = cache_find_by_name(crecp, name, now, F_DNSKEY | F_DS))) - if (crecp->uid == qclass && (qtype == T_RRSIG || crecp->addr.sig.type_covered == qtype)) - { - have_rrsig = 1; - break; - } - - if (qtype == T_RRSIG && have_rrsig) + if (sec_reqd) { - ans = gotone = 1; - auth = 0; - } - else if (qtype == T_DS && have_rrsig) - { - auth = 0; crecp = NULL; - while ((crecp = cache_find_by_name(crecp, name, now, F_DS))) - if (crecp->uid == qclass) - { - ans = gotone = 1; - if (!dryrun && (keydata = blockdata_retrieve(crecp->addr.ds.keydata, crecp->addr.ds.keylen, NULL))) - { - struct all_addr a; - a.addr.keytag = crecp->addr.ds.keytag; + while ((crecp = cache_find_by_name(crecp, name, now, F_DNSKEY | F_DS))) + if (crecp->uid == qclass && crecp->addr.sig.type_covered == qtype) + break; + } + + if (!sec_reqd || crecp) + { + if (qtype == T_DS) + { + crecp = NULL; + while ((crecp = cache_find_by_name(crecp, name, now, F_DS))) + if (crecp->uid == qclass) + { + gotone = 1; + if (!dryrun && (keydata = blockdata_retrieve(crecp->addr.ds.keydata, crecp->addr.ds.keylen, NULL))) + { + struct all_addr a; + a.addr.keytag = crecp->addr.ds.keytag; log_query(F_KEYTAG | (crecp->flags & F_CONFIG), name, &a, "DS keytag %u"); if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, crec_ttl(crecp, now), &nameoffset, @@ -1589,52 +1585,52 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, crecp->addr.ds.keytag, crecp->addr.ds.algo, crecp->addr.ds.digest, crecp->addr.ds.keylen, keydata)) anscount++; - } - } - } - else if (qtype == T_DNSKEY) - { - crecp = NULL; - while ((crecp = cache_find_by_name(crecp, name, now, F_DNSKEY))) - if (crecp->uid == qclass) - { - if ((crecp->flags & F_CONFIG) || have_rrsig) /* Return configured keys without an RRISG */ + } + } + } + else /* DNSKEY */ + { + crecp = NULL; + while ((crecp = cache_find_by_name(crecp, name, now, F_DNSKEY))) + if (crecp->uid == qclass) { - if (!(crecp->flags & F_CONFIG)) - auth = 0, gotone = 1; - ans = 1; - if (!dryrun && (keydata = blockdata_retrieve(crecp->addr.key.keydata, crecp->addr.key.keylen, NULL))) - { - struct all_addr a; - a.addr.keytag = crecp->addr.key.keytag; - log_query(F_KEYTAG | (crecp->flags & F_CONFIG), name, &a, "DNSKEY keytag %u"); - if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, - crec_ttl(crecp, now), &nameoffset, - T_DNSKEY, qclass, "sbbt", - crecp->addr.key.flags, 3, crecp->addr.key.algo, crecp->addr.key.keylen, keydata)) - anscount++; + if (!(crecp->flags & F_CONFIG)) /* Don't return configured keys - send upstream instead */ + { + gotone = 1; + if (!dryrun && (keydata = blockdata_retrieve(crecp->addr.key.keydata, crecp->addr.key.keylen, NULL))) + { + struct all_addr a; + a.addr.keytag = crecp->addr.key.keytag; + log_query(F_KEYTAG | (crecp->flags & F_CONFIG), name, &a, "DNSKEY keytag %u"); + if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, + crec_ttl(crecp, now), &nameoffset, + T_DNSKEY, qclass, "sbbt", + crecp->addr.key.flags, 3, crecp->addr.key.algo, crecp->addr.key.keylen, keydata)) + anscount++; + } } } - } + } } - + /* Now do RRSIGs */ if (gotone) { - crecp = NULL; - while ((crecp = cache_find_by_name(crecp, name, now, F_DNSKEY | F_DS))) - if (crecp->uid == qclass && (qtype == T_RRSIG || (sec_reqd && crecp->addr.sig.type_covered == qtype)) && - !dryrun && - (keydata = blockdata_retrieve(crecp->addr.sig.keydata, crecp->addr.sig.keylen, NULL))) - { - if (qtype == T_RRSIG) - log_query(F_RRNAME, name, NULL, querystr("rrsig", crecp->addr.sig.type_covered)); - if ((keydata = blockdata_retrieve(crecp->addr.sig.keydata, crecp->addr.sig.keylen, NULL)) && + ans = 1; + auth = 0; + if (!dryrun && sec_reqd) + { + crecp = NULL; + while ((crecp = cache_find_by_name(crecp, name, now, F_DNSKEY | F_DS))) + if (crecp->uid == qclass && crecp->addr.sig.type_covered == qtype && + (keydata = blockdata_retrieve(crecp->addr.sig.keydata, crecp->addr.sig.keylen, NULL))) + { add_resource_record(header, limit, &trunc, nameoffset, &ansp, crec_ttl(crecp, now), &nameoffset, - T_RRSIG, qclass, "t", crecp->addr.sig.keylen, keydata)) - anscount++; - } + T_RRSIG, qclass, "t", crecp->addr.sig.keylen, keydata); + anscount++; + } + } } } #endif