mirror of
https://github.com/pi-hole/dnsmasq.git
synced 2025-12-19 18:28:25 +00:00
Fix DNSSEC caching problems: incomplete RRSIG RRsets.
This commit is contained in:
@@ -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
|
|||||||
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 */
|
||||||
|
|||||||
118
src/rfc1035.c
118
src/rfc1035.c
@@ -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;
|
|
||||||
auth = 0;
|
|
||||||
}
|
|
||||||
else if (qtype == T_DS && have_rrsig)
|
|
||||||
{
|
|
||||||
auth = 0;
|
|
||||||
crecp = NULL;
|
crecp = NULL;
|
||||||
while ((crecp = cache_find_by_name(crecp, name, now, F_DS)))
|
while ((crecp = cache_find_by_name(crecp, name, now, F_DNSKEY | F_DS)))
|
||||||
if (crecp->uid == qclass)
|
if (crecp->uid == qclass && crecp->addr.sig.type_covered == qtype)
|
||||||
{
|
break;
|
||||||
ans = gotone = 1;
|
}
|
||||||
if (!dryrun && (keydata = blockdata_retrieve(crecp->addr.ds.keydata, crecp->addr.ds.keylen, NULL)))
|
|
||||||
|
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)
|
||||||
{
|
{
|
||||||
struct all_addr a;
|
gotone = 1;
|
||||||
a.addr.keytag = crecp->addr.ds.keytag;
|
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");
|
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,
|
|||||||
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)
|
|
||||||
{
|
|
||||||
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 */
|
|
||||||
{
|
|
||||||
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++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else /* DNSKEY */
|
||||||
|
{
|
||||||
|
crecp = NULL;
|
||||||
|
while ((crecp = cache_find_by_name(crecp, name, now, F_DNSKEY)))
|
||||||
|
if (crecp->uid == qclass)
|
||||||
|
{
|
||||||
|
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 */
|
/* 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
|
||||||
|
|||||||
Reference in New Issue
Block a user