c7e749
From 40d08c8b1de73d74701b52e59baeb9bb5652cb9e Mon Sep 17 00:00:00 2001
c7e749
From: Simon Kelley <simon@thekelleys.org.uk>
c7e749
Date: Thu, 12 Nov 2020 18:49:23 +0000
c7e749
Subject: [PATCH] Check destination of DNS UDP query replies.
c7e749
c7e749
At any time, dnsmasq will have a set of sockets open, bound to
c7e749
random ports, on which it sends queries to upstream nameservers.
c7e749
This patch fixes the existing problem that a reply for ANY in-flight
c7e749
query would be accepted via ANY open port, which increases the
c7e749
chances of an attacker flooding answers "in the blind" in an
c7e749
attempt to poison the DNS cache. CERT VU#434904 refers.
c7e749
---
c7e749
 src/forward.c | 37 ++++++++++++++++++++++++++++---------
c7e749
 1 file changed, 28 insertions(+), 9 deletions(-)
c7e749
c7e749
diff --git a/src/forward.c b/src/forward.c
c7e749
index 720b503..e210864 100644
c7e749
--- a/src/forward.c
c7e749
+++ b/src/forward.c
c7e749
@@ -16,7 +16,7 @@
c7e749
 
c7e749
 #include "dnsmasq.h"
c7e749
 
c7e749
-static struct frec *lookup_frec(unsigned short id, void *hash);
c7e749
+static struct frec *lookup_frec(unsigned short id, int fd, int family, void *hash);
c7e749
 static struct frec *lookup_frec_by_sender(unsigned short id,
c7e749
 					  union mysockaddr *addr,
c7e749
 					  void *hash);
c7e749
@@ -779,7 +779,7 @@ void reply_query(int fd, int family, time_t now)
c7e749
   crc = questions_crc(header, n, daemon->namebuff);
c7e749
 #endif
c7e749
   
c7e749
-  if (!(forward = lookup_frec(ntohs(header->id), hash)))
c7e749
+  if (!(forward = lookup_frec(ntohs(header->id), fd, family, hash)))
c7e749
     return;
c7e749
   
c7e749
   /* log_query gets called indirectly all over the place, so 
c7e749
@@ -2174,14 +2174,25 @@ struct frec *get_new_frec(time_t now, int *wait, int force)
c7e749
 }
c7e749
  
c7e749
 /* crc is all-ones if not known. */
c7e749
-static struct frec *lookup_frec(unsigned short id, void *hash)
c7e749
+static struct frec *lookup_frec(unsigned short id, int fd, int family, void *hash)
c7e749
 {
c7e749
   struct frec *f;
c7e749
 
c7e749
   for(f = daemon->frec_list; f; f = f->next)
c7e749
     if (f->sentto && f->new_id == id && 
c7e749
 	(!hash || memcmp(hash, f->hash, HASH_SIZE) == 0))
c7e749
-      return f;
c7e749
+      {
c7e749
+	/* sent from random port */
c7e749
+	if (family == AF_INET && f->rfd4 && f->rfd4->fd == fd)
c7e749
+	  return f;
c7e749
+
c7e749
+	if (family == AF_INET6 && f->rfd6 && f->rfd6->fd == fd)
c7e749
+	  return f;
c7e749
+
c7e749
+	/* sent to upstream from bound socket. */
c7e749
+	if (f->sentto->sfd && f->sentto->sfd->fd == fd)
c7e749
+	  return f;
c7e749
+      }
c7e749
       
c7e749
   return NULL;
c7e749
 }
c7e749
@@ -2242,12 +2253,20 @@ void server_gone(struct server *server)
c7e749
 static unsigned short get_id(void)
c7e749
 {
c7e749
   unsigned short ret = 0;
c7e749
+  struct frec *f;
c7e749
   
c7e749
-  do 
c7e749
-    ret = rand16();
c7e749
-  while (lookup_frec(ret, NULL));
c7e749
-  
c7e749
-  return ret;
c7e749
+  while (1)
c7e749
+    {
c7e749
+      ret = rand16();
c7e749
+
c7e749
+      /* ensure id is unique. */
c7e749
+      for (f = daemon->frec_list; f; f = f->next)
c7e749
+	if (f->sentto && f->new_id == ret)
c7e749
+	  break;
c7e749
+
c7e749
+      if (!f)
c7e749
+	return ret;
c7e749
+    }
c7e749
 }
c7e749
 
c7e749
 
c7e749
-- 
c7e749
2.26.2
c7e749