From 3a3e7a049f2ffd00e4e9db87e081ce24d458b5fc Mon Sep 17 00:00:00 2001 From: DL6ER Date: Tue, 13 Oct 2026 17:00:24 +0200 Subject: [PATCH] Fix the NSEC3 closest encloser check for deeper wildcard answers `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 --- 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))