db0bc30
From a997ca0da044719a0ce8a232d14da8b30022592b Mon Sep 17 00:00:00 2001
db0bc30
From: Simon Kelley <simon@thekelleys.org.uk>
db0bc30
Date: Fri, 29 Jun 2018 14:39:41 +0100
db0bc30
Subject: [PATCH] Fix sometimes missing DNSSEC RRs when DNSSEC validation not
db0bc30
 enabled.
db0bc30
db0bc30
Dnsmasq does pass on the do-bit, and return DNSSEC RRs, irrespective
db0bc30
of of having DNSSEC validation compiled in or enabled.
db0bc30
db0bc30
The thing to understand here is that the cache does not store all the
db0bc30
DNSSEC RRs, and dnsmasq doesn't have the (very complex) logic required
db0bc30
to determine the set of DNSSEC RRs required in an answer. Therefore if
db0bc30
the client wants the DNSSEC RRs, the query can not be answered from
db0bc30
the cache. When DNSSEC validation is enabled, any query with the
db0bc30
do-bit set is never answered from the cache, unless the domain is
db0bc30
known not to be signed: the query is always forwarded. This ensures
db0bc30
that the DNSEC RRs are included.
db0bc30
db0bc30
The same thing should be true when DNSSEC validation is not enabled,
db0bc30
but there's a bug in the logic.
db0bc30
db0bc30
line 1666 of src/rfc1035.c looks like this
db0bc30
db0bc30
 if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) || !do_bit || !(crecp->flags & F_DNSSECOK))
db0bc30
db0bc30
{ ...answer from cache ... }
db0bc30
db0bc30
So local stuff (hosts, DHCP, ) get answered. If the do_bit is not set
db0bc30
then the query is answered, and if the domain is known not to be
db0bc30
signed, the query is answered.
db0bc30
db0bc30
Unfortunately, if DNSSEC validation is not turned on then the
db0bc30
F_DNSSECOK bit is not valid, and it's always zero, so the question
db0bc30
always gets answered from the cache, even when the do-bit is set.
db0bc30
db0bc30
This code should look like that at line 1468, dealing with PTR queries
db0bc30
db0bc30
  if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) ||
db0bc30
      !do_bit ||
db0bc30
      (option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK)))
db0bc30
db0bc30
where the F_DNSSECOK bit is only used when validation is enabled.
db0bc30
---
db0bc30
 src/rfc1035.c | 6 ++++--
db0bc30
 1 file changed, 4 insertions(+), 2 deletions(-)
db0bc30
db0bc30
diff --git a/src/rfc1035.c b/src/rfc1035.c
db0bc30
index ebb1f36..580f5ef 100644
db0bc30
--- a/src/rfc1035.c
db0bc30
+++ b/src/rfc1035.c
db0bc30
@@ -1663,7 +1663,9 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
db0bc30
 		    }
db0bc30
 
db0bc30
 		  /* If the client asked for DNSSEC  don't use cached data. */
db0bc30
-		  if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) || !do_bit || !(crecp->flags & F_DNSSECOK))
db0bc30
+		  if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) ||
db0bc30
+		      !do_bit ||
db0bc30
+		      (option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK)))
db0bc30
 		    do
db0bc30
 		      { 
db0bc30
 			/* don't answer wildcard queries with data not from /etc/hosts
db0bc30
@@ -1747,7 +1749,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
db0bc30
 	    {
db0bc30
 	      if ((crecp = cache_find_by_name(NULL, name, now, F_CNAME | (dryrun ? F_NO_RR : 0))) &&
db0bc30
 		  (qtype == T_CNAME || (crecp->flags & F_CONFIG)) &&
db0bc30
-		  ((crecp->flags & F_CONFIG) || !do_bit || !(crecp->flags & F_DNSSECOK)))
db0bc30
+		  ((crecp->flags & F_CONFIG) || !do_bit || (option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK))))
db0bc30
 		{
db0bc30
 		  if (!(crecp->flags & F_DNSSECOK))
db0bc30
 		    sec_data = 0;
db0bc30
-- 
db0bc30
2.14.4
db0bc30