Commit c8ca33f8 authored by Simon Kelley's avatar Simon Kelley

Fix DNSSEC caching problems: incomplete RRSIG RRsets.

parent e243c072
...@@ -460,7 +460,7 @@ struct crec *cache_insert(char *name, struct all_addr *addr, ...@@ -460,7 +460,7 @@ struct crec *cache_insert(char *name, struct all_addr *addr,
return NULL; return NULL;
/* First remove any expired entries and entries for the name/address we /* 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. */ /etc/hosts or DHCP. */
if (!cache_scan_free(name, addr, now, flags)) if (!cache_scan_free(name, addr, now, flags))
{ {
......
...@@ -1168,6 +1168,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch ...@@ -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)) type_covered == T_DNSKEY || type_covered == T_PTR))
{ {
a.addr.dnssec.type = type_covered; a.addr.dnssec.type = type_covered;
a.addr.dnssec.class = class1;
algo = *p2++; algo = *p2++;
p2 += 13; /* labels, orig_ttl, expiration, inception */ p2 += 13; /* labels, orig_ttl, expiration, inception */
......
...@@ -1551,37 +1551,33 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, ...@@ -1551,37 +1551,33 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
} }
#ifdef HAVE_DNSSEC #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; struct blockdata *keydata;
/* Do we have RRSIG? Can't do DS or DNSKEY otherwise. */ /* Do we have RRSIG? Can't do DS or DNSKEY otherwise. */
crecp = NULL; if (sec_reqd)
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)
{ {
ans = gotone = 1; crecp = NULL;
auth = 0; while ((crecp = cache_find_by_name(crecp, name, now, F_DNSKEY | F_DS)))
if (crecp->uid == qclass && crecp->addr.sig.type_covered == qtype)
break;
} }
else if (qtype == T_DS && have_rrsig)
if (!sec_reqd || crecp)
{ {
auth = 0; if (qtype == T_DS)
crecp = NULL; {
while ((crecp = cache_find_by_name(crecp, name, now, F_DS))) crecp = NULL;
if (crecp->uid == qclass) 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))) 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; struct all_addr a;
a.addr.keytag = crecp->addr.ds.keytag;
log_query(F_KEYTAG | (crecp->flags & F_CONFIG), name, &a, "DS keytag %u"); log_query(F_KEYTAG | (crecp->flags & F_CONFIG), name, &a, "DS keytag %u");
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
crec_ttl(crecp, now), &nameoffset, crec_ttl(crecp, now), &nameoffset,
...@@ -1589,52 +1585,52 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, ...@@ -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)) crecp->addr.ds.keytag, crecp->addr.ds.algo, crecp->addr.ds.digest, crecp->addr.ds.keylen, keydata))
anscount++; anscount++;
} }
} }
} }
else if (qtype == T_DNSKEY) else /* DNSKEY */
{ {
crecp = NULL; crecp = NULL;
while ((crecp = cache_find_by_name(crecp, name, now, F_DNSKEY))) while ((crecp = cache_find_by_name(crecp, name, now, F_DNSKEY)))
if (crecp->uid == qclass) if (crecp->uid == qclass)
{
if ((crecp->flags & F_CONFIG) || have_rrsig) /* Return configured keys without an RRISG */
{ {
if (!(crecp->flags & F_CONFIG)) if (!(crecp->flags & F_CONFIG)) /* Don't return configured keys - send upstream instead */
auth = 0, gotone = 1; {
ans = 1; gotone = 1;
if (!dryrun && (keydata = blockdata_retrieve(crecp->addr.key.keydata, crecp->addr.key.keylen, NULL))) if (!dryrun && (keydata = blockdata_retrieve(crecp->addr.key.keydata, crecp->addr.key.keylen, NULL)))
{ {
struct all_addr a; struct all_addr a;
a.addr.keytag = crecp->addr.key.keytag; a.addr.keytag = crecp->addr.key.keytag;
log_query(F_KEYTAG | (crecp->flags & F_CONFIG), name, &a, "DNSKEY keytag %u"); log_query(F_KEYTAG | (crecp->flags & F_CONFIG), name, &a, "DNSKEY keytag %u");
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
crec_ttl(crecp, now), &nameoffset, crec_ttl(crecp, now), &nameoffset,
T_DNSKEY, qclass, "sbbt", T_DNSKEY, qclass, "sbbt",
crecp->addr.key.flags, 3, crecp->addr.key.algo, crecp->addr.key.keylen, keydata)) crecp->addr.key.flags, 3, crecp->addr.key.algo, crecp->addr.key.keylen, keydata))
anscount++; anscount++;
}
} }
} }
} }
} }
/* Now do RRSIGs */ /* Now do RRSIGs */
if (gotone) if (gotone)
{ {
crecp = NULL; ans = 1;
while ((crecp = cache_find_by_name(crecp, name, now, F_DNSKEY | F_DS))) auth = 0;
if (crecp->uid == qclass && (qtype == T_RRSIG || (sec_reqd && crecp->addr.sig.type_covered == qtype)) && if (!dryrun && sec_reqd)
!dryrun && {
(keydata = blockdata_retrieve(crecp->addr.sig.keydata, crecp->addr.sig.keylen, NULL))) crecp = NULL;
{ while ((crecp = cache_find_by_name(crecp, name, now, F_DNSKEY | F_DS)))
if (qtype == T_RRSIG) if (crecp->uid == qclass && crecp->addr.sig.type_covered == qtype &&
log_query(F_RRNAME, name, NULL, querystr("rrsig", crecp->addr.sig.type_covered)); (keydata = blockdata_retrieve(crecp->addr.sig.keydata, crecp->addr.sig.keylen, NULL)))
if ((keydata = blockdata_retrieve(crecp->addr.sig.keydata, crecp->addr.sig.keylen, NULL)) && {
add_resource_record(header, limit, &trunc, nameoffset, &ansp, add_resource_record(header, limit, &trunc, nameoffset, &ansp,
crec_ttl(crecp, now), &nameoffset, crec_ttl(crecp, now), &nameoffset,
T_RRSIG, qclass, "t", crecp->addr.sig.keylen, keydata)) T_RRSIG, qclass, "t", crecp->addr.sig.keylen, keydata);
anscount++; anscount++;
} }
}
} }
} }
#endif #endif
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment