Commit 824202ef authored by Simon Kelley's avatar Simon Kelley

More DNSSEC cache readout.

parent 9ebfca1e
...@@ -345,30 +345,10 @@ static int cache_scan_free(char *name, struct all_addr *addr, time_t now, unsign ...@@ -345,30 +345,10 @@ static int cache_scan_free(char *name, struct all_addr *addr, time_t now, unsign
#ifdef HAVE_DNSSEC #ifdef HAVE_DNSSEC
/* Deletion has to be class-sensitive for DS, DNSKEY, RRSIG, also /* Deletion has to be class-sensitive for DS, DNSKEY, RRSIG, also
type-covered sensitive for RRSIG */ type-covered sensitive for RRSIG */
if ((flags & (F_DNSKEY | F_DS)) == (crecp->flags & (F_DNSKEY | F_DS))) if ((flags & (F_DNSKEY | F_DS)) == (crecp->flags & (F_DNSKEY | F_DS)) &&
{ crecp->uid == addr->addr.dnssec.class &&
int del = 0; (!((flags & (F_DS | F_DNSKEY)) == (F_DS | F_DNSKEY)) ||
switch (flags & (F_DS | F_DNSKEY)) crecp->addr.sig.type_covered == addr->addr.dnssec.type))
{
case F_DS:
if (crecp->addr.ds.class == addr->addr.dnssec.class)
del = 1;
break;
case F_DNSKEY:
if (crecp->addr.key.class == addr->addr.dnssec.class)
del = 1;
break;
/* Both set -> RRSIG */
case F_DS | F_DNSKEY:
if (crecp->addr.sig.class == addr->addr.dnssec.class &&
crecp->addr.sig.type_covered == addr->addr.dnssec.type)
del = 1;
break;
}
if (del)
{ {
if (crecp->flags & F_CONFIG) if (crecp->flags & F_CONFIG)
return 0; return 0;
...@@ -377,7 +357,6 @@ static int cache_scan_free(char *name, struct all_addr *addr, time_t now, unsign ...@@ -377,7 +357,6 @@ static int cache_scan_free(char *name, struct all_addr *addr, time_t now, unsign
cache_free(crecp); cache_free(crecp);
continue; continue;
} }
}
#endif #endif
} }
up = &crecp->hash_next; up = &crecp->hash_next;
...@@ -1020,11 +999,11 @@ void cache_reload(void) ...@@ -1020,11 +999,11 @@ void cache_reload(void)
{ {
cache->flags = F_FORWARD | F_IMMORTAL | F_DNSKEY | F_CONFIG | F_NAMEP; cache->flags = F_FORWARD | F_IMMORTAL | F_DNSKEY | F_CONFIG | F_NAMEP;
cache->name.namep = key->name; cache->name.namep = key->name;
cache->uid = key->keylen; cache->addr.key.keylen = key->keylen;
cache->addr.key.algo = key->algo; cache->addr.key.algo = key->algo;
cache->addr.key.flags = key->flags; cache->addr.key.flags = key->flags;
cache->addr.key.keytag = dnskey_keytag(key->algo, key->flags, (unsigned char *)key->key, key->keylen); cache->addr.key.keytag = dnskey_keytag(key->algo, key->flags, (unsigned char *)key->key, key->keylen);
cache->addr.key.class = C_IN; /* TODO - in option? */ cache->uid = C_IN; /* TODO - in option? */
cache_hash(cache); cache_hash(cache);
} }
#endif #endif
......
...@@ -368,23 +368,23 @@ struct crec { ...@@ -368,23 +368,23 @@ struct crec {
} cname; } cname;
struct { struct {
struct blockdata *keydata; struct blockdata *keydata;
unsigned short class, flags, keytag; unsigned short keylen, flags, keytag;
unsigned char algo; unsigned char algo;
} key; } key;
struct { struct {
struct blockdata *keydata; struct blockdata *keydata;
unsigned short class, keytag; unsigned short keylen, keytag;
unsigned char algo; unsigned char algo;
unsigned char digest; unsigned char digest;
} ds; } ds;
struct { struct {
struct blockdata *keydata; struct blockdata *keydata;
unsigned short class, type_covered, keytag; unsigned short keylen, type_covered, keytag;
char algo; char algo;
} sig; } sig;
} addr; } addr;
time_t ttd; /* time to die */ time_t ttd; /* time to die */
/* used as keylen if F_DNSKEY or F_DS, index to source for F_HOSTS */ /* used as class if DNSKEY/DS/RRSIG, index to source for F_HOSTS */
int uid; int uid;
unsigned short flags; unsigned short flags;
union { union {
......
...@@ -594,9 +594,9 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in ...@@ -594,9 +594,9 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
if ((block = blockdata_alloc((char*)pdata + 2, rdlen)) && if ((block = blockdata_alloc((char*)pdata + 2, rdlen)) &&
(crecp = cache_insert(name, &a, now, ttl, F_FORWARD | F_DNSKEY | F_DS))) (crecp = cache_insert(name, &a, now, ttl, F_FORWARD | F_DNSKEY | F_DS)))
{ {
crecp->uid = rdlen; crecp->uid = class;
crecp->addr.sig.keydata = block; crecp->addr.sig.keydata = block;
crecp->addr.sig.class = class; crecp->addr.sig.keylen = rdlen;
crecp->addr.sig.keytag = key_tag; crecp->addr.sig.keytag = key_tag;
crecp->addr.sig.type_covered = type_covered; crecp->addr.sig.type_covered = type_covered;
crecp->addr.sig.algo = algo; crecp->addr.sig.algo = algo;
...@@ -737,8 +737,8 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in ...@@ -737,8 +737,8 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
for (; crecp; crecp = cache_find_by_name(crecp, keyname, now, F_DNSKEY)) for (; crecp; crecp = cache_find_by_name(crecp, keyname, now, F_DNSKEY))
if (crecp->addr.key.algo == algo && if (crecp->addr.key.algo == algo &&
crecp->addr.key.keytag == key_tag && crecp->addr.key.keytag == key_tag &&
crecp->addr.key.class == class && crecp->uid == class &&
verify(crecp->addr.key.keydata, crecp->uid, sig, sig_len, digest, algo)) verify(crecp->addr.key.keydata, crecp->addr.key.keylen, sig, sig_len, digest, algo))
return STAT_SECURE; return STAT_SECURE;
} }
} }
...@@ -837,7 +837,7 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch ...@@ -837,7 +837,7 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
if (recp1->addr.ds.algo == algo && if (recp1->addr.ds.algo == algo &&
recp1->addr.ds.keytag == keytag && recp1->addr.ds.keytag == keytag &&
recp1->addr.ds.class == class && recp1->uid == class &&
(hash = hash_find(ds_digest_name(recp1->addr.ds.digest))) && (hash = hash_find(ds_digest_name(recp1->addr.ds.digest))) &&
hash_init(hash, &ctx, &digest)) hash_init(hash, &ctx, &digest))
...@@ -852,9 +852,9 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch ...@@ -852,9 +852,9 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
from_wire(name); from_wire(name);
if (recp1->uid == (int)hash->digest_size && if (recp1->addr.ds.keylen == (int)hash->digest_size &&
(ds_digest = blockdata_retrieve(recp1->addr.key.keydata, recp1->uid, NULL)) && (ds_digest = blockdata_retrieve(recp1->addr.key.keydata, recp1->addr.ds.keylen, NULL)) &&
memcmp(ds_digest, digest, recp1->uid) == 0 && memcmp(ds_digest, digest, recp1->addr.ds.keylen) == 0 &&
validate_rrset(now, header, plen, class, T_DNSKEY, name, keyname, key, rdlen - 4, algo, keytag)) validate_rrset(now, header, plen, class, T_DNSKEY, name, keyname, key, rdlen - 4, algo, keytag))
{ {
valid = 1; valid = 1;
...@@ -913,12 +913,12 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch ...@@ -913,12 +913,12 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
a.addr.keytag = keytag; a.addr.keytag = keytag;
log_query(F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %u"); log_query(F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %u");
recp1->uid = rdlen - 4; recp1->addr.key.keylen = rdlen - 4;
recp1->addr.key.keydata = key; recp1->addr.key.keydata = key;
recp1->addr.key.algo = algo; recp1->addr.key.algo = algo;
recp1->addr.key.keytag = keytag; recp1->addr.key.keytag = keytag;
recp1->addr.key.flags = flags; recp1->addr.key.flags = flags;
recp1->addr.key.class = class; recp1->uid = class;
} }
p = psave; p = psave;
...@@ -1131,8 +1131,8 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch ...@@ -1131,8 +1131,8 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
crecp->addr.ds.keydata = key; crecp->addr.ds.keydata = key;
crecp->addr.ds.algo = algo; crecp->addr.ds.algo = algo;
crecp->addr.ds.keytag = keytag; crecp->addr.ds.keytag = keytag;
crecp->addr.ds.class = class2; crecp->uid = class2;
crecp->uid = rdlen2 - 4; crecp->addr.ds.keylen = rdlen2 - 4;
} }
p2 = psave; p2 = psave;
......
...@@ -1549,9 +1549,9 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, ...@@ -1549,9 +1549,9 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
do { do {
char *keydata; char *keydata;
if (crecp->addr.ds.class == qclass && if (crecp->uid == qclass &&
(qtype == T_DNSKEY || (crecp->flags & F_CONFIG)) && (qtype == T_DNSKEY || (crecp->flags & F_CONFIG)) &&
(keydata = blockdata_retrieve(crecp->addr.key.keydata, crecp->uid, NULL))) (keydata = blockdata_retrieve(crecp->addr.key.keydata, crecp->addr.key.keylen, NULL)))
{ {
ans = 1; ans = 1;
if (!dryrun) if (!dryrun)
...@@ -1562,7 +1562,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, ...@@ -1562,7 +1562,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
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->uid, keydata)) crecp->addr.key.flags, 3, crecp->addr.key.algo, crecp->addr.key.keylen, keydata))
anscount++; anscount++;
} }
} }
...@@ -1574,9 +1574,9 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, ...@@ -1574,9 +1574,9 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
do { do {
char *keydata; char *keydata;
if (crecp->addr.ds.class == qclass && if (crecp->uid == qclass &&
(qtype == T_DS || (crecp->flags & F_CONFIG)) && (qtype == T_DS || (crecp->flags & F_CONFIG)) &&
(keydata = blockdata_retrieve(crecp->addr.ds.keydata, crecp->uid, NULL))) (keydata = blockdata_retrieve(crecp->addr.ds.keydata, crecp->addr.ds.keylen, NULL)))
{ {
ans = 1; ans = 1;
if (!dryrun) if (!dryrun)
...@@ -1587,7 +1587,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, ...@@ -1587,7 +1587,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
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_DS, qclass, "sbbt", T_DS, qclass, "sbbt",
crecp->addr.ds.keytag, crecp->addr.ds.algo, crecp->addr.ds.digest, crecp->uid, keydata)) crecp->addr.ds.keytag, crecp->addr.ds.algo, crecp->addr.ds.digest, crecp->addr.ds.keylen, keydata))
anscount++; anscount++;
} }
} }
...@@ -1860,6 +1860,44 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, ...@@ -1860,6 +1860,44 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
crecp = save; crecp = save;
} }
#ifdef HAVE_DNSSEC
if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) &&
(crecp->flags & F_DNSSECOK) &&
!(crecp->flags & F_NEG) &&
sec_reqd &&
option_bool(OPT_DNSSEC_VALID))
{
/* We're returning validated data, need to return the RRSIG too. */
int sigtype = type;
/* The signature may have expired even though the data is still in cache,
forward instead of answering from cache if so. */
int gotsig = 0;
if (crecp->flags & F_CNAME)
sigtype = T_CNAME;
crecp = NULL;
while ((crecp = cache_find_by_name(crecp, name, now, F_DS | F_DNSKEY)))
{
if (crecp->addr.sig.type_covered == sigtype && crecp->uid == C_IN)
{
char *sigdata = blockdata_retrieve(crecp->addr.sig.keydata, crecp->addr.sig.keylen, NULL);
gotsig = 1;
if (!dryrun &&
add_resource_record(header, limit, &trunc, nameoffset, &ansp,
crecp->ttd - now, &nameoffset,
T_RRSIG, C_IN, "t", crecp->addr.sig.keylen, sigdata))
anscount++;
}
}
/* Need to re-run original cache search */
crecp = gotsig ? cache_find_by_name(NULL, name, now, flag | F_CNAME) : NULL;
}
#endif
if (crecp)
do do
{ {
/* don't answer wildcard queries with data not from /etc/hosts /* don't answer wildcard queries with data not from /etc/hosts
...@@ -1892,6 +1930,10 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, ...@@ -1892,6 +1930,10 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
} }
if (crecp->flags & F_NEG) if (crecp->flags & F_NEG)
{
/* We don't cache NSEC records, so if a DNSSEC-validated negative answer
is cached and the client wants DNSSEC, forward rather than answering from the cache */
if (!sec_reqd || !(crecp->flags & F_DNSSECOK))
{ {
ans = 1; ans = 1;
auth = 0; auth = 0;
...@@ -1900,7 +1942,8 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, ...@@ -1900,7 +1942,8 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
if (!dryrun) if (!dryrun)
log_query(crecp->flags, name, NULL, NULL); log_query(crecp->flags, name, NULL, NULL);
} }
else if ((crecp->flags & (F_HOSTS | F_DHCP)) || !sec_reqd || option_bool(OPT_DNSSEC_VALID)) }
else
{ {
/* If we are returning local answers depending on network, /* If we are returning local answers depending on network,
filter here. */ filter here. */
......
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