From 67f31c504679dfcd9f1231037afa56da01e40d36 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. --- 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 7f900de9eb..94d0859afa 100644 --- a/lib/ns/query.c +++ b/lib/ns/query.c @@ -10956,24 +10956,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 b457f64d4a171181440058b68cf7d59a77d38ad3 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 --- 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