diff --git a/CHANGES b/CHANGES index ad8eb6a68c..4dbf17fdc4 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,6 @@ +3684. [bug] The list of included files would grow on reload. + [RT 35090] + 3683. [cleanup] Add a more detailed "not found" message to rndc commands which specify a zone name. [RT #35059] diff --git a/bin/tests/system/zonechecks/ns1/named.conf b/bin/tests/system/zonechecks/ns1/named.conf index 7be4cee879..6caed2ff79 100644 --- a/bin/tests/system/zonechecks/ns1/named.conf +++ b/bin/tests/system/zonechecks/ns1/named.conf @@ -51,3 +51,7 @@ zone "master.example" { auto-dnssec maintain; }; +zone "reload.example" { + type master; + file "reload.db"; +}; diff --git a/bin/tests/system/zonechecks/setup.sh b/bin/tests/system/zonechecks/setup.sh index a72fbdbbb5..0c8a69829e 100644 --- a/bin/tests/system/zonechecks/setup.sh +++ b/bin/tests/system/zonechecks/setup.sh @@ -26,4 +26,6 @@ echo '$INCLUDE "master.db.signed"' >> master.db $KEYGEN -r ../random.data -3q master.example > /dev/null 2>&1 $KEYGEN -r ../random.data -3qfk master.example > /dev/null 2>&1 $SIGNER -SD -o master.example master.db > /dev/null 2>&1 - +echo '$INCLUDE "soa.db"' > reload.db +echo '@ 0 NS .' >> reload.db +echo '@ 0 SOA . . 1 0 0 0 0' > soa.db diff --git a/bin/tests/system/zonechecks/tests.sh b/bin/tests/system/zonechecks/tests.sh index 32bd4b3fe0..97305f72f5 100644 --- a/bin/tests/system/zonechecks/tests.sh +++ b/bin/tests/system/zonechecks/tests.sh @@ -204,6 +204,35 @@ checkfor "nodes: " rndc.out.slave checkfor "next refresh: " rndc.out.slave checkfor "expires: " rndc.out.slave checkfor "secure: yes" rndc.out.slave +for i in 0 1 2 3 4 5 6 7 8 9 +do + $RNDC -c ../common/rndc.conf -s 10.53.0.1 -p 9953 zonestatus reload.example > rndc.out.prereload 2>&1 + grep "zone not loaded" rndc.out.prereload > /dev/null || break + sleep 1 +done +checkfor "files: reload.db, soa.db$" rndc.out.prereload +echo "@ 0 SOA . . 2 0 0 0 0" > ns1/soa.db +$RNDC -c ../common/rndc.conf -s 10.53.0.1 -p 9953 reload reload.example +for i in 0 1 2 3 4 5 6 7 8 9 +do + $DIG reload.example SOA @10.53.0.1 -p 5300 > dig.out + grep " 2 0 0 0 0" dig.out >/dev/null && break + sleep 1 +done +$RNDC -c ../common/rndc.conf -s 10.53.0.1 -p 9953 zonestatus reload.example > rndc.out.postreload 2>&1 +checkfor "files: reload.db, soa.db$" rndc.out.postreload +sleep 1 +echo "@ 0 SOA . . 3 0 0 0 0" > ns1/reload.db +echo "@ 0 NS ." >> ns1/reload.db +$RNDC -c ../common/rndc.conf -s 10.53.0.1 -p 9953 reload reload.example +for i in 0 1 2 3 4 5 6 7 8 9 +do + $DIG reload.example SOA @10.53.0.1 -p 5300 > dig.out + grep " 3 0 0 0 0" dig.out >/dev/null && break + sleep 1 +done +$RNDC -c ../common/rndc.conf -s 10.53.0.1 -p 9953 zonestatus reload.example > rndc.out.removeinclude 2>&1 +checkfor "files: reload.db$" rndc.out.removeinclude if [ $ret != 0 ]; then echo "I:failed"; fi status=`expr $status + $ret` diff --git a/lib/dns/zone.c b/lib/dns/zone.c index 388f0cf48d..f24aa33bad 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -218,6 +218,7 @@ struct dns_zone { dns_name_t origin; char *masterfile; ISC_LIST(dns_include_t) includes; /* Include files */ + ISC_LIST(dns_include_t) newincludes; /* Loading */ unsigned int nincludes; dns_masterformat_t masterformat; char *journal; @@ -869,6 +870,7 @@ dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx) { zone->strviewname = NULL; zone->masterfile = NULL; ISC_LIST_INIT(zone->includes); + ISC_LIST_INIT(zone->newincludes); zone->nincludes = 0; zone->masterformat = dns_masterformat_none; zone->keydirectory = NULL; @@ -1065,6 +1067,13 @@ zone_free(dns_zone_t *zone) { isc_mem_free(zone->mctx, include->name); isc_mem_put(zone->mctx, include, sizeof *include); } + for (include = ISC_LIST_HEAD(zone->newincludes); + include != NULL; + include = ISC_LIST_HEAD(zone->newincludes)) { + ISC_LIST_UNLINK(zone->newincludes, include, link); + isc_mem_free(zone->mctx, include->name); + isc_mem_put(zone->mctx, include, sizeof *include); + } if (zone->masterfile != NULL) isc_mem_free(zone->mctx, zone->masterfile); zone->masterfile = NULL; @@ -2052,6 +2061,15 @@ zone_registerinclude(const char *filename, void *arg) { if (filename == NULL) return; + /* + * Suppress duplicates. + */ + for (inc = ISC_LIST_HEAD(zone->newincludes); + inc != NULL; + inc = ISC_LIST_NEXT(inc, link)) + if (strcmp(filename, inc->name) == 0) + return; + inc = isc_mem_get(zone->mctx, sizeof(dns_include_t)); if (inc == NULL) return; @@ -2066,8 +2084,7 @@ zone_registerinclude(const char *filename, void *arg) { if (result != ISC_R_SUCCESS) isc_time_settoepoch(&inc->filetime); - ISC_LIST_APPEND(zone->includes, inc, link); - zone->nincludes++; + ISC_LIST_APPEND(zone->newincludes, inc, link); } static void @@ -4048,6 +4065,7 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime, isc_boolean_t hasinclude = DNS_ZONE_FLAG(zone, DNS_ZONEFLG_HASINCLUDE); isc_boolean_t nomaster = ISC_FALSE; unsigned int options; + dns_include_t *inc; INSIST(LOCKED_ZONE(zone)); if (inline_raw(zone)) @@ -4472,6 +4490,29 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime, zone_settimer(zone, &now); } + /* + * Clear old include list. + */ + for (inc = ISC_LIST_HEAD(zone->includes); + inc != NULL; + inc = ISC_LIST_HEAD(zone->includes)) { + ISC_LIST_UNLINK(zone->includes, inc, link); + isc_mem_free(zone->mctx, inc->name); + isc_mem_put(zone->mctx, inc, sizeof(*inc)); + } + zone->nincludes = 0; + + /* + * Transfer new include list. + */ + for (inc = ISC_LIST_HEAD(zone->newincludes); + inc != NULL; + inc = ISC_LIST_HEAD(zone->newincludes)) { + ISC_LIST_UNLINK(zone->newincludes, inc, link); + ISC_LIST_APPEND(zone->includes, inc, link); + zone->nincludes++; + } + if (! dns_db_ispersistent(db)) dns_zone_log(zone, ISC_LOG_INFO, "loaded serial %u%s", serial, dns_db_issecure(db) ? " (DNSSEC signed)" : ""); @@ -4481,6 +4522,13 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime, return (result); cleanup: + for (inc = ISC_LIST_HEAD(zone->newincludes); + inc != NULL; + inc = ISC_LIST_HEAD(zone->newincludes)) { + ISC_LIST_UNLINK(zone->newincludes, inc, link); + isc_mem_free(zone->mctx, inc->name); + isc_mem_put(zone->mctx, inc, sizeof(*inc)); + } if (zone->type == dns_zone_slave || zone->type == dns_zone_stub || zone->type == dns_zone_key ||