a7b456
From 6ff6c5003120fbb609cb2e2739679fd4583731f6 Mon Sep 17 00:00:00 2001
a7b456
From: Simon Kelley <simon@thekelleys.org.uk>
a7b456
Date: Wed, 19 Sep 2018 22:27:11 +0100
a7b456
Subject: [PATCH] Change behavior when RD bit unset in queries.
a7b456
a7b456
Change anti cache-snooping behaviour with queries with the
a7b456
recursion-desired bit unset. Instead to returning SERVFAIL, we
a7b456
now always forward, and never answer from the cache. This
a7b456
allows "dig +trace" command to work.
a7b456
a7b456
(cherry picked from commit 4139298d287eb5c57f4aa53c459cb02fc5be2495)
a7b456
a7b456
Restore ability to answer non-recursive requests
a7b456
a7b456
Instead, check only local configured entries are answered without
a7b456
rdbit set. All cached replies are still denied, but locally configured
a7b456
names are available with both recursion and without it.
a7b456
a7b456
Fixes commit 4139298d287eb5c57f4aa53c459cb02fc5be2495 unintended
a7b456
behaviour.
a7b456
a7b456
(cherry picked from commit 29ae3083981ea82f535f77ea54bbd538f1224a9e)
a7b456
---
a7b456
 src/rfc1035.c | 19 ++++++++++---------
a7b456
 1 file changed, 10 insertions(+), 9 deletions(-)
a7b456
a7b456
diff --git a/src/rfc1035.c b/src/rfc1035.c
a7b456
index 96acae9..ae2cc96 100644
a7b456
--- a/src/rfc1035.c
a7b456
+++ b/src/rfc1035.c
a7b456
@@ -1252,7 +1252,6 @@ static unsigned long crec_ttl(struct crec *crecp, time_t now)
a7b456
   else
a7b456
     return daemon->max_ttl;
a7b456
 }
a7b456
-  
a7b456
 
a7b456
 /* return zero if we can't answer from cache, or packet size if we can */
a7b456
 size_t answer_request(struct dns_header *header, char *limit, size_t qlen,  
a7b456
@@ -1271,12 +1270,15 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
a7b456
   int nxdomain = 0, auth = 1, trunc = 0, sec_data = 1;
a7b456
   struct mx_srv_record *rec;
a7b456
   size_t len;
a7b456
+  int rd_bit;
a7b456
   // Make sure we do not underflow here too.
a7b456
   if (qlen > (limit - ((char *)header))) return 0;
a7b456
+  rd_bit = (header->hb3 & HB3_RD);
a7b456
   
a7b456
+  /* never answer queries with RD unset, to avoid cache snooping. */
a7b456
   if (ntohs(header->ancount) != 0 ||
a7b456
       ntohs(header->nscount) != 0 ||
a7b456
-      ntohs(header->qdcount) == 0 || 
a7b456
+      ntohs(header->qdcount) == 0 ||
a7b456
       OPCODE(header) != QUERY )
a7b456
     return 0;
a7b456
   
a7b456
@@ -1443,9 +1445,8 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
a7b456
 		  /* Don't use cache when DNSSEC data required, unless we know that
a7b456
 		     the zone is unsigned, which implies that we're doing
a7b456
 		     validation. */
a7b456
-		  if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) || 
a7b456
-		      !do_bit || 
a7b456
-		      (option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK)))
a7b456
+		  if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) ||
a7b456
+		      (rd_bit && (!do_bit || (option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK)))))
a7b456
 		    {
a7b456
 		      do 
a7b456
 			{ 
a7b456
@@ -1633,8 +1634,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
a7b456
 
a7b456
 		  /* If the client asked for DNSSEC  don't use cached data. */
a7b456
 		  if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) ||
a7b456
-		      !do_bit ||
a7b456
-		      (option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK)))
a7b456
+		      (rd_bit && (!do_bit || (option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK))) ))
a7b456
 		    do
a7b456
 		      { 
a7b456
 			/* don't answer wildcard queries with data not from /etc/hosts
a7b456
@@ -1718,7 +1718,8 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
a7b456
 	    {
a7b456
 	      if ((crecp = cache_find_by_name(NULL, name, now, F_CNAME | (dryrun ? F_NO_RR : 0))) &&
a7b456
 		  (qtype == T_CNAME || (crecp->flags & F_CONFIG)) &&
a7b456
-		  ((crecp->flags & F_CONFIG) || !do_bit || (option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK))))
a7b456
+		  ((crecp->flags & F_CONFIG) ||
a7b456
+		   (rd_bit && (!do_bit || (option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK))))))
a7b456
 		{
a7b456
 		  if (!(crecp->flags & F_DNSSECOK))
a7b456
 		    sec_data = 0;
a7b456
@@ -1756,7 +1757,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
a7b456
 		    }
a7b456
 		  }
a7b456
 	      
a7b456
-	      if (!found && (option_bool(OPT_SELFMX) || option_bool(OPT_LOCALMX)) && 
a7b456
+	      if (!found && (option_bool(OPT_SELFMX) || option_bool(OPT_LOCALMX)) &&
a7b456
 		  cache_find_by_name(NULL, name, now, F_HOSTS | F_DHCP | F_NO_RR))
a7b456
 		{ 
a7b456
 		  ans = 1;
a7b456
-- 
a7b456
2.21.1
a7b456