dns_name_totext(dns_catz_entry_getname(ev->entry), true, &namebuf);
isc_buffer_putuint8(&namebuf, 0);
- /* Zone shouldn't already exist */
result = dns_zt_find(ev->view->zonetable,
dns_catz_entry_getname(ev->entry), 0, NULL, &zone);
isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
"catz: error \"%s\" while trying to "
- "modify zone \"%s\"",
+ "modify zone '%s'",
isc_result_totext(result), nameb);
goto cleanup;
}
dns_zone_detach(&zone);
} else {
+ /* Zone shouldn't already exist when adding */
if (result == ISC_R_SUCCESS) {
- isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
- NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
- "catz: zone \"%s\" is overridden "
- "by explicitly configured zone",
- nameb);
+ if (dns_zone_get_parentcatz(zone) == NULL) {
+ isc_log_write(
+ named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
+ NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
+ "catz: "
+ "catz_addmodzone_taskaction: "
+ "zone '%s' will not be added "
+ "because it is an explicitly "
+ "configured zone",
+ nameb);
+ } else {
+ isc_log_write(
+ named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
+ NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
+ "catz: "
+ "catz_addmodzone_taskaction: "
+ "zone '%s' will not be added "
+ "because another catalog zone "
+ "already contains an entry with "
+ "that zone",
+ nameb);
+ }
goto cleanup;
} else if (result != ISC_R_NOTFOUND &&
result != DNS_R_PARTIALMATCH) {
isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
"catz: error \"%s\" while trying to "
- "add zone \"%s\"",
+ "add zone '%s'",
isc_result_totext(result), nameb);
goto cleanup;
} else { /* this can happen in case of DNS_R_PARTIALMATCH */
isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
"catz: error \"%s\" while trying to generate "
- "config for zone \"%s\"",
+ "config for zone '%s'",
isc_result_totext(result), nameb);
goto cleanup;
}
if (result != ISC_R_SUCCESS) {
isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
- "catz: failed to configure zone \"%s\" - %d",
- nameb, result);
+ "catz: failed to configure zone '%s' - %d", nameb,
+ result);
goto cleanup;
}
/ns2/catalog*.example.db
/ns1/*dom*.example.db
+/ns3/dom2.example.db
/ns3/dom13.example.db
/ns3/dom14.example.db
/ns3/dom17.example.db
rm -f ns1/*dom*example.db
rm -f ns2/__catz__*db
rm -f ns2/named.conf.tmp
-rm -f ns3/dom13.example.db ns3/dom14.example.db ns3/dom17.example.db ns3/dom18.example.db
+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.*
rm -f ns[123]/catalog[1234].example.db
rm -rf ns2/zonedir
--- /dev/null
+; 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.
#T3 database "dlopen bad-dlz.so example.org";
#T3};
+zone "dom-existing.example" {
+ type primary;
+ file "dom-existing.example.db";
+};
+
zone "catalog1.example" {
type secondary;
file "catalog1.example.db";
# identical to named1.conf.in
};
+zone "dom-existing.example" {
+ type primary;
+ file "dom-existing.example.db";
+};
+
zone "catalog1.example" {
type secondary;
file "catalog1.example.db";
ret=0
echo "@ 3600 IN SOA . . 1 3600 3600 3600 3600" > ns1/dom2.example.db
echo "@ IN NS invalid." >> ns1/dom2.example.db
+echo "@ IN A 192.0.2.1" >> ns1/dom2.example.db
rndccmd 10.53.0.1 addzone dom2.example. '{type primary; file "dom2.example.db";};' || ret=1
if [ $ret -ne 0 ]; then echo_i "failed"; fi
status=$((status+ret))
+n=$((n+1))
+echo_i "adding domain dom2.example. to primary ns3 via RNDC ($n)"
+ret=0
+echo "@ 3600 IN SOA . . 1 3600 3600 3600 3600" > ns3/dom2.example.db
+echo "@ IN NS invalid." >> ns3/dom2.example.db
+echo "@ IN A 192.0.2.2" >> ns3/dom2.example.db
+rndccmd 10.53.0.3 addzone dom2.example. '{type primary; file "dom2.example.db";};' || ret=1
+if [ $ret -ne 0 ]; then echo_i "failed"; fi
+status=$((status+ret))
+
n=$((n+1))
echo_i "adding domain dom4.example. to primary via RNDC ($n)"
ret=0
update add blahblah.636722929740e507aaf27c502812fc395d30fb17.zones.catalog1.example. 3600 IN TXT "blah blah"
update add version.catalog1.example. 3600 IN A 1.2.3.4
send
-
END
if [ $ret -ne 0 ]; then echo_i "failed"; fi
status=$((status+ret))
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
+$NSUPDATE -d <<END >> nsupdate.out.test$n 2>&1 || ret=1
+ server 10.53.0.3 ${PORT}
+ update add dom2-without-coo.zones.catalog2.example. 3600 IN PTR dom2.example.
+ update add primaries.dom2-without-coo.zones.catalog2.example. 3600 IN A 10.53.0.3
+ 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 ($n)"
+ret=0
+wait_for_message ns2/named.run "catz: adding zone 'dom2.example' from catalog 'catalog2.example'" || ret=1
+if [ $ret -ne 0 ]; then echo_i "failed"; fi
+status=$((status+ret))
+
+n=$((n+1))
+echo_i "checking that unpermitted change of ownership did not happen ($n)"
+ret=0
+wait_for_message ns2/named.run "catz_addmodzone_taskaction: zone 'dom2.example' will not be added because another catalog zone already contains an entry with that zone" || ret=1
+if [ $ret -ne 0 ]; then echo_i "failed"; fi
+status=$((status+ret))
+
+n=$((n+1))
+echo_i "checking that dom2.example. is served by secondary and that it's the one from ns1 ($n)"
+ret=0
+wait_for_a @10.53.0.2 dom2.example. dig.out.test$n || ret=1
+grep "192.0.2.1" dig.out.test$n > /dev/null || 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 "adding change of ownership permission record for dom2.example. into catalog1 zone ($n)"
+ret=0
+$NSUPDATE -d <<END >> nsupdate.out.test$n 2>&1 || ret=1
+ server 10.53.0.1 ${PORT}
+ update add coo.636722929740e507aaf27c502812fc395d30fb17.zones.catalog1.example. 3600 IN PTR catalog2.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 ($n)"
+ret=0
+wait_for_message ns2/named.run "catz: updating catalog zone 'catalog1.example'" &&
+wait_for_message ns2/named.run "catz: update_from_db: new zone merged" || ret=1
+if [ $ret -ne 0 ]; then echo_i "failed"; fi
+status=$((status+ret))
+
+n=$((n+1))
+echo_i "updating catalog2 zone to initiate a zone transfer ($n)"
+ret=0
+$NSUPDATE -d <<END >> nsupdate.out.test$n 2>&1 || ret=1
+ server 10.53.0.3 ${PORT}
+ update delete dom2-without-coo.zones.catalog2.example. 3600 IN PTR dom2.example.
+ update delete primaries.dom2-without-coo.zones.catalog2.example. 3600 IN A 10.53.0.3
+ update add dom2-with-coo.zones.catalog2.example. 3600 IN PTR dom2.example.
+ update add primaries.dom2-with-coo.zones.catalog2.example. 3600 IN A 10.53.0.3
+ 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 change of ownership was successful ($n)"
+ret=0
+wait_for_message ns2/named.run "catz: zone 'dom2.example' change of ownership from 'catalog1.example' to 'catalog2.example'" &&
+wait_for_message ns2/named.run "catz: deleting zone 'dom2.example' from catalog 'catalog1.example' - success" &&
+wait_for_message ns2/named.run "catz: adding zone 'dom2.example' from catalog 'catalog2.example'" &&
+wait_for_message ns2/named.run "transfer of 'dom2.example/IN' from 10.53.0.3#${PORT}: Transfer status: success" || ret=1
+if [ $ret -ne 0 ]; then echo_i "failed"; fi
+status=$((status+ret))
+
+n=$((n+1))
+echo_i "checking that dom2.example. is served by secondary and that it's now the one from ns3 ($n)"
+ret=0
+wait_for_a @10.53.0.2 dom2.example. dig.out.test$n || ret=1
+grep "192.0.2.2" dig.out.test$n > /dev/null || 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 "removing dom2.example. and its change of ownership permission record from catalog1 zone ($n)"
+ret=0
+$NSUPDATE -d <<END >> 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 PTR catalog2.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 ($n)"
+ret=0
+wait_for_message ns2/named.run "catz: update_from_db: iteration finished" || 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 "adding change of ownership permission record for dom2.example. into catalog2 zone ($n)"
+ret=0
+$NSUPDATE -d <<END >> nsupdate.out.test$n 2>&1 || ret=1
+ server 10.53.0.3 ${PORT}
+ update add coo.dom2-with-coo.zones.catalog2.example. 3600 IN PTR catalog1.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 ($n)"
+ret=0
+wait_for_message ns2/named.run "catz: update_from_db: iteration finished" || 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 "adding back dom2.example. into catalog1 zone ($n)"
+ret=0
+$NSUPDATE -d <<END >> 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.
+ send
+END
+if [ $ret -ne 0 ]; then echo_i "failed"; fi
+status=$((status+ret))
+
+n=$((n+1))
+echo_i "checking that the change of ownership did not happen because version '1' catalog2 zone does not support the 'coo' property ($n)"
+ret=0
+wait_for_message ns2/named.run "catz_addmodzone_taskaction: zone 'dom2.example' will not be added because another catalog zone already contains an entry with that zone" || ret=1
+if [ $ret -ne 0 ]; then echo_i "failed"; fi
+status=$((status+ret))
+
+n=$((n+1))
+echo_i "checking that dom2.example. is still served by secondary and that it's still the one from ns3 ($n)"
+ret=0
+wait_for_a @10.53.0.2 dom2.example. dig.out.test$n || ret=1
+grep "192.0.2.2" dig.out.test$n > /dev/null || 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 "reconfiguring secondary - checking if catz survives a certain class of failed reconfiguration attempts ($n)"
ret=0
if [ $ret -ne 0 ]; then echo_i "failed"; fi
status=$((status+ret))
+nextpart ns2/named.run >/dev/null
+
+n=$((n+1))
+echo_i "adding a domain dom-existing.example. to primary via RNDC ($n)"
+ret=0
+echo "@ 3600 IN SOA . . 1 3600 3600 3600 3600" > ns1/dom-existing.example.db
+echo "@ IN NS invalid." >> ns1/dom-existing.example.db
+echo "@ IN A 192.0.2.1" >> ns1/dom-existing.example.db
+rndccmd 10.53.0.1 addzone dom-existing.example. '{type primary; file "dom-existing.example.db"; also-notify { 10.53.0.2; }; notify explicit; };' || ret=1
+if [ $ret -ne 0 ]; then echo_i "failed"; fi
+status=$((status+ret))
+
+n=$((n+1))
+echo_i "checking that dom-existing.example. is served by primary ($n)"
+ret=0
+wait_for_a @10.53.0.1 dom-existing.example. dig.out.test$n || ret=1
+if [ $ret -ne 0 ]; then echo_i "failed"; fi
+status=$((status+ret))
+
+n=$((n+1))
+echo_i "adding domain dom-existing.example. to catalog1 zone to test that existing zones don't get overwritten ($n)"
+ret=0
+$NSUPDATE -d <<END >> nsupdate.out.test$n 2>&1 || ret=1
+ server 10.53.0.1 ${PORT}
+ update add dom-existing.zones.catalog1.example. 3600 IN PTR dom-existing.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 ($n)"
+ret=0
+wait_for_message ns2/named.run "catz: adding zone 'dom-existing.example' from catalog 'catalog1.example'" &&
+wait_for_message ns2/named.run "catz_addmodzone_taskaction: zone 'dom-existing.example' will not be added because it is an explicitly configured zone" || ret=1
+if [ $ret -ne 0 ]; then echo_i "failed"; fi
+status=$((status+ret))
+
+n=$((n+1))
+echo_i "checking that dom-existing.example. is served by secondary and that it's not the one from the primary ns1 ($n)"
+ret=0
+wait_for_a @10.53.0.2 dom-existing.example. dig.out.test$n || ret=1
+grep "192.0.2.1" dig.out.test$n > /dev/null && ret=1
+if [ $ret -ne 0 ]; then echo_i "failed"; fi
+status=$((status+ret))
+
n=$((n+1))
echo_i "removing all records from catalog1 zone ($n)"
ret=0
update delete foobarbaz.b901f492f3ebf6c1e5b597e51766f02f0479eb03.zones.catalog1.example. 3600 IN APL 1:1.2.3.4/30
update delete blahblah.636722929740e507aaf27c502812fc395d30fb17.zones.catalog1.example. 3600 IN TXT "blah blah"
update delete version.catalog1.example. 3600 IN A 1.2.3.4
+ update delete dom-existing.zones.catalog1.example. 3600 IN PTR dom-existing.example.
send
-
END
if [ $ret -ne 0 ]; then echo_i "failed"; fi
status=$((status+ret))
ret=0
$NSUPDATE -d <<END >> nsupdate.out.test$n 2>&1 || ret=1
server 10.53.0.3 ${PORT}
+ update delete dom2-with-coo.zones.catalog2.example. 3600 IN PTR dom2.example.
+ update delete primaries.dom2-with-coo.zones.catalog2.example. 3600 IN A 10.53.0.3
+ update delete coo.dom2-with-coo.zones.catalog2.example. 3600 IN PTR catalog1.example.
update delete de26b88d855397a03f77ff1162fd055d8b419584.zones.catalog2.example. 3600 IN PTR dom4.example.
send
END
echo_i "waiting for secondary to sync up ($n)"
ret=0
wait_for_message ns2/named.run "catz: adding zone 'dom6.example' from catalog 'catalog1.example'" &&
-wait_for_message ns2/named.run "error \"failure\" while trying to generate config for zone \"dom6.example\"" || ret=1
+wait_for_message ns2/named.run "error \"failure\" while trying to generate config for zone 'dom6.example'" || ret=1
if [ $ret -ne 0 ]; then echo_i "failed"; fi
status=$((status+ret))
echo_i "waiting for secondary to sync up ($n)"
ret=0
wait_for_message ns2/named.run "catz: adding zone 'dom9.example' from catalog 'catalog1.example'" &&
-wait_for_message ns2/named.run "error \"failure\" while trying to generate config for zone \"dom9.example\"" || ret=1
+wait_for_message ns2/named.run "error \"failure\" while trying to generate config for zone 'dom9.example'" || ret=1
if [ $ret -ne 0 ]; then echo_i "failed"; fi
status=$((status+ret))
records are defined for that custom property for the specific zone. For example,
if the zone had a ``primaries`` record of type A but not AAAA, it
would *not* inherit the type AAAA record from the global custom property
-or from global the option in the configuration file.
+or from the global option in the configuration file.
+
+Change of Ownership (coo)
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+BIND supports the catalog zones "Change of Ownership" (coo) property. When the
+same entry which exists in one catalog zone is added into another catalog zone,
+the default behavior for BIND is to ignore it, and continue serving the zone
+using the catalog zone where it was originally existed, unless it is removed
+from there, then it can be added into the new one.
+
+Using the ``coo`` property it is possible to gracefully move a zone from one
+catalog zone into another, by letting the catalog consumers know that it is
+permitted to do so. To do that, the original catalog zone should be updated with
+a new record with ``coo`` custom property:
+
+::
+
+ uniquelabel.zones.catalog.example. IN PTR domain2.example.
+ coo.uniquelabel.zones.catalog.example. IN PTR catalog2.example.
+
+Here, the ``catalog.example`` catalog zone gives permission for the member zone
+with label "uniquelabel" to be transferred into ``catalog2.example`` catalog
+zone. Catalog consumers which support the ``coo`` property will then take note,
+and when the zone is finally added into ``catalog2.example`` catalog zone,
+catalog consumers will change the ownership of the zone from ``catalog.example``
+to ``catalog2.example``. BIND's implementation simply deletes the zone from the
+old catalog zone and adds it back into the new catalog zone. The record with
+``coo`` custom property can be later deleted by the catalog zone operator, if it
+is confirmed that all the consumers have received it and have successfully
+changed the ownership of the zone.
#define DNS_CATZ_ZONE_MAGIC ISC_MAGIC('c', 'a', 't', 'z')
#define DNS_CATZ_ZONES_MAGIC ISC_MAGIC('c', 'a', 't', 's')
#define DNS_CATZ_ENTRY_MAGIC ISC_MAGIC('c', 'a', 't', 'e')
+#define DNS_CATZ_COO_MAGIC ISC_MAGIC('c', 'a', 't', 'c')
#define DNS_CATZ_ZONE_VALID(catz) ISC_MAGIC_VALID(catz, DNS_CATZ_ZONE_MAGIC)
#define DNS_CATZ_ZONES_VALID(catzs) ISC_MAGIC_VALID(catzs, DNS_CATZ_ZONES_MAGIC)
#define DNS_CATZ_ENTRY_VALID(entry) ISC_MAGIC_VALID(entry, DNS_CATZ_ENTRY_MAGIC)
+#define DNS_CATZ_COO_VALID(coo) ISC_MAGIC_VALID(coo, DNS_CATZ_COO_MAGIC)
#define DNS_CATZ_VERSION_UNDEFINED ((uint32_t)(-1))
+/*%
+ * Change of ownership permissions
+ */
+struct dns_catz_coo {
+ unsigned int magic;
+ dns_name_t name;
+ isc_refcount_t refs;
+};
+
/*%
* Single member zone in a catalog
*/
dns_rdata_t soa;
/* key in entries is 'mhash', not domain name! */
isc_ht_t *entries;
+ /* key in coos is domain name */
+ isc_ht_t *coos;
+
/*
* defoptions are taken from named.conf
* zoneoptions are global options from zone
opts->in_memory = defaults->in_memory;
}
+static void
+catz_coo_new(isc_mem_t *mctx, const dns_name_t *domain,
+ dns_catz_coo_t **ncoop) {
+ dns_catz_coo_t *ncoo;
+
+ REQUIRE(mctx != NULL);
+ REQUIRE(domain != NULL);
+ REQUIRE(ncoop != NULL && *ncoop == NULL);
+
+ ncoo = isc_mem_get(mctx, sizeof(dns_catz_coo_t));
+ dns_name_init(&ncoo->name, NULL);
+ dns_name_dup(domain, mctx, &ncoo->name);
+ isc_refcount_init(&ncoo->refs, 1);
+ ncoo->magic = DNS_CATZ_COO_MAGIC;
+ *ncoop = ncoo;
+}
+
+static void
+catz_coo_detach(dns_catz_zone_t *zone, dns_catz_coo_t **coop) {
+ dns_catz_coo_t *coo;
+
+ REQUIRE(DNS_CATZ_ZONE_VALID(zone));
+ REQUIRE(coop != NULL && DNS_CATZ_COO_VALID(*coop));
+ coo = *coop;
+ *coop = NULL;
+
+ if (isc_refcount_decrement(&coo->refs) == 1) {
+ isc_mem_t *mctx = zone->catzs->mctx;
+ coo->magic = 0;
+ isc_refcount_destroy(&coo->refs);
+ if (dns_name_dynamic(&coo->name)) {
+ dns_name_free(&coo->name, mctx);
+ }
+ isc_mem_put(mctx, coo, sizeof(dns_catz_coo_t));
+ }
+}
+
void
dns_catz_entry_new(isc_mem_t *mctx, const dns_name_t *domain,
dns_catz_entry_t **nentryp) {
result = delcur ? isc_ht_iter_delcurrent_next(iter1)
: isc_ht_iter_next(iter1))
{
+ isc_result_t zt_find_result;
dns_catz_entry_t *nentry = NULL;
dns_catz_entry_t *oentry = NULL;
dns_zone_t *zone = NULL;
&target->zoneoptions,
&nentry->opts);
+ /* Try to find the zone in the view */
+ zt_find_result = dns_zt_find(target->catzs->view->zonetable,
+ dns_catz_entry_getname(nentry), 0,
+ NULL, &zone);
+ if (zt_find_result == ISC_R_SUCCESS) {
+ dns_catz_zone_t *parentcatz = NULL;
+ dns_catz_coo_t *coo = NULL;
+ char pczname[DNS_NAME_FORMATSIZE];
+
+ /*
+ * Change of ownership (coo) processing, if required
+ */
+ parentcatz = dns_zone_get_parentcatz(zone);
+ if (parentcatz != NULL && parentcatz != target &&
+ isc_ht_find(parentcatz->coos, nentry->name.ndata,
+ nentry->name.length,
+ (void **)&coo) == ISC_R_SUCCESS &&
+ dns_name_equal(&coo->name, &target->name))
+ {
+ dns_name_format(&parentcatz->name, pczname,
+ DNS_NAME_FORMATSIZE);
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
+ DNS_LOGMODULE_MASTER,
+ ISC_LOG_DEBUG(3),
+ "catz: zone '%s' "
+ "change of ownership from "
+ "'%s' to '%s'",
+ zname, pczname, czname);
+ result = delzone(nentry, parentcatz,
+ parentcatz->catzs->view,
+ parentcatz->catzs->taskmgr,
+ parentcatz->catzs->zmm->udata);
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
+ DNS_LOGMODULE_MASTER,
+ ISC_LOG_INFO,
+ "catz: deleting zone '%s' "
+ "from catalog '%s' - %s",
+ zname, pczname,
+ isc_result_totext(result));
+ }
+ }
+ if (zt_find_result == ISC_R_SUCCESS ||
+ zt_find_result == DNS_R_PARTIALMATCH) {
+ dns_zone_detach(&zone);
+ }
+
+ /* Try to find the zone in the old catalog zone */
result = isc_ht_find(target->entries, key, (uint32_t)keysize,
(void **)&oentry);
if (result != ISC_R_SUCCESS) {
continue;
}
- result = dns_zt_find(target->catzs->view->zonetable,
- dns_catz_entry_getname(nentry), 0, NULL,
- &zone);
- if (result != ISC_R_SUCCESS) {
+ if (zt_find_result != ISC_R_SUCCESS) {
isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
DNS_LOGMODULE_MASTER, ISC_LOG_DEBUG(3),
"catz: zone '%s' was expected to exist "
czname);
continue;
}
- dns_zone_detach(&zone);
if (dns_catz_entry_cmp(oentry, nentry) != true) {
catz_entry_add_or_mod(target, tomod, key, keysize,
target->entries = newzone->entries;
newzone->entries = NULL;
+ /*
+ * We do not need to merge old coo (change of ownership) permission
+ * records with the new ones, just replace them.
+ */
+ if (target->coos != NULL && newzone->coos != NULL) {
+ isc_ht_iter_t *iter = NULL;
+
+ isc_ht_iter_create(target->coos, &iter);
+ for (result = isc_ht_iter_first(iter); result == ISC_R_SUCCESS;
+ result = isc_ht_iter_delcurrent_next(iter))
+ {
+ dns_catz_coo_t *coo = NULL;
+
+ isc_ht_iter_current(iter, (void **)&coo);
+ catz_coo_detach(target, &coo);
+ }
+ INSIST(result == ISC_R_NOMORE);
+ isc_ht_iter_destroy(&iter);
+
+ /* The hashtable has to be empty now. */
+ INSIST(isc_ht_count(target->coos) == 0);
+ isc_ht_destroy(&target->coos);
+
+ target->coos = newzone->coos;
+ newzone->coos = NULL;
+ }
+
result = ISC_R_SUCCESS;
isc_ht_iter_destroy(&iteradd);
dns_name_dup(name, catzs->mctx, &new_zone->name);
isc_ht_init(&new_zone->entries, catzs->mctx, 4, ISC_HT_CASE_SENSITIVE);
+ isc_ht_init(&new_zone->coos, catzs->mctx, 4, ISC_HT_CASE_INSENSITIVE);
new_zone->updatetimer = NULL;
isc_timer_create(catzs->timermgr, catzs->updater,
INSIST(isc_ht_count(zone->entries) == 0);
isc_ht_destroy(&zone->entries);
}
+ if (zone->coos != NULL) {
+ isc_ht_iter_t *iter = NULL;
+ isc_result_t result;
+ isc_ht_iter_create(zone->coos, &iter);
+ for (result = isc_ht_iter_first(iter);
+ result == ISC_R_SUCCESS;
+ result = isc_ht_iter_delcurrent_next(iter))
+ {
+ dns_catz_coo_t *coo = NULL;
+
+ isc_ht_iter_current(iter, (void **)&coo);
+ catz_coo_detach(zone, &coo);
+ }
+ INSIST(result == ISC_R_NOMORE);
+ isc_ht_iter_destroy(&iter);
+
+ /* The hashtable has to be empty now. */
+ INSIST(isc_ht_count(zone->coos) == 0);
+ isc_ht_destroy(&zone->coos);
+ }
zone->magic = 0;
isc_timer_destroy(&zone->updatetimer);
if (zone->db_registered) {
typedef enum {
CATZ_OPT_NONE,
CATZ_OPT_ZONES,
+ CATZ_OPT_COO,
CATZ_OPT_VERSION,
CATZ_OPT_CUSTOM_START, /* CATZ custom properties must go below this */
CATZ_OPT_EXT,
return (CATZ_OPT_ALLOW_QUERY);
} else if (catz_opt_cmp(option, "allow-transfer")) {
return (CATZ_OPT_ALLOW_TRANSFER);
+ } else if (catz_opt_cmp(option, "coo")) {
+ return (CATZ_OPT_COO);
} else if (catz_opt_cmp(option, "version")) {
return (CATZ_OPT_VERSION);
} else {
}
}
+static isc_result_t
+catz_process_coo(dns_catz_zone_t *zone, dns_label_t *mhash,
+ dns_rdataset_t *value) {
+ isc_result_t result;
+ dns_rdata_t rdata;
+ dns_rdata_ptr_t ptr;
+ dns_catz_entry_t *entry = NULL;
+ dns_catz_coo_t *ncoo = NULL;
+ dns_catz_coo_t *ocoo = NULL;
+
+ REQUIRE(DNS_CATZ_ZONE_VALID(zone));
+ REQUIRE(mhash != NULL);
+ REQUIRE(DNS_RDATASET_VALID(value));
+
+ /* Change of Ownership was introduced in version "2" of the schema. */
+ if (zone->version < 2) {
+ return (ISC_R_FAILURE);
+ }
+
+ if (value->rdclass != dns_rdataclass_in ||
+ value->type != dns_rdatatype_ptr) {
+ return (ISC_R_FAILURE);
+ }
+
+ result = dns_rdataset_first(value);
+ if (result != ISC_R_SUCCESS) {
+ return (result);
+ }
+
+ dns_rdata_init(&rdata);
+ dns_rdataset_current(value, &rdata);
+
+ result = dns_rdata_tostruct(&rdata, &ptr, NULL);
+ if (result != ISC_R_SUCCESS) {
+ return (result);
+ }
+
+ if (dns_name_countlabels(&ptr.ptr) == 0) {
+ result = ISC_R_FAILURE;
+ goto cleanup;
+ }
+
+ result = isc_ht_find(zone->entries, mhash->base, mhash->length,
+ (void **)&entry);
+ if (result != ISC_R_SUCCESS) {
+ /* The entry was not found .*/
+ goto cleanup;
+ }
+
+ if (dns_name_countlabels(&entry->name) == 0) {
+ result = ISC_R_FAILURE;
+ goto cleanup;
+ }
+
+ result = isc_ht_find(zone->coos, entry->name.ndata, entry->name.length,
+ (void **)&ocoo);
+ if (result == ISC_R_SUCCESS) {
+ /* The change of ownership permission was already registered. */
+ goto cleanup;
+ }
+
+ catz_coo_new(zone->catzs->mctx, &ptr.ptr, &ncoo);
+ result = isc_ht_add(zone->coos, entry->name.ndata, entry->name.length,
+ ncoo);
+ if (result != ISC_R_SUCCESS) {
+ catz_coo_detach(zone, &ncoo);
+ }
+
+cleanup:
+ dns_rdata_freestruct(&ptr);
+
+ return (result);
+}
+
static isc_result_t
catz_process_zones_entry(dns_catz_zone_t *zone, dns_rdataset_t *value,
dns_label_t *mhash) {
dns_name_init(&prefix, NULL);
dns_name_split(name, suffix_labels, &prefix, NULL);
switch (opt) {
+ case CATZ_OPT_COO:
+ return (catz_process_coo(zone, mhash, value));
case CATZ_OPT_MASTERS:
return (catz_process_primaries(zone, &entry->opts.masters,
value, &prefix));
typedef struct dns_catz_zonemodmethods dns_catz_zonemodmethods_t;
typedef struct dns_catz_entry_options dns_catz_options_t;
typedef struct dns_catz_entry dns_catz_entry_t;
+typedef struct dns_catz_coo dns_catz_coo_t;
typedef struct dns_catz_zone dns_catz_zone_t;
typedef struct dns_catz_changed dns_catz_changed_t;
typedef struct dns_catz_zones dns_catz_zones_t;