[Dnsmasq-discuss] [PATCH] Fix the NSEC3 closest encloser check for deeper wildcard answers
Dominik Derigs
git at dl6er.de
Tue Oct 13 15:00:24 UTC 2026
From: DL6ER <dl6er at dl6er.de>
`validate_rrset()` returns the start of the closest encloser as an offset
into the owner name, and `prove_non_existence_nsec3()` is meant to stop
its search there. It compares `name - closest_encloser` with that offset,
but `closest_encloser` only moves forward from `name`, so the difference
is never positive and the search never stops at the encloser the RRSIG
labels field gives.
A wildcard answer one label below the closest encloser is not affected,
as the NSEC3 covering the next closer name covers the query name itself.
Two or more labels below, dnsmasq looks for an NSEC3 matching the closest
encloser, which RFC 5155 section 7.2.6 does not require the zone to send,
and returns SERVFAIL with EDE 12 (NSEC Missing). An example is
foo.login.us2.yubico.com, answered from *.us2.yubico.com.
The comparison came with f603a4f ("Fix a corner-case in DNSSEC validation
with wildcards."), which replaced the name compare. Swap the operands.
Signed-off-by: DL6ER <dl6er at dl6er.de>
---
Hi Simon,
since f603a4f, dnsmasq returns SERVFAIL with EDE 12 (NSEC Missing) for
NSEC3-signed wildcard answers two or more labels below the closest
encloser. The offset check in prove_non_existence_nsec3() has its
operands swapped, so the search never stops at the closest encloser the
RRSIG labels give.
Reproducer, against a public resolver:
dnsmasq -d --port=5353 --no-resolv --server=1.0.0.1 --dnssec --conf-file=trust-anchors.conf
dig -p 5353 @127.0.0.1 foo.login.us2.yubico.com A
This gives SERVFAIL on current master and NOERROR with AD with the
patch. login.us2.yubico.com, one label below *.us2.yubico.com, validates
either way, and NXDOMAIN proofs from NSEC3 zones (nic.cz, isc.org) are
unchanged.
Downstream report: https://github.com/pi-hole/FTL/issues/3161
Best regards,
Dominik
src/dnssec.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/dnssec.c b/src/dnssec.c
index f874b61..01b18b9 100644
--- a/src/dnssec.c
+++ b/src/dnssec.c
@@ -1643,7 +1643,7 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
if (*closest_encloser == '.')
closest_encloser++;
- if (wild_offset != 0 && name - closest_encloser == wild_offset)
+ if (wild_offset != 0 && closest_encloser - name == wild_offset)
break;
if (dec_counter(validate_counter, NULL))
--
2.43.0
More information about the Dnsmasq-discuss
mailing list