diff --git a/CHANGES b/CHANGES index a5d88d80eb..aa68299913 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,6 @@ +4341. [bug] 'rndc flushtree' could fail to clean the tree if there + wasn't a node at the specified name. [RT #41846] + --- 9.11.0a1 released --- 4341. [bug] Correct the handling of ECS options with diff --git a/bin/tests/system/cacheclean/tests.sh b/bin/tests/system/cacheclean/tests.sh index 86b90a8d7d..0ab44dab03 100644 --- a/bin/tests/system/cacheclean/tests.sh +++ b/bin/tests/system/cacheclean/tests.sh @@ -190,6 +190,22 @@ nrecords=`grep flushtest.example ns2/named_dump.db | grep -v '^;' | egrep '(TXT| if [ $ret != 0 ]; then echo "I:failed"; fi status=`expr $status + $ret` +echo "I:check the check that flushname of a partial match works." +ret=0 +in_cache txt second2.top1.flushtest.example || ret=1 +$RNDC $RNDCOPTS flushtree example +in_cache txt second2.top1.flushtest.example && ret=1 +if [ $ret != 0 ]; then echo "I:failed"; fi +status=`expr $status + $ret` + +echo "I:check the number of cached records remaining" +ret=0 +dump_cache +nrecords=`grep flushtest.example ns2/named_dump.db | grep -v '^;' | egrep '(TXT|ANY)' | wc -l` +[ $nrecords -eq 1 ] || { ret=1; echo "I: found $nrecords records expected 1"; } +if [ $ret != 0 ]; then echo "I:failed"; fi +status=`expr $status + $ret` + echo "I:check flushtree clears adb correctly" ret=0 load_cache diff --git a/lib/dns/cache.c b/lib/dns/cache.c index 83da390b47..514959cf57 100644 --- a/lib/dns/cache.c +++ b/lib/dns/cache.c @@ -1228,6 +1228,8 @@ cleartree(dns_db_t *db, dns_name_t *name) { goto cleanup; result = dns_dbiterator_seek(iter, name); + if (result == DNS_R_PARTIALMATCH) + result = dns_dbiterator_next(iter); if (result != ISC_R_SUCCESS) goto cleanup; @@ -1279,7 +1281,7 @@ dns_cache_flushnode(dns_cache_t *cache, dns_name_t *name, dns_dbnode_t *node = NULL; dns_db_t *db = NULL; - if (dns_name_equal(name, dns_rootname)) + if (tree && dns_name_equal(name, dns_rootname)) return (dns_cache_flush(cache)); LOCK(&cache->lock); diff --git a/lib/dns/include/dns/dbiterator.h b/lib/dns/include/dns/dbiterator.h index 366d6767a7..8f51d1c96f 100644 --- a/lib/dns/include/dns/dbiterator.h +++ b/lib/dns/include/dns/dbiterator.h @@ -166,6 +166,8 @@ dns_dbiterator_seek(dns_dbiterator_t *iterator, dns_name_t *name); * Returns: *\li #ISC_R_SUCCESS *\li #ISC_R_NOTFOUND + *\li #DNS_R_PARTIALMATCH + * (node is at name above requested named when name has children) * *\li Other results are possible, depending on the DB implementation. */ diff --git a/lib/dns/rbtdb.c b/lib/dns/rbtdb.c index d831162001..cb98eeac90 100644 --- a/lib/dns/rbtdb.c +++ b/lib/dns/rbtdb.c @@ -9204,23 +9204,7 @@ dbiterator_seek(dns_dbiterator_t *iterator, dns_name_t *name) { } } -#if 1 - if (result == ISC_R_SUCCESS) { - result = dns_rbtnodechain_current(rbtdbiter->current, iname, - origin, NULL); - if (result == ISC_R_SUCCESS) { - rbtdbiter->new_origin = ISC_TRUE; - reference_iter_node(rbtdbiter); - } - } else if (result == DNS_R_PARTIALMATCH) { - result = ISC_R_NOTFOUND; - rbtdbiter->node = NULL; - } - - rbtdbiter->result = result; -#else if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) { - isc_result_t tresult; tresult = dns_rbtnodechain_current(rbtdbiter->current, iname, origin, NULL); if (tresult == ISC_R_SUCCESS) { @@ -9235,7 +9219,6 @@ dbiterator_seek(dns_dbiterator_t *iterator, dns_name_t *name) { rbtdbiter->result = (result == DNS_R_PARTIALMATCH) ? ISC_R_SUCCESS : result; -#endif return (result); } diff --git a/lib/dns/tests/dbiterator_test.c b/lib/dns/tests/dbiterator_test.c index dc7b37058a..888d3be89d 100644 --- a/lib/dns/tests/dbiterator_test.c +++ b/lib/dns/tests/dbiterator_test.c @@ -318,7 +318,7 @@ static void test_seek_empty(const atf_tc_t *tc) { ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); result = dns_dbiterator_seek(iter, seekname); - ATF_CHECK_EQ(result, ISC_R_NOTFOUND); + ATF_CHECK_EQ(result, DNS_R_PARTIALMATCH); dns_dbiterator_destroy(&iter); dns_db_detach(&db); @@ -374,6 +374,12 @@ static void test_seek_nx(const atf_tc_t *tc) { result = make_name("nonexistent." TEST_ORIGIN, seekname); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + result = dns_dbiterator_seek(iter, seekname); + ATF_CHECK_EQ(result, DNS_R_PARTIALMATCH); + + result = make_name("nonexistent.", seekname); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + result = dns_dbiterator_seek(iter, seekname); ATF_CHECK_EQ(result, ISC_R_NOTFOUND);