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 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. */