From 9fa5a723e188ddb5e6165af4957ba789e17cfdf5 Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Wed, 26 Jun 2013 14:59:32 -0700 Subject: [PATCH] [master] "rndc flushtree -all " 3606. [func] "rndc flushtree -all" flushes matching records in the ADB and bad cache as well as the DNS cache. (Without the "-all" option, flushtree will still only flush records from the DNS cache.) [RT #33970] --- CHANGES | 6 +++++ bin/named/server.c | 17 +++++++++----- bin/rndc/rndc.docbook | 10 ++++---- bin/tests/system/cacheclean/tests.sh | 13 ++++++++++- lib/dns/adb.c | 32 +++++++++++++++++++++++++- lib/dns/include/dns/adb.h | 11 +++++++++ lib/dns/include/dns/resolver.h | 10 ++++++++ lib/dns/include/dns/view.h | 13 +++++++---- lib/dns/resolver.c | 34 ++++++++++++++++++++++++++++ lib/dns/view.c | 16 +++++++++---- lib/dns/win32/libdns.def | 2 ++ 11 files changed, 143 insertions(+), 21 deletions(-) diff --git a/CHANGES b/CHANGES index fc06e5fc76..b15040609c 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,9 @@ +3606. [func] "rndc flushtree -all" flushes matching + records in the ADB and bad cache as well as + the DNS cache. (Without the "-all" option, + flushtree will still only flush records from + the DNS cache.) [RT #33970] + 3605. [port] win32: Addressed several compatibility issues with newer versions of Visual Studio. [RT #33916] diff --git a/bin/named/server.c b/bin/named/server.c index 9f69c45a3c..fb1e22f142 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -7614,22 +7614,27 @@ ns_server_flushcache(ns_server_t *server, char *args) { isc_result_t ns_server_flushnode(ns_server_t *server, char *args, isc_boolean_t tree) { - char *ptr, *target, *viewname; + char *target, *viewname; dns_view_t *view; isc_boolean_t flushed; - isc_boolean_t found; + isc_boolean_t found, all = ISC_FALSE; isc_result_t result; isc_buffer_t b; dns_fixedname_t fixed; dns_name_t *name; /* Skip the command name. */ - ptr = next_token(&args, " \t"); - if (ptr == NULL) + target = next_token(&args, " \t"); + if (target == NULL) return (ISC_R_UNEXPECTEDEND); - /* Find the domain name to flush. */ target = next_token(&args, " \t"); + if (strcmp(target, "-all") == 0) { + all = ISC_TRUE; + target = next_token(&args, " \t"); + } + + /* Find the domain name to flush. */ if (target == NULL) return (ISC_R_UNEXPECTEDEND); @@ -7660,7 +7665,7 @@ ns_server_flushnode(ns_server_t *server, char *args, isc_boolean_t tree) { * if some of the views share a single cache. But since the * operation is lightweight we prefer simplicity here. */ - result = dns_view_flushnode(view, name, tree); + result = dns_view_flushnode(view, name, tree, all); if (result != ISC_R_SUCCESS) { flushed = ISC_FALSE; isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, diff --git a/bin/rndc/rndc.docbook b/bin/rndc/rndc.docbook index 17a4d7250d..472a62f8ed 100644 --- a/bin/rndc/rndc.docbook +++ b/bin/rndc/rndc.docbook @@ -518,13 +518,15 @@ - flushtree name view + flushtree -all name view Flushes the given name, and all of its subdomains, - from the server's DNS cache. Note that this does - not affect he server's address - database or bad-server cache. + from the server's DNS cache. By default, this does + not affect the server's address + database or bad-server cache. To eliminate matching + names from those databases as well, use + the option. diff --git a/bin/tests/system/cacheclean/tests.sh b/bin/tests/system/cacheclean/tests.sh index 712d2b22ac..86e318cc4e 100644 --- a/bin/tests/system/cacheclean/tests.sh +++ b/bin/tests/system/cacheclean/tests.sh @@ -65,7 +65,7 @@ EOF dump_cache () { rm -f ns2/named_dump.db - $RNDC $RNDCOPTS dumpdb -cache + $RNDC $RNDCOPTS dumpdb -cache _default sleep 1 } @@ -185,5 +185,16 @@ nrecords=`grep flushtest.example ns2/named_dump.db | grep -v '^;' | grep -Ew '(T if [ $ret != 0 ]; then echo "I:failed"; fi status=`expr $status + $ret` +echo "I:check flushtree -all clears adb correctly" +ret=0 +load_cache +dump_cache +awk '/Address database/ {getline; getline; if ($2 == "ns.flushtest.example") exit(0); exit(1); }' ns2/named_dump.db || ret=1 +$RNDC $RNDCOPTS flushtree -all flushtest.example || ret=1 +dump_cache +awk '/Address database/ {getline; getline; if ($2 == "ns.flushtest.example") exit(1); exit(0); }' ns2/named_dump.db || ret=1 +if [ $ret != 0 ]; then echo "I:failed"; fi +status=`expr $status + $ret` + echo "I:exit status: $status" exit $status diff --git a/lib/dns/adb.c b/lib/dns/adb.c index 455bac68b4..a69f2537fd 100644 --- a/lib/dns/adb.c +++ b/lib/dns/adb.c @@ -4362,7 +4362,8 @@ dns_adb_flushname(dns_adb_t *adb, dns_name_t *name) { dns_adbname_t *nextname; int bucket; - INSIST(DNS_ADB_VALID(adb)); + REQUIRE(DNS_ADB_VALID(adb)); + REQUIRE(name != NULL); LOCK(&adb->lock); bucket = dns_name_hash(name, ISC_FALSE) % adb->nnames; @@ -4382,6 +4383,35 @@ dns_adb_flushname(dns_adb_t *adb, dns_name_t *name) { UNLOCK(&adb->lock); } +void +dns_adb_flushnames(dns_adb_t *adb, dns_name_t *name) { + dns_adbname_t *adbname, *nextname; + unsigned int i; + + REQUIRE(DNS_ADB_VALID(adb)); + REQUIRE(name != NULL); + + LOCK(&adb->lock); + for (i = 0; i < adb->nnames; i++) { + LOCK(&adb->namelocks[i]); + adbname = ISC_LIST_HEAD(adb->names[i]); + while (adbname != NULL) { + isc_boolean_t ret; + nextname = ISC_LIST_NEXT(adbname, plink); + if (!NAME_DEAD(adbname) && + dns_name_issubdomain(&adbname->name, name)) + { + ret = kill_name(&adbname, + DNS_EVENT_ADBCANCELED); + RUNTIME_CHECK(ret == ISC_FALSE); + } + adbname = nextname; + } + UNLOCK(&adb->namelocks[i]); + } + UNLOCK(&adb->lock); +} + static void water(void *arg, int mark) { /* diff --git a/lib/dns/include/dns/adb.h b/lib/dns/include/dns/adb.h index 27ad144311..0d4891a043 100644 --- a/lib/dns/include/dns/adb.h +++ b/lib/dns/include/dns/adb.h @@ -718,6 +718,17 @@ dns_adb_flushname(dns_adb_t *adb, dns_name_t *name); *\li 'name' is valid. */ +void +dns_adb_flushnames(dns_adb_t *adb, dns_name_t *name); +/*%< + * Flush 'name' and all subdomains from the adb cache. + * + * Requires: + *\li 'adb' is valid. + *\li 'name' is valid. + */ + + ISC_LANG_ENDDECLS #endif /* DNS_ADB_H */ diff --git a/lib/dns/include/dns/resolver.h b/lib/dns/include/dns/resolver.h index 2451f9c076..075fa8acb8 100644 --- a/lib/dns/include/dns/resolver.h +++ b/lib/dns/include/dns/resolver.h @@ -589,6 +589,16 @@ dns_resolver_flushbadcache(dns_resolver_t *resolver, dns_name_t *name); * \li resolver to be valid. */ +void +dns_resolver_flushbadnames(dns_resolver_t *resolver, dns_name_t *name); +/*%< + * Flush the bad cache of all entries at or below 'name'. + * + * Requires: + * \li resolver to be valid. + * \li name != NULL + */ + void dns_resolver_printbadcache(dns_resolver_t *resolver, FILE *fp); /*% diff --git a/lib/dns/include/dns/view.h b/lib/dns/include/dns/view.h index 637cf433e1..3e9e2d6640 100644 --- a/lib/dns/include/dns/view.h +++ b/lib/dns/include/dns/view.h @@ -875,15 +875,18 @@ dns_view_flushcache2(dns_view_t *view, isc_boolean_t fixuponly); */ isc_result_t -dns_view_flushnode(dns_view_t *view, dns_name_t *name, isc_boolean_t tree); +dns_view_flushnode(dns_view_t *view, dns_name_t *name, + isc_boolean_t cachetree, isc_boolean_t all); /*%< * Flush the given name from the view's cache (and optionally ADB/badcache). * - * If 'tree' is true, flush 'name' and all names below it - * from the cache, but do not flush ADB. + * If 'cachetree' or 'all' is true, flush 'name' and all names below it + * from the cache. + * If 'all' is true, flush 'name' and all names below it from the ADB + * and badcache. * - * If 'tree' is false, flush 'name' frmo both the cache and ADB, - * but do not touch any other nodes. + * If 'cachetree' and 'all' are false, flush 'name' from both the + * cache and ADB, but do not touch any other nodes. * * Requires: *\li 'view' is valid. diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index 605df695f3..13139ab084 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -8747,6 +8747,40 @@ dns_resolver_flushbadcache(dns_resolver_t *resolver, dns_name_t *name) { } +void +dns_resolver_flushbadnames(dns_resolver_t *resolver, dns_name_t *name) { + dns_badcache_t *bad, *prev, *next; + unsigned int i; + + REQUIRE(VALID_RESOLVER(resolver)); + REQUIRE(name != NULL); + + LOCK(&resolver->lock); + if (resolver->badcache == NULL) + goto unlock; + + for (i = 0; i < resolver->badhash; i++) { + prev = NULL; + for (bad = resolver->badcache[i]; bad != NULL; bad = next) { + next = bad->next; + if (dns_name_issubdomain(&bad->name, name)) { + if (prev == NULL) + resolver->badcache[i] = bad->next; + else + prev->next = bad->next; + isc_mem_put(resolver->mctx, bad, sizeof(*bad) + + bad->name.length); + resolver->badcount--; + } else + prev = bad; + } + } + + unlock: + UNLOCK(&resolver->lock); + +} + static void resizehash(dns_resolver_t *resolver, isc_time_t *now, isc_boolean_t grow) { unsigned int newsize; diff --git a/lib/dns/view.c b/lib/dns/view.c index 59a5d2714e..45480c8f92 100644 --- a/lib/dns/view.c +++ b/lib/dns/view.c @@ -1556,15 +1556,22 @@ dns_view_flushcache2(dns_view_t *view, isc_boolean_t fixuponly) { isc_result_t dns_view_flushname(dns_view_t *view, dns_name_t *name) { - return (dns_view_flushnode(view, name, ISC_FALSE)); + return (dns_view_flushnode(view, name, ISC_FALSE, ISC_FALSE)); } isc_result_t -dns_view_flushnode(dns_view_t *view, dns_name_t *name, isc_boolean_t tree) { +dns_view_flushnode(dns_view_t *view, dns_name_t *name, + isc_boolean_t cachetree, isc_boolean_t all) +{ REQUIRE(DNS_VIEW_VALID(view)); - if (!tree) { + if (all) { + if (view->adb != NULL) + dns_adb_flushnames(view->adb, name); + if (view->resolver != NULL) + dns_resolver_flushbadnames(view->resolver, name); + } else if (!cachetree) { if (view->adb != NULL) dns_adb_flushname(view->adb, name); if (view->cache == NULL) @@ -1572,7 +1579,8 @@ dns_view_flushnode(dns_view_t *view, dns_name_t *name, isc_boolean_t tree) { if (view->resolver != NULL) dns_resolver_flushbadcache(view->resolver, name); } - return (dns_cache_flushnode(view->cache, name, tree)); + + return (dns_cache_flushnode(view->cache, name, cachetree || all)); } isc_result_t diff --git a/lib/dns/win32/libdns.def b/lib/dns/win32/libdns.def index 5409435c28..e901a61fa3 100644 --- a/lib/dns/win32/libdns.def +++ b/lib/dns/win32/libdns.def @@ -43,6 +43,8 @@ dns_adb_dump dns_adb_dumpfind dns_adb_findaddrinfo dns_adb_flush +dns_adb_flushmatch +dns_adb_flushname dns_adb_freeaddrinfo dns_adb_marklame dns_adb_setadbsize