Blob Blame History Raw
From 10642f9fb350e118d88e995b8dfa2badc7be1c30 Mon Sep 17 00:00:00 2001
From: Petr Mensik <pemensik@redhat.com>
Date: Wed, 11 Dec 2019 13:41:57 +0100
Subject: [PATCH] Restore ability to answer non-recursive requests

Instead, check only local configured entries are answered without
rdbit set. All cached replies are still denied, but locally configured
names are available with both recursion and without it.
---
 src/rfc1035.c | 27 ++++++++++++++-------------
 1 file changed, 14 insertions(+), 13 deletions(-)

diff --git a/src/rfc1035.c b/src/rfc1035.c
index 6b3bb27..6a7c154 100644
--- a/src/rfc1035.c
+++ b/src/rfc1035.c
@@ -1262,7 +1262,11 @@ static unsigned long crec_ttl(struct crec *crecp, time_t now)
   else
     return daemon->max_ttl;
 }
-  
+
+static int cache_validated(const struct crec *crecp)
+{
+  return (option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK));
+}
 
 /* return zero if we can't answer from cache, or packet size if we can */
 size_t answer_request(struct dns_header *header, char *limit, size_t qlen,  
@@ -1281,6 +1285,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
   int nxdomain = 0, auth = 1, trunc = 0, sec_data = 1;
   struct mx_srv_record *rec;
   size_t len;
+  int rd_bit;
   // Make sure we do not underflow here too.
   if (qlen > (limit - ((char *)header))) return 0;
 
@@ -1290,10 +1295,8 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
       OPCODE(header) != QUERY )
     return 0;
 
-  /* always servfail queries with RD unset, to avoid cache snooping. */
-  if (!(header->hb3 & HB3_RD))
-    return setup_reply(header, qlen, NULL, F_SERVFAIL, 0);
-  
+  rd_bit = (header->hb3 & HB3_RD);
+
   /* Don't return AD set if checking disabled. */
   if (header->hb4 & HB4_CD)
     sec_data = 0;
@@ -1458,9 +1461,8 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
 		  /* Don't use cache when DNSSEC data required, unless we know that
 		     the zone is unsigned, which implies that we're doing
 		     validation. */
-		  if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) || 
-		      !do_bit || 
-		      (option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK)))
+		  if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) ||
+		      (rd_bit && (!do_bit || cache_validated(crecp)) ))
 		    {
 		      do 
 			{ 
@@ -1657,8 +1659,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
 
 		  /* If the client asked for DNSSEC  don't use cached data. */
 		  if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) ||
-		      !do_bit ||
-		      (option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK)))
+		      (rd_bit && (!do_bit || cache_validated(crecp)) ))
 		    do
 		      { 
 			/* don't answer wildcard queries with data not from /etc/hosts
@@ -1741,8 +1742,8 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
 	  if (qtype == T_CNAME || qtype == T_ANY)
 	    {
 	      if ((crecp = cache_find_by_name(NULL, name, now, F_CNAME | (dryrun ? F_NO_RR : 0))) &&
-		  (qtype == T_CNAME || (crecp->flags & F_CONFIG)) &&
-		  ((crecp->flags & F_CONFIG) || !do_bit || (option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK))))
+		  ((qtype == T_CNAME && rd_bit) || (crecp->flags & F_CONFIG)) &&
+		  ((crecp->flags & F_CONFIG) || (!do_bit || cache_validated(crecp))))
 		{
 		  if (!(crecp->flags & F_DNSSECOK))
 		    sec_data = 0;
@@ -1780,7 +1781,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
 		    }
 		  }
 	      
-	      if (!found && (option_bool(OPT_SELFMX) || option_bool(OPT_LOCALMX)) && 
+	      if (!found && (option_bool(OPT_SELFMX) || option_bool(OPT_LOCALMX)) &&
 		  cache_find_by_name(NULL, name, now, F_HOSTS | F_DHCP | F_NO_RR))
 		{ 
 		  ans = 1;
-- 
2.21.0