[PATCH] dnsmasq: add fix related to DNSSEC verification from upstream

Uwe Kleine-König uwe+openwrt at kleine-koenig.org
Mon Jan 27 07:12:23 PST 2025


To find the DS record for a given zone the parent zone's nameserver must
be queried and not the nameserver for the zone. Otherwise DNSSEC
verification for unsigned delegations breaks.

Signed-off-by: Uwe Kleine-König <uwe+openwrt at kleine-koenig.org>
---
Hello,

this patch fixes DNSSEC verification when dnsmasq serves an (unsigned)
zone under a signed parent zone.

It makes the difference between:

	$ delv ares.kk2.kleine-koenig.org
	;; no valid RRSIG resolving 'kk2.kleine-koenig.org/DS/IN': 127.0.0.53#53
	;; broken trust chain resolving 'ares.kk2.kleine-koenig.org/A/IN': 127.0.0.53#53
	;; resolution failed: broken trust chain

(previous behaviour) and

	$ delv ares.kk2.kleine-koenig.org
	; unsigned answer
	ares.kk2.kleine-koenig.org. 600	IN	A	192.168.137.18

(new behaviour).

This patch fits on the openwrt-24.10 branch and also on top of main.
(However main has a patch to dnsmasq and I'm unsure how to handle
bumping PKG_RELEASE there.)

This patch is contained in dnsmasq v2.91test8 which I expect to lead to
v2.91 soon, but not before the expected release of OpenWrt 24.10. So I'm
forwarding this patch. Note that Simon Kelly found a few more fixes that
are in upstream git and the most recent release is v2.91test9. But this
patch is enought to fix operation for me.

This is a followup to my patch that updates dnsmasq to 2.91test8 which
hauke in irc indicated was not ok to go into 24.10.

Thanks for considering it for inclusion in openwrt-24.10.

Best regards
Uwe

 package/network/services/dnsmasq/Makefile     |   2 +-
 ...0003-Handle-DS-queries-to-auth-zones.patch | 100 ++++++++++++++++++
 2 files changed, 101 insertions(+), 1 deletion(-)
 create mode 100644 package/network/services/dnsmasq/patches/0003-Handle-DS-queries-to-auth-zones.patch

diff --git a/package/network/services/dnsmasq/Makefile b/package/network/services/dnsmasq/Makefile
index 0a597c03ce40..47a5ae54ae7f 100644
--- a/package/network/services/dnsmasq/Makefile
+++ b/package/network/services/dnsmasq/Makefile
@@ -10,7 +10,7 @@ include $(TOPDIR)/rules.mk
 PKG_NAME:=dnsmasq
 PKG_UPSTREAM_VERSION:=2.90
 PKG_VERSION:=$(subst test,~~test,$(subst rc,~rc,$(PKG_UPSTREAM_VERSION)))
-PKG_RELEASE:=3
+PKG_RELEASE:=4
 
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_UPSTREAM_VERSION).tar.xz
 PKG_SOURCE_URL:=https://thekelleys.org.uk/dnsmasq/
