Fix subtle bug in arbitrary-RR caching.

If the client asks for DNSSEC RRs via the do bit, and
we have an answer cached, we can only return the cached
answer if the RR was not validated. This is because
we don't the extra info (RRSIGS, NSECs) for a complete
validated answer. In that case we have to forward again.

This bug was that the "is the cache entry validated" test was
in an outer loop rather than an inner one. A cache hit on
a different RRtype that wasn't validated would satify the
condition to use the cache, even if the cache entry for
the required RRtype didn't. The only time when there can be a mix
of validated and non validated cache entries for the same domain
is when most are not validated, but one is a negative cache for
a DS record.

This bug took a long time to find.
This commit is contained in:
Simon Kelley
2025-01-18 22:40:30 +00:00
parent 622cf03ab9
commit 5bbea085d0

View File

@@ -1561,8 +1561,6 @@ static unsigned long crec_ttl(struct crec *crecp, time_t now)
static int cache_validated(const struct crec *crecp)
{
/* return 0; */
return (option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK));
}
@@ -2159,8 +2157,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
if (!ans)
{
if ((crecp = cache_find_by_name(NULL, name, now, F_RR | F_NXDOMAIN)) &&
rd_bit && (!do_bit || cache_validated(crecp)))
if ((crecp = cache_find_by_name(NULL, name, now, F_RR | F_NXDOMAIN)) && rd_bit)
do
{
int flags = crecp->flags;
@@ -2171,7 +2168,8 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
else
rrtype = crecp->addr.rrdata.rrtype;
if ((flags & F_NXDOMAIN) || rrtype == qtype)
if (((flags & F_NXDOMAIN) || rrtype == qtype) &&
(!do_bit || cache_validated(crecp)))
{
char *rrdata = NULL;
unsigned short rrlen = 0;