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