]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Fix "rndc flushname" for longer name server names
authorMichał Kępień <michal@isc.org>
Thu, 30 Jan 2025 06:44:18 +0000 (07:44 +0100)
committerMichał Kępień <michal@isc.org>
Thu, 30 Jan 2025 06:44:18 +0000 (07:44 +0100)
dns_adb_flushname() calls dns_name_hash() to determine the ADB bucket
number to search for the given name.  Meanwhile, all other functions in
lib/dns/adb.c call dns_name_fullhash() for determining the bucket number
instead.  This discrepancy causes dns_adb_flushname() to have virtually
no chances of actually removing the given name from the ADB if the
name is longer than 16 bytes (since dns_name_hash() only hashes the
first 16 bytes of the name provided to it) - more specifically, the
probability of success for names longer than 16 bytes is inversely
proportional to the number of ADB buckets in use, i.e. 1:1021 at best.

Fix by using dns_name_fullhash() instead of dns_name_hash() in
dns_adb_flushname(), so that the logic for determining the bucket number
that a given name belongs to is consistent throughout lib/dns/adb.c.

bin/tests/system/cacheclean/tests.sh
lib/dns/adb.c

index 141716a28196ba4f4c97cb62cddc0034b27681c2..726e7dc240ee571615ebe8c7a053dffbd3110e3e 100755 (executable)
@@ -239,25 +239,38 @@ nrecords=$(filter_tree flushtest.example ns2/named_dump.db.test$n | grep -E '(TX
 if [ $ret != 0 ]; then echo_i "failed"; fi
 status=$((status + ret))
 
+run_adb_flush_test() {
+  ret=0
+  load_cache
+  dump_cache
+  mv ns2/named_dump.db.test$n ns2/named_dump.db.test$n.a
+  sed -n '/plain success\/timeout/,/Unassociated entries/p' \
+    ns2/named_dump.db.test$n.a >sed.out.$n.a
+  grep 'plain success/timeout' sed.out.$n.a >/dev/null 2>&1 || ret=1
+  grep 'Unassociated entries' sed.out.$n.a >/dev/null 2>&1 || ret=1
+  grep 'ns.flushtest.example' sed.out.$n.a >/dev/null 2>&1 || ret=1
+  $RNDC $RNDCOPTS "$@" || ret=1
+  dump_cache
+  mv ns2/named_dump.db.test$n ns2/named_dump.db.test$n.b
+  sed -n '/plain success\/timeout/,/Unassociated entries/p' \
+    ns2/named_dump.db.test$n.b >sed.out.$n.b
+  grep 'plain success/timeout' sed.out.$n.b >/dev/null 2>&1 || ret=1
+  grep 'Unassociated entries' sed.out.$n.b >/dev/null 2>&1 || ret=1
+  grep 'ns.flushtest.example' sed.out.$n.b >/dev/null 2>&1 && ret=1
+  return $ret
+}
+
+n=$((n + 1))
+echo_i "check flushname clears adb correctly ($n)"
+ret=0
+run_adb_flush_test flushname ns.flushtest.example || ret=1
+if [ $ret != 0 ]; then echo_i "failed"; fi
+status=$((status + ret))
+
 n=$((n + 1))
 echo_i "check flushtree clears adb correctly ($n)"
 ret=0
-load_cache
-dump_cache
-mv ns2/named_dump.db.test$n ns2/named_dump.db.test$n.a
-sed -n '/plain success\/timeout/,/Unassociated entries/p' \
-  ns2/named_dump.db.test$n.a >sed.out.$n.a
-grep 'plain success/timeout' sed.out.$n.a >/dev/null 2>&1 || ret=1
-grep 'Unassociated entries' sed.out.$n.a >/dev/null 2>&1 || ret=1
-grep 'ns.flushtest.example' sed.out.$n.a >/dev/null 2>&1 || ret=1
-$RNDC $RNDCOPTS flushtree flushtest.example || ret=1
-dump_cache
-mv ns2/named_dump.db.test$n ns2/named_dump.db.test$n.b
-sed -n '/plain success\/timeout/,/Unassociated entries/p' \
-  ns2/named_dump.db.test$n.b >sed.out.$n.b
-grep 'plain success/timeout' sed.out.$n.b >/dev/null 2>&1 || ret=1
-grep 'Unassociated entries' sed.out.$n.b >/dev/null 2>&1 || ret=1
-grep 'ns.flushtest.example' sed.out.$n.b >/dev/null 2>&1 && ret=1
+run_adb_flush_test flushtree flushtest.example || ret=1
 if [ $ret != 0 ]; then echo_i "failed"; fi
 status=$((status + ret))
 
index fb79d47ab184c6f1b7b1d992f5512eab2bdab01e..d6cf066493d8e52df1321daf2facb8a83b5ced1d 100644 (file)
@@ -4631,7 +4631,7 @@ dns_adb_flushname(dns_adb_t *adb, const dns_name_t *name) {
        REQUIRE(name != NULL);
 
        LOCK(&adb->lock);
-       bucket = dns_name_hash(name, false) % adb->nnames;
+       bucket = dns_name_fullhash(name, false) % adb->nnames;
        LOCK(&adb->namelocks[bucket]);
        adbname = ISC_LIST_HEAD(adb->names[bucket]);
        while (adbname != NULL) {