mirror of
https://github.com/pi-hole/dnsmasq.git
synced 2025-12-19 18:28:25 +00:00
More DNSSEC cache readout.
This commit is contained in:
33
src/cache.c
33
src/cache.c
@@ -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
|
|||||||
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)
|
|||||||
{
|
{
|
||||||
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 {
|
|||||||
} 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 {
|
||||||
|
|||||||
24
src/dnssec.c
24
src/dnssec.c
@@ -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
|
|||||||
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
|
|||||||
|
|
||||||
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
|
|||||||
|
|
||||||
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
|
|||||||
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
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
}
|
}
|
||||||
|
|
||||||
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,
|
|||||||
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. */
|
||||||
|
|||||||
Reference in New Issue
Block a user