From 6539f73e3a3b484c19c34ff3543be370bccd64c1 Mon Sep 17 00:00:00 2001 From: Aram Sargsyan Date: Thu, 17 Mar 2022 14:43:18 +0000 Subject: [PATCH] Introduce the concept of broken catalog zones The DNS catalog zones draft version 5 document describes various situations when a catalog zones must be considered as "broken" and not be processed. Implement those checks in catz.c and add corresponding system tests. (cherry picked from commit a8228d5f190d556ba6a3e25cc523ba936fbfe957) --- bin/tests/system/catz/clean.sh | 1 + .../system/catz/ns1/catalog-bad1.example.db | 13 +++ .../system/catz/ns1/catalog-bad2.example.db | 14 +++ .../system/catz/ns1/catalog-bad3.example.db | 15 +++ bin/tests/system/catz/ns1/named.conf.in | 30 +++++ bin/tests/system/catz/ns2/named1.conf.in | 27 +++++ bin/tests/system/catz/ns2/named2.conf.in | 18 +++ bin/tests/system/catz/tests.sh | 87 ++++++++++++++- lib/dns/catz.c | 105 +++++++++++++++--- 9 files changed, 291 insertions(+), 19 deletions(-) create mode 100644 bin/tests/system/catz/ns1/catalog-bad1.example.db create mode 100644 bin/tests/system/catz/ns1/catalog-bad2.example.db create mode 100644 bin/tests/system/catz/ns1/catalog-bad3.example.db diff --git a/bin/tests/system/catz/clean.sh b/bin/tests/system/catz/clean.sh index 783ed4e763..e293e7dc0c 100644 --- a/bin/tests/system/catz/clean.sh +++ b/bin/tests/system/catz/clean.sh @@ -19,6 +19,7 @@ rm -f ns*/named.run rm -f ns*/named.run.prev rm -f ns1/*dom*example.db rm -f ns2/__catz__*db +rm -f ns2/catalog-bad*.db rm -f ns2/named.conf.tmp rm -f ns3/dom2.example.db ns3/dom13.example.db ns3/dom14.example.db ns3/dom17.example.db ns3/dom18.example.db rm -f nsupdate.out.* diff --git a/bin/tests/system/catz/ns1/catalog-bad1.example.db b/bin/tests/system/catz/ns1/catalog-bad1.example.db new file mode 100644 index 0000000000..b8402de301 --- /dev/null +++ b/bin/tests/system/catz/ns1/catalog-bad1.example.db @@ -0,0 +1,13 @@ +; Copyright (C) Internet Systems Consortium, Inc. ("ISC") +; +; SPDX-License-Identifier: MPL-2.0 +; +; This Source Code Form is subject to the terms of the Mozilla Public +; License, v. 2.0. If a copy of the MPL was not distributed with this +; file, you can obtain one at https://mozilla.org/MPL/2.0/. +; +; See the COPYRIGHT file distributed with this work for additional +; information regarding copyright ownership. + +@ 3600 SOA . . 1 86400 3600 86400 3600 +@ 3600 IN NS invalid. diff --git a/bin/tests/system/catz/ns1/catalog-bad2.example.db b/bin/tests/system/catz/ns1/catalog-bad2.example.db new file mode 100644 index 0000000000..06b9121f13 --- /dev/null +++ b/bin/tests/system/catz/ns1/catalog-bad2.example.db @@ -0,0 +1,14 @@ +; Copyright (C) Internet Systems Consortium, Inc. ("ISC") +; +; SPDX-License-Identifier: MPL-2.0 +; +; This Source Code Form is subject to the terms of the Mozilla Public +; License, v. 2.0. If a copy of the MPL was not distributed with this +; file, you can obtain one at https://mozilla.org/MPL/2.0/. +; +; See the COPYRIGHT file distributed with this work for additional +; information regarding copyright ownership. + +@ 3600 SOA . . 1 86400 3600 86400 3600 +@ 3600 IN NS invalid. +version IN TXT "99" diff --git a/bin/tests/system/catz/ns1/catalog-bad3.example.db b/bin/tests/system/catz/ns1/catalog-bad3.example.db new file mode 100644 index 0000000000..0116697de3 --- /dev/null +++ b/bin/tests/system/catz/ns1/catalog-bad3.example.db @@ -0,0 +1,15 @@ +; Copyright (C) Internet Systems Consortium, Inc. ("ISC") +; +; SPDX-License-Identifier: MPL-2.0 +; +; This Source Code Form is subject to the terms of the Mozilla Public +; License, v. 2.0. If a copy of the MPL was not distributed with this +; file, you can obtain one at https://mozilla.org/MPL/2.0/. +; +; See the COPYRIGHT file distributed with this work for additional +; information regarding copyright ownership. + +@ 3600 SOA . . 1 86400 3600 86400 3600 +@ 3600 IN NS invalid. +version IN TXT "1" +version IN TXT "2" diff --git a/bin/tests/system/catz/ns1/named.conf.in b/bin/tests/system/catz/ns1/named.conf.in index 5a46d3984f..5cf799f1c6 100644 --- a/bin/tests/system/catz/ns1/named.conf.in +++ b/bin/tests/system/catz/ns1/named.conf.in @@ -61,6 +61,36 @@ zone "catalog4.example" { /* catalog5 is missing on purpose */ +# No "version" property +zone "catalog-bad1.example" { + type primary; + file "catalog-bad1.example.db"; + allow-transfer { any; }; + allow-update { any; }; + also-notify { 10.53.0.2; }; + notify explicit; +}; + +# Unsupported "version" property +zone "catalog-bad2.example" { + type primary; + file "catalog-bad2.example.db"; + allow-transfer { any; }; + allow-update { any; }; + also-notify { 10.53.0.2; }; + notify explicit; +}; + +# Two RRs in TXT RRset for the "version" property +zone "catalog-bad3.example" { + type primary; + file "catalog-bad3.example.db"; + allow-transfer { any; }; + allow-update { any; }; + also-notify { 10.53.0.2; }; + notify explicit; +}; + key tsig_key. { secret "LSAnCU+Z"; algorithm hmac-md5; diff --git a/bin/tests/system/catz/ns2/named1.conf.in b/bin/tests/system/catz/ns2/named1.conf.in index ed7f87943b..8ff6f687a0 100644 --- a/bin/tests/system/catz/ns2/named1.conf.in +++ b/bin/tests/system/catz/ns2/named1.conf.in @@ -43,6 +43,15 @@ options { #T1 default-masters { 10.53.0.1; }; #T2 zone "catalog5.example" #T2 default-primaries { 10.53.0.1; }; + zone "catalog-bad1.example" + default-masters { 10.53.0.1; } + in-memory yes; + zone "catalog-bad2.example" + default-masters { 10.53.0.1; } + in-memory yes; + zone "catalog-bad3.example" + default-masters { 10.53.0.1; } + in-memory yes; }; }; @@ -83,6 +92,24 @@ zone "catalog4.example" { primaries { 10.53.0.1; }; }; +zone "catalog-bad1.example" { + type secondary; + file "catalog-bad1.example.db"; + primaries { 10.53.0.1; }; +}; + +zone "catalog-bad2.example" { + type secondary; + file "catalog-bad2.example.db"; + primaries { 10.53.0.1; }; +}; + +zone "catalog-bad3.example" { + type secondary; + file "catalog-bad3.example.db"; + primaries { 10.53.0.1; }; +}; + key tsig_key. { secret "LSAnCU+Z"; algorithm hmac-md5; diff --git a/bin/tests/system/catz/ns2/named2.conf.in b/bin/tests/system/catz/ns2/named2.conf.in index 12884c6797..787d62b510 100644 --- a/bin/tests/system/catz/ns2/named2.conf.in +++ b/bin/tests/system/catz/ns2/named2.conf.in @@ -61,6 +61,24 @@ zone "catalog4.example" { primaries { 10.53.0.1; }; }; +zone "catalog-bad1.example" { + type secondary; + file "catalog-bad1.example.db"; + primaries { 10.53.0.1; }; +}; + +zone "catalog-bad2.example" { + type secondary; + file "catalog-bad2.example.db"; + primaries { 10.53.0.1; }; +}; + +zone "catalog-bad3.example" { + type secondary; + file "catalog-bad3.example.db"; + primaries { 10.53.0.1; }; +}; + key tsig_key. { secret "LSAnCU+Z"; algorithm hmac-md5; diff --git a/bin/tests/system/catz/tests.sh b/bin/tests/system/catz/tests.sh index 6785dd84e9..807fb14bc0 100644 --- a/bin/tests/system/catz/tests.sh +++ b/bin/tests/system/catz/tests.sh @@ -80,6 +80,36 @@ wait_for_no_zonefile() ( status=0 n=0 + +########################################################################## +n=$((n+1)) +echo_i "checking that catalog-bad1.example (with no version) has failed to load ($n)" +ret=0 +wait_for_message ns2/named.run "catz: zone 'catalog-bad1.example' has no 'version' record" && +wait_for_message ns2/named.run "catz: new catalog zone 'catalog-bad1.example' is broken and will not be processed" || ret=1 +if [ $ret -ne 0 ]; then echo_i "failed"; fi +status=$((status+ret)) + +n=$((n+1)) +echo_i "checking that catalog-bad2.example (with unsupported version) has failed to load ($n)" +ret=0 +wait_for_message ns2/named.run "catz: zone 'catalog-bad2.example' unsupported version '99'" && +wait_for_message ns2/named.run "catz: new catalog zone 'catalog-bad2.example' is broken and will not be processed" || ret=1 +if [ $ret -ne 0 ]; then echo_i "failed"; fi +status=$((status+ret)) + +n=$((n+1)) +echo_i "checking that catalog-bad3.example (with two supported version records) has failed to load ($n)" +ret=0 +wait_for_message ns2/named.run "catz: 'version' property TXT RRset contains more than one record, which is invalid" && +wait_for_message ns2/named.run "catz: invalid record in catalog zone - version.catalog-bad3.example IN TXT (failure) - ignoring" && +wait_for_message ns2/named.run "catz: zone 'catalog-bad3.example' version is not set" && +wait_for_message ns2/named.run "catz: new catalog zone 'catalog-bad3.example' is broken and will not be processed" || ret=1 +if [ $ret -ne 0 ]; then echo_i "failed"; fi +status=$((status+ret)) + +nextpart ns2/named.run >/dev/null + ########################################################################## echo_i "Testing adding/removing of domain in catalog zone" n=$((n+1)) @@ -145,6 +175,8 @@ wait_for_zonefile "ns2/zonedir/__catz___default_catalog1.example_dom1.example.db if [ $ret -ne 0 ]; then echo_i "failed"; fi status=$((status+ret)) +nextpart ns2/named.run >/dev/null + n=$((n+1)) echo_i "update dom1.example. ($n)" ret=0 @@ -176,6 +208,8 @@ test -f ns2/zonedir/__catz___default_catalog1.example_dom1.example.db.jnl || ret if [ $ret -ne 0 ]; then echo_i "failed"; fi status=$((status+ret)) +nextpart ns2/named.run >/dev/null + n=$((n+1)) echo_i "update catalog zone serial ($n)" ret=0 @@ -202,6 +236,8 @@ retry_quiet 10 wait_for_soa_equal_20 || ret=1 if [ $ret -ne 0 ]; then echo_i "failed"; fi status=$((status+ret)) +nextpart ns2/named.run >/dev/null + n=$((n+1)) echo_i "update dom1.example. again ($n)" ret=0 @@ -259,6 +295,8 @@ wait_for_no_zonefile "ns2/zonedir/__catz___default_catalog1.example_dom1.example if [ $ret -ne 0 ]; then echo_i "failed"; fi status=$((status+ret)) +nextpart ns2/named.run >/dev/null + ########################################################################## echo_i "Testing various simple operations on domains, including using multiple catalog zones and garbage in zone" n=$((n+1)) @@ -296,6 +334,7 @@ ret=0 $NSUPDATE -d <> nsupdate.out.test$n 2>&1 || ret=1 server 10.53.0.1 ${PORT} update add 636722929740e507aaf27c502812fc395d30fb17.zones.catalog1.example. 3600 IN PTR dom2.example. + update add coo.636722929740e507aaf27c502812fc395d30fb17.zones.catalog1.example. 3600 IN TXT "catalog2.example." update add b901f492f3ebf6c1e5b597e51766f02f0479eb03.zones.catalog1.example. 3600 IN PTR dom3.example. update add e721433b6160b450260d4f54b3ec8bab30cb3b83.zones.catalog1.example. 3600 IN NS foo.bar. update add trash.catalog1.example. 3600 IN A 1.2.3.4 @@ -322,10 +361,11 @@ END if [ $ret -ne 0 ]; then echo_i "failed"; fi status=$((status+ret)) - n=$((n+1)) echo_i "waiting for secondary to sync up ($n)" ret=0 +wait_for_message ns2/named.run "catz: adding zone 'dom2.example' from catalog 'catalog1.example'" && +wait_for_message ns2/named.run "catz: adding zone 'dom3.example' from catalog 'catalog1.example'" && wait_for_message ns2/named.run "catz: adding zone 'dom4.example' from catalog 'catalog2.example'" && wait_for_message ns2/named.run "transfer of 'dom4.example/IN' from 10.53.0.1#${EXTRAPORT1}: Transfer status: success" || ret=1 if [ $ret -ne 0 ]; then echo_i "failed"; fi @@ -338,7 +378,6 @@ wait_for_soa @10.53.0.2 dom4.example. dig.out.test$n || ret=1 if [ $ret -ne 0 ]; then echo_i "failed"; fi status=$((status+ret)) - n=$((n+1)) echo_i "checking that dom3.example. is not served by primary ($n)" ret=0 @@ -365,8 +404,6 @@ status=$((status+ret)) n=$((n+1)) echo_i "waiting for secondary to sync up ($n)" ret=0 -wait_for_message ns2/named.run "catz: adding zone 'dom2.example' from catalog 'catalog1.example'" && -wait_for_message ns2/named.run "catz: adding zone 'dom3.example' from catalog 'catalog1.example'" && wait_for_message ns2/named.run "transfer of 'dom2.example/IN' from 10.53.0.1#${PORT}: Transfer status: success" && wait_for_message ns2/named.run "transfer of 'dom3.example/IN' from 10.53.0.1#${PORT}: Transfer status: success" || ret=1 if [ $ret -ne 0 ]; then echo_i "failed"; fi @@ -381,6 +418,43 @@ status=$((status+ret)) nextpart ns2/named.run >/dev/null +# The member zone's PTR RRset must have only one record in it. +# Check that adding a second record to the RRset is caught and such a +# catalog zone is not processed. +n=$((n+1)) +echo_i "adding domain dom4-reused-label.example. to catalog2 zone, reusing a label ($n)" +ret=0 +$NSUPDATE -d <> nsupdate.out.test$n 2>&1 || ret=1 + server 10.53.0.3 ${PORT} + update add de26b88d855397a03f77ff1162fd055d8b419584.zones.catalog2.example. 3600 IN PTR dom4-reused-label.example. + send +END +if [ $ret -ne 0 ]; then echo_i "failed"; fi +status=$((status+ret)) + +n=$((n+1)) +echo_i "waiting for secondary to sync up, and checking that the reused label has been caught ($n)" +ret=0 +wait_for_message ns2/named.run "de26b88d855397a03f77ff1162fd055d8b419584.zones.catalog2.example IN PTR (failure)" && +wait_for_message ns2/named.run "catz: new catalog zone 'catalog2.example' is broken and will not be processed" || ret=1 +if [ $ret -ne 0 ]; then echo_i "failed"; fi +status=$((status+ret)) + +nextpart ns2/named.run >/dev/null + +n=$((n+1)) +echo_i "deleting domain dom4-reused-label.example. from catalog2 zone ($n)" +ret=0 +$NSUPDATE -d <> nsupdate.out.test$n 2>&1 || ret=1 + server 10.53.0.3 ${PORT} + update delete de26b88d855397a03f77ff1162fd055d8b419584.zones.catalog2.example. 3600 IN PTR dom4-reused-label.example. + send +END +if [ $ret -ne 0 ]; then echo_i "failed"; fi +status=$((status+ret)) + +nextpart ns2/named.run >/dev/null + n=$((n+1)) echo_i "adding domain dom2.example. to catalog2 zone to test change of ownership ($n)" ret=0 @@ -615,6 +689,7 @@ ret=0 $NSUPDATE -d <> nsupdate.out.test$n 2>&1 || ret=1 server 10.53.0.1 ${PORT} update delete 636722929740e507aaf27c502812fc395d30fb17.zones.catalog1.example. 3600 IN PTR dom2.example. + update delete coo.636722929740e507aaf27c502812fc395d30fb17.zones.catalog1.example. 3600 IN TXT "catalog2.example." update delete b901f492f3ebf6c1e5b597e51766f02f0479eb03.zones.catalog1.example. 3600 IN PTR dom3.example. update delete e721433b6160b450260d4f54b3ec8bab30cb3b83.zones.catalog1.example. 3600 IN NS foo.bar. update delete trash.catalog1.example. 3600 IN A 1.2.3.4 @@ -2083,7 +2158,7 @@ status=$((status+ret)) n=$((n+1)) echo_i "waiting for secondary to sync up ($n)" ret=0 -wait_for_message ns2/named.run "catz: unknown record in catalog zone - primaries.dom17.zones.catalog1.example IN A(failure) - ignoring" && +wait_for_message ns2/named.run "catz: invalid record in catalog zone - primaries.dom17.zones.catalog1.example IN A (failure) - ignoring" && wait_for_message ns2/named.run "catz: adding zone 'dom17.example' from catalog 'catalog1.example'" && wait_for_message ns2/named.run "catz: adding zone 'dom18.example' from catalog 'catalog1.example'" && wait_for_message ns2/named.run "transfer of 'dom17.example/IN' from 10.53.0.1#${PORT}: Transfer status: success" && @@ -2174,7 +2249,7 @@ status=$((status+ret)) n=$((n+1)) echo_i "waiting for secondary to sync up ($n)" ret=0 -wait_for_message ns2/named.run "catz: unknown record in catalog zone - primaries.ext.dom18.zones.catalog2.example IN A(failure) - ignoring" && +wait_for_message ns2/named.run "catz: invalid record in catalog zone - primaries.ext.dom18.zones.catalog2.example IN A (failure) - ignoring" && wait_for_message ns2/named.run "catz: adding zone 'dom17.example' from catalog 'catalog2.example'" && wait_for_message ns2/named.run "catz: adding zone 'dom18.example' from catalog 'catalog2.example'" && wait_for_message ns2/named.run "transfer of 'dom17.example/IN' from 10.53.0.3#${PORT}: Transfer status: success" && diff --git a/lib/dns/catz.c b/lib/dns/catz.c index b8b28efb76..3b55a552ce 100644 --- a/lib/dns/catz.c +++ b/lib/dns/catz.c @@ -94,6 +94,7 @@ struct dns_catz_zone { bool active; bool db_registered; + bool broken; isc_refcount_t refs; }; @@ -1077,6 +1078,15 @@ catz_process_coo(dns_catz_zone_t *zone, dns_label_t *mhash, return (ISC_R_FAILURE); } + if (dns_rdataset_count(value) != 1) { + isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, + DNS_LOGMODULE_MASTER, ISC_LOG_WARNING, + "catz: 'coo' property PTR RRset contains " + "more than one record, which is invalid"); + zone->broken = true; + return (ISC_R_FAILURE); + } + result = dns_rdataset_first(value); if (result != ISC_R_SUCCESS) { return (result); @@ -1135,24 +1145,32 @@ catz_process_zones_entry(dns_catz_zone_t *zone, dns_rdataset_t *value, dns_rdata_ptr_t ptr; dns_catz_entry_t *entry = NULL; - /* - * We only take -first- value, as mhash must be - * different. - */ - if (value->type != dns_rdatatype_ptr) { + if (value->rdclass != dns_rdataclass_in || + value->type != dns_rdatatype_ptr) { + return (ISC_R_FAILURE); + } + + if (dns_rdataset_count(value) != 1) { + isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, + DNS_LOGMODULE_MASTER, ISC_LOG_WARNING, + "catz: member zone PTR RRset contains " + "more than one record, which is invalid"); + zone->broken = true; return (ISC_R_FAILURE); } result = dns_rdataset_first(value); if (result != ISC_R_SUCCESS) { - return (ISC_R_FAILURE); + return (result); } dns_rdata_init(&rdata); dns_rdataset_current(value, &rdata); result = dns_rdata_tostruct(&rdata, &ptr, NULL); - RUNTIME_CHECK(result == ISC_R_SUCCESS); + if (result != ISC_R_SUCCESS) { + return (result); + } result = isc_ht_find(zone->entries, mhash->base, mhash->length, (void **)&entry); @@ -1198,6 +1216,15 @@ catz_process_version(dns_catz_zone_t *zone, dns_rdataset_t *value) { return (ISC_R_FAILURE); } + if (dns_rdataset_count(value) != 1) { + isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, + DNS_LOGMODULE_MASTER, ISC_LOG_WARNING, + "catz: 'version' property TXT RRset contains " + "more than one record, which is invalid"); + zone->broken = true; + return (ISC_R_FAILURE); + } + result = dns_rdataset_first(value); if (result != ISC_R_SUCCESS) { return (result); @@ -1207,7 +1234,9 @@ catz_process_version(dns_catz_zone_t *zone, dns_rdataset_t *value) { dns_rdataset_current(value, &rdata); result = dns_rdata_tostruct(&rdata, &rdatatxt, NULL); - RUNTIME_CHECK(result == ISC_R_SUCCESS); + if (result != ISC_R_SUCCESS) { + return (result); + } result = dns_rdata_txt_first(&rdatatxt); if (result != ISC_R_SUCCESS) { @@ -1239,6 +1268,13 @@ catz_process_version(dns_catz_zone_t *zone, dns_rdataset_t *value) { cleanup: dns_rdata_freestruct(&rdatatxt); + if (result != ISC_R_SUCCESS) { + isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, + DNS_LOGMODULE_MASTER, ISC_LOG_WARNING, + "catz: invalid record for the catalog " + "zone version property"); + zone->broken = true; + } return (result); } @@ -1682,6 +1718,14 @@ dns_catz_update_process(dns_catz_zones_t *catzs, dns_catz_zone_t *zone, REQUIRE(DNS_CATZ_ZONE_VALID(zone)); REQUIRE(ISC_MAGIC_VALID(src_name, DNS_NAME_MAGIC)); + if (rdataset->rdclass != dns_rdataclass_in) { + isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, + DNS_LOGMODULE_MASTER, ISC_LOG_ERROR, + "catz: RR found which has a non-IN class"); + zone->broken = true; + return (ISC_R_FAILURE); + } + nrres = dns_name_fullcompare(src_name, &zone->name, &order, &nlabels); if (nrres == dns_namereln_equal) { if (rdataset->type == dns_rdatatype_soa) { @@ -2059,8 +2103,10 @@ dns_catz_update_from_db(dns_db_t *db, dns_catz_zones_t *catzs) { dns_rdatasetiter_t *rdsiter = NULL; dns_rdataset_t rdataset; char bname[DNS_NAME_FORMATSIZE]; + char cname[DNS_NAME_FORMATSIZE]; bool is_vers_processed = false; uint32_t vers; + uint32_t catz_vers; REQUIRE(DNS_DB_VALID(db)); REQUIRE(DNS_CATZ_ZONES_VALID(catzs)); @@ -2137,13 +2183,13 @@ dns_catz_update_from_db(dns_db_t *db, dns_catz_zones_t *catzs) { result = dns_dbiterator_seek(it, name); if (result != ISC_R_SUCCESS) { dns_dbiterator_destroy(&it); - dns_catz_zone_detach(&newzone); dns_db_closeversion(db, &oldzone->dbversion, false); isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_MASTER, ISC_LOG_ERROR, "catz: zone '%s' has no 'version' record (%s)", bname, isc_result_totext(result)); - return; + newzone->broken = true; + goto final; } name = dns_fixedname_initname(&fixname); @@ -2189,7 +2235,6 @@ dns_catz_update_from_db(dns_db_t *db, dns_catz_zones_t *catzs) { result = dns_catz_update_process(catzs, newzone, name, &rdataset); if (result != ISC_R_SUCCESS) { - char cname[DNS_NAME_FORMATSIZE]; char typebuf[DNS_RDATATYPE_FORMATSIZE]; char classbuf[DNS_RDATACLASS_FORMATSIZE]; @@ -2203,8 +2248,8 @@ dns_catz_update_from_db(dns_db_t *db, dns_catz_zones_t *catzs) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_MASTER, ISC_LOG_WARNING, - "catz: unknown record in catalog " - "zone - %s %s %s(%s) - ignoring", + "catz: invalid record in catalog " + "zone - %s %s %s (%s) - ignoring", cname, classbuf, typebuf, isc_result_totext(result)); } @@ -2230,6 +2275,40 @@ dns_catz_update_from_db(dns_db_t *db, dns_catz_zones_t *catzs) { ISC_LOG_DEBUG(3), "catz: update_from_db: iteration finished"); + /* + * Check catalog zone version compatibilites. + */ + catz_vers = (newzone->version == DNS_CATZ_VERSION_UNDEFINED) + ? oldzone->version + : newzone->version; + if (catz_vers == DNS_CATZ_VERSION_UNDEFINED) { + isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, + DNS_LOGMODULE_MASTER, ISC_LOG_WARNING, + "catz: zone '%s' version is not set", bname); + newzone->broken = true; + } else if (catz_vers != 1 && catz_vers != 2) { + isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, + DNS_LOGMODULE_MASTER, ISC_LOG_WARNING, + "catz: zone '%s' unsupported version " + "'%" PRIu32 "'", + bname, catz_vers); + newzone->broken = true; + } else { + oldzone->version = catz_vers; + } + +final: + if (newzone->broken) { + dns_name_format(name, cname, DNS_NAME_FORMATSIZE); + isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, + DNS_LOGMODULE_MASTER, ISC_LOG_ERROR, + "catz: new catalog zone '%s' is broken and " + "will not be processed", + bname); + dns_catz_zone_detach(&newzone); + return; + } + /* * Finally merge new zone into old zone. */