mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-08-29 21:47:59 +00:00
Implement catalog zones change of ownership (coo) support
Catalog zones change of ownership is special mechanism to facilitate controlled migration of a member zone from one catalog to another. It is implemented using catalog zones property named "coo" and is documented in DNS catalog zones draft version 5 document. Implement the feature using a new hash table in the catalog zone structure, which holds the added "coo" properties for the catalog zone (containing the target catalog zone's name), and the key for the hash table being the member zone's name for which the "coo" property is being created. Change some log messages to have consistent zone name quoting types. Update the ARM with change of ownership documentation and usage examples. Add tests which check newly the added features.
This commit is contained in:
parent
e8ba18906b
commit
bb837db4ee
@ -2669,7 +2669,6 @@ catz_addmodzone_taskaction(isc_task_t *task, isc_event_t *event0) {
|
||||
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);
|
||||
|
||||
@ -2680,7 +2679,7 @@ catz_addmodzone_taskaction(isc_task_t *task, isc_event_t *event0) {
|
||||
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;
|
||||
}
|
||||
@ -2718,19 +2717,37 @@ catz_addmodzone_taskaction(isc_task_t *task, isc_event_t *event0) {
|
||||
|
||||
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 */
|
||||
@ -2757,7 +2774,7 @@ catz_addmodzone_taskaction(isc_task_t *task, isc_event_t *event0) {
|
||||
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;
|
||||
}
|
||||
@ -2784,8 +2801,8 @@ catz_addmodzone_taskaction(isc_task_t *task, isc_event_t *event0) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
1
bin/tests/system/catz/.gitignore
vendored
1
bin/tests/system/catz/.gitignore
vendored
@ -10,6 +10,7 @@
|
||||
/ns2/catalog*.example.db
|
||||
|
||||
/ns1/*dom*.example.db
|
||||
/ns3/dom2.example.db
|
||||
/ns3/dom13.example.db
|
||||
/ns3/dom14.example.db
|
||||
/ns3/dom17.example.db
|
||||
|
@ -20,7 +20,7 @@ rm -f ns*/named.run.prev
|
||||
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
|
||||
|
13
bin/tests/system/catz/ns2/dom-existing.example.db
Normal file
13
bin/tests/system/catz/ns2/dom-existing.example.db
Normal file
@ -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.
|
@ -54,6 +54,11 @@ options {
|
||||
#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";
|
||||
|
@ -32,6 +32,11 @@ options {
|
||||
# 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";
|
||||
|
@ -266,10 +266,21 @@ echo_i "adding domain dom2.example. to primary via RNDC ($n)"
|
||||
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
|
||||
@ -296,7 +307,6 @@ $NSUPDATE -d <<END >> nsupdate.out.test$n 2>&1 || ret=1
|
||||
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))
|
||||
@ -369,6 +379,166 @@ wait_for_soa @10.53.0.2 dom3.example. dig.out.test$n || 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 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
|
||||
@ -393,6 +563,52 @@ rndccmd 10.53.0.2 reconfig || 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 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
|
||||
@ -409,8 +625,8 @@ $NSUPDATE -d <<END >> nsupdate.out.test$n 2>&1 || ret=1
|
||||
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))
|
||||
@ -420,6 +636,9 @@ echo_i "removing all records from catalog2 zone ($n)"
|
||||
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
|
||||
@ -557,7 +776,7 @@ n=$((n+1))
|
||||
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))
|
||||
|
||||
@ -847,7 +1066,7 @@ n=$((n+1))
|
||||
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))
|
||||
|
||||
|
@ -261,4 +261,34 @@ Note that none of the global records for a custom property are inherited if any
|
||||
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.
|
||||
|
232
lib/dns/catz.c
232
lib/dns/catz.c
@ -35,13 +35,24 @@
|
||||
#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
|
||||
*/
|
||||
@ -62,6 +73,9 @@ struct dns_catz_zone {
|
||||
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
|
||||
@ -208,6 +222,43 @@ dns_catz_options_setdefault(isc_mem_t *mctx, const dns_catz_options_t *defaults,
|
||||
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) {
|
||||
@ -418,6 +469,7 @@ dns_catz_zones_merge(dns_catz_zone_t *target, dns_catz_zone_t *newzone) {
|
||||
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;
|
||||
@ -449,6 +501,53 @@ dns_catz_zones_merge(dns_catz_zone_t *target, dns_catz_zone_t *newzone) {
|
||||
&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) {
|
||||
@ -458,10 +557,7 @@ dns_catz_zones_merge(dns_catz_zone_t *target, dns_catz_zone_t *newzone) {
|
||||
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 "
|
||||
@ -472,7 +568,6 @@ dns_catz_zones_merge(dns_catz_zone_t *target, dns_catz_zone_t *newzone) {
|
||||
czname);
|
||||
continue;
|
||||
}
|
||||
dns_zone_detach(&zone);
|
||||
|
||||
if (dns_catz_entry_cmp(oentry, nentry) != true) {
|
||||
catz_entry_add_or_mod(target, tomod, key, keysize,
|
||||
@ -554,6 +649,33 @@ dns_catz_zones_merge(dns_catz_zone_t *target, dns_catz_zone_t *newzone) {
|
||||
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);
|
||||
@ -633,6 +755,7 @@ dns_catz_new_zone(dns_catz_zones_t *catzs, dns_catz_zone_t **zonep,
|
||||
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,
|
||||
@ -766,6 +889,26 @@ dns_catz_zone_detach(dns_catz_zone_t **zonep) {
|
||||
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) {
|
||||
@ -826,6 +969,7 @@ dns_catz_catzs_detach(dns_catz_zones_t **catzsp) {
|
||||
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,
|
||||
@ -859,6 +1003,8 @@ catz_get_option(const dns_label_t *option) {
|
||||
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 {
|
||||
@ -896,6 +1042,80 @@ catz_process_zones(dns_catz_zone_t *zone, dns_rdataset_t *value,
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
@ -1330,6 +1550,8 @@ catz_process_zones_suboption(dns_catz_zone_t *zone, dns_rdataset_t *value,
|
||||
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));
|
||||
|
@ -42,6 +42,7 @@ typedef struct dns_byaddr dns_byaddr_t;
|
||||
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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user