From 14bb1f8aa0a088881340ab2fb1859d96fca077b0 Mon Sep 17 00:00:00 2001 From: Mark Andrews Date: Thu, 10 Oct 2024 16:39:10 +1100 Subject: [PATCH 1/2] Use a binary search to find the NSEC3 closest encloser maxlabels is the suffix length that corresponds to the latest NXDOMAIN response. minlabels is the suffix length that corresponds to longest found existing name. (cherry picked from commit 67f31c504679dfcd9f1231037afa56da01e40d36) --- lib/ns/query.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/lib/ns/query.c b/lib/ns/query.c index 17f2592c2e..05e6086ea2 100644 --- a/lib/ns/query.c +++ b/lib/ns/query.c @@ -11311,24 +11311,33 @@ again: * No NSEC proof available, return NSEC3 proofs instead. */ cname = dns_fixedname_initname(&cfixed); + /* - * Find the closest encloser. + * Find the closest encloser using a binary search. + * maxlabels: suffix length of NXDOMAIN result + * minlabels: suffix length of non NXDOMAIN result */ + unsigned int maxlabels = dns_name_countlabels(name); + unsigned int minlabels = dns_name_countlabels(fname); + bool search = result == DNS_R_NXDOMAIN; dns_name_copy(name, cname); - while (result == DNS_R_NXDOMAIN) { - labels = dns_name_countlabels(cname) - 1; - /* - * Sanity check. - */ - if (labels == 0U) { - goto cleanup; + while (search) { + labels = (maxlabels + minlabels) / 2; + dns_name_split(name, labels, NULL, cname); + if (labels == minlabels) { + break; } - dns_name_split(cname, labels, NULL, cname); result = dns_db_findext(qctx->db, cname, qctx->version, dns_rdatatype_nsec, options, 0, NULL, fname, &cm, &ci, NULL, NULL); + if (result == DNS_R_NXDOMAIN) { + maxlabels = labels; + } else { + minlabels = labels; + } } + /* * Add closest (provable) encloser NSEC3. */ From fd2f1bdf02c77a005e0ab843ea08605986851fe7 Mon Sep 17 00:00:00 2001 From: Mark Andrews Date: Thu, 10 Oct 2024 18:29:02 +1100 Subject: [PATCH 2/2] Test that the correct NSEC3 closest encloser is returned (cherry picked from commit b457f64d4a171181440058b68cf7d59a77d38ad3) --- bin/tests/system/dnssec/tests.sh | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/bin/tests/system/dnssec/tests.sh b/bin/tests/system/dnssec/tests.sh index f2b7b76685..839384217b 100644 --- a/bin/tests/system/dnssec/tests.sh +++ b/bin/tests/system/dnssec/tests.sh @@ -4487,5 +4487,35 @@ n=$((n + 1)) if [ "$ret" -ne 0 ]; then echo_i "failed"; fi status=$((status + ret)) +echo_i "checking NSEC3 nxdomain response closest encloser with 0 ENT ($n)" +ret=0 +dig_with_opts @10.53.0.3 b.b.b.b.b.a.nsec3.example. >dig.out.ns3.test$n +grep "status: NXDOMAIN" dig.out.ns3.test$n >/dev/null || ret=1 +pat="^6OVDUHTN094ML2PV8AN90U0DPU823GH2\.nsec3.example\..*NSEC3 1 0 0 - 7AT0S0RIDCJRFF2M5H5AAV22CSFJBUL4 A RRSIG\$" +grep "$pat" dig.out.ns3.test$n >/dev/null || ret=1 +n=$((n + 1)) +if [ "$ret" -ne 0 ]; then echo_i "failed"; fi +status=$((status + ret)) + +echo_i "checking NSEC3 nxdomain response closest encloser with 1 ENTs ($n)" +ret=0 +dig_with_opts @10.53.0.3 b.b.b.b.b.a.a.nsec3.example. >dig.out.ns3.test$n +grep "status: NXDOMAIN" dig.out.ns3.test$n >/dev/null || ret=1 +pat="^NGCJFSOLJUUE27PFNQNJIME4TQ0OU2DH\.nsec3.example\..*NSEC3 1 0 0 - R8EVDMNIGNOKME4LH2H90OSP2PRSNJ1Q\$" +grep "$pat" dig.out.ns3.test$n >/dev/null || ret=1 +n=$((n + 1)) +if [ "$ret" -ne 0 ]; then echo_i "failed"; fi +status=$((status + ret)) + +echo_i "checking NSEC3 nxdomain response closest encloser with 2 ENTs ($n)" +ret=0 +dig_with_opts @10.53.0.3 b.b.b.b.b.a.a.a.nsec3.example. >dig.out.ns3.test$n +grep "status: NXDOMAIN" dig.out.ns3.test$n >/dev/null || ret=1 +pat="^H7RHPDCHSVVRAND332F878C8AB6IBJQV\.nsec3.example\..*NSEC3 1 0 0 - K8IG76R2UPQ13IKFO49L7IB9JRVB6QJI\$" +grep "$pat" dig.out.ns3.test$n >/dev/null || ret=1 +n=$((n + 1)) +if [ "$ret" -ne 0 ]; then echo_i "failed"; fi +status=$((status + ret)) + echo_i "exit status: $status" [ $status -eq 0 ] || exit 1