From 90a354ab367f420147a498e026305f59bf58a72b Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Fri, 4 Nov 2011 05:51:02 +0000 Subject: [PATCH] 3204. [bug] When a master server that has been marked as unreachable but sends a NOTIFY, mark it reachable again. [RT #25960] --- CHANGES | 4 ++ lib/dns/include/dns/zone.h | 28 +++++++++++++- lib/dns/tests/zonemgr_test.c | 71 ++++++++++++++++++++++++++++++++++-- lib/dns/zone.c | 58 ++++++++++++++++++++++++----- 4 files changed, 148 insertions(+), 13 deletions(-) diff --git a/CHANGES b/CHANGES index f1a021a692..9eaf218c48 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,7 @@ +3204. [bug] When a master server that has been marked as + unreachable but sends a NOTIFY, mark it reachable + again. [RT #25960] + 3203. [bug] Increase log level to 'info' for validation failures from expired or not-yet-valid RRSIGs. [RT #21796] diff --git a/lib/dns/include/dns/zone.h b/lib/dns/include/dns/zone.h index 55a279a4b4..bcf93a0408 100644 --- a/lib/dns/include/dns/zone.h +++ b/lib/dns/include/dns/zone.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: zone.h,v 1.196 2011/10/28 06:20:06 each Exp $ */ +/* $Id: zone.h,v 1.197 2011/11/04 05:51:01 each Exp $ */ #ifndef DNS_ZONE_H #define DNS_ZONE_H 1 @@ -1607,6 +1607,32 @@ dns_zonemgr_unreachableadd(dns_zonemgr_t *zmgr, isc_sockaddr_t *remote, *\li 'local' to be a valid sockaddr. */ +isc_boolean_t +dns_zonemgr_unreachable(dns_zonemgr_t *zmgr, isc_sockaddr_t *remote, + isc_sockaddr_t *local, isc_time_t *now); +/*%< + * Returns ISC_TRUE if the given local/remote address pair + * is found in the zone maanger's unreachable cache. + * + * Requires: + *\li 'zmgr' to be a valid zone manager. + *\li 'remote' to be a valid sockaddr. + *\li 'local' to be a valid sockaddr. + *\li 'now' != NULL + */ + +void +dns_zonemgr_unreachabledel(dns_zonemgr_t *zmgr, isc_sockaddr_t *remote, + isc_sockaddr_t *local); +/*%< + * Remove the pair of addresses from the unreachable cache. + * + * Requires: + *\li 'zmgr' to be a valid zone manager. + *\li 'remote' to be a valid sockaddr. + *\li 'local' to be a valid sockaddr. + */ + void dns_zone_forcereload(dns_zone_t *zone); /*%< diff --git a/lib/dns/tests/zonemgr_test.c b/lib/dns/tests/zonemgr_test.c index f9ee19e070..77a2b91bb1 100644 --- a/lib/dns/tests/zonemgr_test.c +++ b/lib/dns/tests/zonemgr_test.c @@ -14,7 +14,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: zonemgr_test.c,v 1.3 2011/09/02 21:15:37 each Exp $ */ +/* $Id: zonemgr_test.c,v 1.4 2011/11/04 05:51:02 each Exp $ */ /*! \file */ @@ -110,12 +110,79 @@ ATF_TC_BODY(zonemgr_managezone, tc) { dns_test_end(); } +ATF_TC(zonemgr_unreachable); +ATF_TC_HEAD(zonemgr_unreachable, tc) { + atf_tc_set_md_var(tc, "descr", "manage and release a zone"); +} +ATF_TC_BODY(zonemgr_unreachable, tc) { + dns_zonemgr_t *zonemgr = NULL; + dns_zone_t *zone = NULL; + isc_sockaddr_t addr1, addr2; + struct in_addr in; + isc_result_t result; + isc_time_t now; + + UNUSED(tc); + + TIME_NOW(&now); + + result = dns_test_begin(NULL, ISC_TRUE); + + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + + result = dns_zonemgr_create(mctx, taskmgr, timermgr, socketmgr, + &zonemgr); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + + result = dns_test_makezone("foo", &zone, NULL, ISC_FALSE); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + + result = dns_zonemgr_setsize(zonemgr, 1); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + + result = dns_zonemgr_managezone(zonemgr, zone); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + + in.s_addr = inet_addr("10.53.0.1"); + isc_sockaddr_fromin(&addr1, &in, 2112); + in.s_addr = inet_addr("10.53.0.2"); + isc_sockaddr_fromin(&addr2, &in, 5150); + ATF_CHECK(! dns_zonemgr_unreachable(zonemgr, &addr1, &addr2, &now)); + dns_zonemgr_unreachableadd(zonemgr, &addr1, &addr2, &now); + ATF_CHECK(dns_zonemgr_unreachable(zonemgr, &addr1, &addr2, &now)); + + in.s_addr = inet_addr("10.53.0.3"); + isc_sockaddr_fromin(&addr2, &in, 5150); + ATF_CHECK(! dns_zonemgr_unreachable(zonemgr, &addr1, &addr2, &now)); + dns_zonemgr_unreachableadd(zonemgr, &addr1, &addr2, &now); + ATF_CHECK(dns_zonemgr_unreachable(zonemgr, &addr1, &addr2, &now)); + + dns_zonemgr_unreachabledel(zonemgr, &addr1, &addr2); + ATF_CHECK(! dns_zonemgr_unreachable(zonemgr, &addr1, &addr2, &now)); + + in.s_addr = inet_addr("10.53.0.2"); + isc_sockaddr_fromin(&addr2, &in, 5150); + ATF_CHECK(dns_zonemgr_unreachable(zonemgr, &addr1, &addr2, &now)); + dns_zonemgr_unreachabledel(zonemgr, &addr1, &addr2); + ATF_CHECK(! dns_zonemgr_unreachable(zonemgr, &addr1, &addr2, &now)); + + dns_zonemgr_releasezone(zonemgr, zone); + dns_zone_detach(&zone); + dns_zonemgr_shutdown(zonemgr); + dns_zonemgr_detach(&zonemgr); + ATF_REQUIRE_EQ(zonemgr, NULL); + + dns_test_end(); +} + + /* * Main */ ATF_TP_ADD_TCS(tp) { ATF_TP_ADD_TC(tp, zonemgr_create); ATF_TP_ADD_TC(tp, zonemgr_managezone); + ATF_TP_ADD_TC(tp, zonemgr_unreachable); return (atf_no_error()); } @@ -137,6 +204,4 @@ ATF_TP_ADD_TCS(tp) { * - dns_zonemgr_dbdestroyed * - dns_zonemgr_setserialqueryrate * - dns_zonemgr_getserialqueryrate - * - dns_zonemgr_unreachable - * - dns_zonemgr_unreachableadd */ diff --git a/lib/dns/zone.c b/lib/dns/zone.c index 4433768304..9f06a7cd6f 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: zone.c,v 1.646 2011/11/03 03:26:19 each Exp $ */ +/* $Id: zone.c,v 1.647 2011/11/04 05:51:01 each Exp $ */ /*! \file */ @@ -701,10 +701,6 @@ static void zone_saveunique(dns_zone_t *zone, const char *path, static void zone_maintenance(dns_zone_t *zone); static void zone_notify(dns_zone_t *zone, isc_time_t *now); static void dump_done(void *arg, isc_result_t result); -static isc_boolean_t dns_zonemgr_unreachable(dns_zonemgr_t *zmgr, - isc_sockaddr_t *remote, - isc_sockaddr_t *local, - isc_time_t *now); static isc_result_t zone_signwithkey(dns_zone_t *zone, dns_secalg_t algorithm, isc_uint16_t keyid, isc_boolean_t delete); static isc_result_t delete_nsec(dns_db_t *db, dns_dbversion_t *ver, @@ -9909,7 +9905,8 @@ refresh_callback(isc_task_t *task, isc_event_t *event) { if (!dns_zonemgr_unreachable(zone->zmgr, &zone->masteraddr, &zone->sourceaddr, - &now)) { + &now)) + { LOCK_ZONE(zone); DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_SOABEFOREAXFR); @@ -10105,7 +10102,8 @@ refresh_callback(isc_task_t *task, isc_event_t *event) { DNS_ZONE_FLAG(zone, DNS_ZONEFLG_FORCEXFER) || isc_serial_gt(serial, oldserial)) { if (dns_zonemgr_unreachable(zone->zmgr, &zone->masteraddr, - &zone->sourceaddr, &now)) { + &zone->sourceaddr, &now)) + { dns_zone_log(zone, ISC_LOG_INFO, "refresh: skipping %s as master %s " "(source %s) is unreachable (cached)", @@ -11235,6 +11233,7 @@ dns_zone_notifyreceive(dns_zone_t *zone, isc_sockaddr_t *from, char fromtext[ISC_SOCKADDR_FORMATSIZE]; int match = 0; isc_netaddr_t netaddr; + isc_sockaddr_t local, remote; REQUIRE(DNS_ZONE_VALID(zone)); @@ -11393,7 +11392,10 @@ dns_zone_notifyreceive(dns_zone_t *zone, isc_sockaddr_t *from, return (ISC_R_SUCCESS); } zone->notifyfrom = *from; + local = zone->masteraddr; + remote = zone->sourceaddr; UNLOCK_ZONE(zone); + dns_zonemgr_unreachabledel(zone->zmgr, &local, &remote); dns_zone_refresh(zone); return (ISC_R_SUCCESS); } @@ -12930,7 +12932,8 @@ got_transfer_quota(isc_task_t *task, isc_event_t *event) { isc_sockaddr_format(&zone->masteraddr, master, sizeof(master)); if (dns_zonemgr_unreachable(zone->zmgr, &zone->masteraddr, - &zone->sourceaddr, &now)) { + &zone->sourceaddr, &now)) + { isc_sockaddr_format(&zone->sourceaddr, source, sizeof(source)); dns_zone_log(zone, ISC_LOG_INFO, "got_transfer_quota: skipping zone transfer as " @@ -14010,7 +14013,7 @@ dns_zonemgr_getserialqueryrate(dns_zonemgr_t *zmgr) { return (zmgr->serialqueryrate); } -static isc_boolean_t +isc_boolean_t dns_zonemgr_unreachable(dns_zonemgr_t *zmgr, isc_sockaddr_t *remote, isc_sockaddr_t *local, isc_time_t *now) { @@ -14039,6 +14042,43 @@ dns_zonemgr_unreachable(dns_zonemgr_t *zmgr, isc_sockaddr_t *remote, return (ISC_TF(i < UNREACH_CHACHE_SIZE)); } +void +dns_zonemgr_unreachabledel(dns_zonemgr_t *zmgr, isc_sockaddr_t *remote, + isc_sockaddr_t *local) +{ + unsigned int i; + isc_rwlocktype_t locktype; + isc_result_t result; + + char master[ISC_SOCKADDR_FORMATSIZE]; + char source[ISC_SOCKADDR_FORMATSIZE]; + + isc_sockaddr_format(remote, master, sizeof(master)); + isc_sockaddr_format(local, source, sizeof(source)); + + REQUIRE(DNS_ZONEMGR_VALID(zmgr)); + + locktype = isc_rwlocktype_read; + RWLOCK(&zmgr->rwlock, locktype); + for (i = 0; i < UNREACH_CHACHE_SIZE; i++) { + if (isc_sockaddr_equal(&zmgr->unreachable[i].remote, remote) && + isc_sockaddr_equal(&zmgr->unreachable[i].local, local)) { + result = isc_rwlock_tryupgrade(&zmgr->rwlock); + if (result == ISC_R_SUCCESS) { + locktype = isc_rwlocktype_write; + zmgr->unreachable[i].expire = 0; + isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, + DNS_LOGMODULE_ZONE, ISC_LOG_INFO, + "master %s (source %s) deleted " + "from unreachable cache", + master, source); + } + break; + } + } + RWUNLOCK(&zmgr->rwlock, locktype); +} + void dns_zonemgr_unreachableadd(dns_zonemgr_t *zmgr, isc_sockaddr_t *remote, isc_sockaddr_t *local, isc_time_t *now)