diff --git a/package/network/services/dnsmasq/patches/0003-Handle-DS-queries-to-auth-zones.patch b/package/network/services/dnsmasq/patches/0003-Handle-DS-queries-to-auth-zones.patch
new file mode 100644
index 000000000000..c4c8744e23a7
--- /dev/null
+++ b/package/network/services/dnsmasq/patches/0003-Handle-DS-queries-to-auth-zones.patch
@@ -0,0 +1,100 @@
+From 8ce27433f8b2e17c557cb55e4f16941d309deeac Mon Sep 17 00:00:00 2001
+From: Simon Kelley <simon at thekelleys.org.uk>
+Date: Fri, 17 Jan 2025 17:49:29 +0000
+Subject: [PATCH] Handle DS queries to auth zones.
+Origin: upstream, v2.91test8
+
+When dnsmasq is configured to act as an authoritative server and has
+an authoritative zone configured, and recieves a query for
+that zone _as_forwarder_ it answers the query directly rather
+than forwarding it. This doesn't affect the answer, but it
+saves dnsmasq forwarding the query to the recusor upstream,
+whch then bounces it back to dnsmasq in auth mode. The
+exception should be when the query is for the root of zone, for a DS
+RR. The answer to that has to come from the parent, via the
+recursor, and will typically be a proof-of-nonexistence since
+dnsmasq doesn't support signed zones. This patch suppresses
+local answers and forces forwarding to the upstream recursor
+for such queries. It stops breakage when a DNSSEC validating
+client makes queries to dnsmasq acting as forwarder for a zone
+for which it is authoritative.
+
+[ukleinek: drop changes to CHANGELOG to prevent conflicts]
+---
+ src/forward.c | 52 +++++++++++++++++++++++++++++++++++++--------------
+ 1 file changed, 38 insertions(+), 14 deletions(-)
+
+diff --git a/src/forward.c b/src/forward.c
+index 32f37e4054ba..a197594386dd 100644
+--- a/src/forward.c
++++ b/src/forward.c
+@@ -1744,15 +1744,27 @@ void receive_query(struct listener *listen, time_t now)
+ #endif
+ 
+ #ifdef HAVE_AUTH
+-      /* find queries for zones we're authoritative for, and answer them directly */
++      /* Find queries for zones we're authoritative for, and answer them directly.
++	 The exception to this is DS queries for the zone route. They
++	 have to come from the parent zone. Since dnsmasq's auth server
++	 can't do DNSSEC, the zone will be unsigned, and anything using
++	 dnsmasq as a forwarder and doing validation will be expecting to
++	 see the proof of non-existence from the parent. */
+       if (!auth_dns && !option_bool(OPT_LOCALISE))
+ 	for (zone = daemon->auth_zones; zone; zone = zone->next)
+-	  if (in_zone(zone, daemon->namebuff, NULL))
+-	    {
+-	      auth_dns = 1;
+-	      local_auth = 1;
+-	      break;
+-	    }
++	  {
++	    char *cut;
++	    
++	    if (in_zone(zone, daemon->namebuff, &cut))
++	      {
++		if (type != T_DS || cut)
++		  {
++		    auth_dns = 1;
++		    local_auth = 1;
++		  }
++		break;
++	      }
++	  }
+ #endif
+       
+ #ifdef HAVE_LOOP
+@@ -2268,15 +2280,27 @@ unsigned char *tcp_request(int confd, time_t now,
+ 				   &peer_addr, auth_dns ? "auth" : "query", qtype);
+ 	      
+ #ifdef HAVE_AUTH
+-	      /* find queries for zones we're authoritative for, and answer them directly */
++	      /* Find queries for zones we're authoritative for, and answer them directly.
++		 The exception to this is DS queries for the zone route. They
++		 have to come from the parent zone. Since dnsmasq's auth server
++		 can't do DNSSEC, the zone will be unsigned, and anything using
++		 dnsmasq as a forwarder and doing validation will be expecting to
++		 see the proof of non-existence from the parent. */
+ 	      if (!auth_dns && !option_bool(OPT_LOCALISE))
+ 		for (zone = daemon->auth_zones; zone; zone = zone->next)
+-		  if (in_zone(zone, daemon->namebuff, NULL))
+-		    {
+-		      auth_dns = 1;
+-		      local_auth = 1;
+-		      break;
+-		    }
++		  {
++		    char *cut;
++		    
++		    if (in_zone(zone, daemon->namebuff, &cut))
++		      {
++			if (qtype != T_DS || cut)
++			  {
++			    auth_dns = 1;
++			    local_auth = 1;
++			  }
++			break;
++		      }
++		  }
+ #endif
+ 	    }
+ 	}




More information about the openwrt-devel mailing list