Fix "rndc flushname" for longer name server names

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.
This commit is contained in:
Michał Kępień 2025-01-30 07:44:18 +01:00
parent 73997c8161
commit 64367010f2
No known key found for this signature in database
2 changed files with 30 additions and 17 deletions

View file

@ -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))

View 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) {