[9.20] fix: usr: Fix a catalog zones issue when a member zone could fail to load

A catalog zone's member zone could fail to load in some rare cases, when
the internally generated zone configuration string was exceeding 512
bytes. That condition only was not enough for the issue to arise, but it
was a necessary condition. This could happen, for example, if the catalog
zone's default primary servers list contained a large number of items.
This has been fixed.

Closes #5658

Backport of MR !11281

Merge branch 'backport-5658-dns_catz_generate_zonecfg-bug-fix-9.20' into 'bind-9.20'

See merge request isc-projects/bind9!11349
This commit is contained in:
Arаm Sаrgsyаn 2025-12-09 11:12:32 +00:00
commit 95cbc2c327
7 changed files with 125 additions and 21 deletions

View file

@ -2853,20 +2853,26 @@ catz_addmodzone_cb(void *arg) {
cfg_parser_reset(cfg->add_parser);
result = cfg_parse_buffer(cfg->add_parser, confbuf, "catz", 0,
&cfg_type_addzoneconf, 0, &zoneconf);
isc_buffer_free(&confbuf);
}
/*
* Fail if either dns_catz_generate_zonecfg() or cfg_parse_buffer()
* failed.
*/
if (result != ISC_R_SUCCESS) {
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'",
isc_result_totext(result), nameb);
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'%s%.*s%s",
isc_result_totext(result), nameb,
confbuf != NULL ? " buffer '" : "",
confbuf != NULL ? (int)isc_buffer_usedlength(confbuf)
: 0,
confbuf != NULL ? (char *)isc_buffer_base(confbuf) : "",
confbuf != NULL ? "'" : "");
goto cleanup;
}
isc_buffer_free(&confbuf);
CHECK(cfg_map_get(zoneconf, "zone", &zlist));
if (!cfg_obj_islist(zlist)) {
CHECK(ISC_R_FAILURE);
@ -2926,6 +2932,9 @@ catz_addmodzone_cb(void *arg) {
dns_zone_set_parentcatz(zone, cz->origin);
cleanup:
if (confbuf != NULL) {
isc_buffer_free(&confbuf);
}
if (zone != NULL) {
dns_zone_detach(&zone);
}

View file

@ -137,6 +137,16 @@ view "default" {
also-notify { 10.53.0.4; };
notify explicit;
};
# A catalog zone to test specific issues
zone "catalog-misc.example" {
type primary;
file "catalog-misc.example.db";
allow-transfer { any; };
allow-update { any; };
also-notify { 10.53.0.4; };
notify explicit;
};
};
view "ch" ch {
@ -162,3 +172,8 @@ key next_key. {
secret "LaAnCU+Z";
algorithm @DEFAULT_HMAC@;
};
key longlonglongname0123456789abcdef. {
secret "LaAnCU+Z";
algorithm @DEFAULT_HMAC@;
};

View file

@ -35,6 +35,9 @@ options {
dnssec-validation no;
catalog-zones {
zone "catalog-misc.example"
min-update-interval 1s
default-primaries { 10.53.0.1; };
zone "catalog-tls.example"
min-update-interval 1s
default-primaries { 10.53.0.1 key tsig_key tls ephemeral; };
@ -50,6 +53,12 @@ zone "catalog-tls.example" {
primaries { 10.53.0.1 key tsig_key tls ephemeral; };
};
zone "catalog-misc.example" {
type secondary;
file "catalog-misc.example.db";
primaries { 10.53.0.1; };
};
zone "catalog-self.example" {
type primary;
file "catalog-self.example.db";
@ -65,3 +74,8 @@ key next_key. {
secret "LaAnCU+Z";
algorithm @DEFAULT_HMAC@;
};
key longlonglongname0123456789abcdef. {
secret "LaAnCU+Z";
algorithm @DEFAULT_HMAC@;
};

View file

@ -25,6 +25,7 @@ cp -f ns1/catalog.example.db.in ns1/catalog3.example.db
cp -f ns1/catalog.example.db.in ns1/catalog4.example.db
# catalog5 is missing on purpose
cp -f ns1/catalog.example.db.in ns1/catalog6.example.db
cp -f ns1/catalog.example.db.in ns1/catalog-misc.example.db
cp -f ns1/catalog.example.db.in ns1/catalog-tls.example.db
cp -f ns4/catalog.example.db.in ns4/catalog-self.example.db

View file

@ -2652,6 +2652,74 @@ wait_for_soa @10.53.0.4 tls1.example. dig.out.test$n || ret=1
if [ $ret -ne 0 ]; then echo_i "failed"; fi
status=$((status + ret))
##########################################################################
# GL #5658
n=$((n + 1))
echo_i "Adding a domain longlong.longlong.long.long.name.example. to primary via RNDC ($n)"
ret=0
# enough initial content for IXFR response when TXT record is added below
echo "@ 3600 IN SOA . . 1 3600 3600 3600 3600" >ns1/longlong.longlong.long.long.name.example.db
echo "@ 3600 IN NS invalid." >>ns1/longlong.longlong.long.long.name.example.db
echo "foo 3600 IN TXT some content here" >>ns1/longlong.longlong.long.long.name.example.db
echo "bar 3600 IN TXT some content here" >>ns1/longlong.longlong.long.long.name.example.db
echo "xxx 3600 IN TXT some content here" >>ns1/longlong.longlong.long.long.name.example.db
echo "yyy 3600 IN TXT some content here" >>ns1/longlong.longlong.long.long.name.example.db
rndccmd 10.53.0.1 addzone longlong.longlong.long.long.name.example. in default '{ type primary; file "longlong.longlong.long.long.name.example.db"; allow-transfer { key longlonglongname0123456789abcdef; }; allow-update { any; }; notify explicit; also-notify { 10.53.0.4; }; };' || ret=1
if [ $ret -ne 0 ]; then echo_i "failed"; fi
status=$((status + ret))
n=$((n + 1))
echo_i "checking that longlong.longlong.long.long.name.example. is now served by primary ($n)"
ret=0
wait_for_soa @10.53.0.1 longlong.longlong.long.long.name.example. dig.out.test$n || ret=1
if [ $ret -ne 0 ]; then echo_i "failed"; fi
status=$((status + ret))
nextpart ns4/named.run >/dev/null
n=$((n + 1))
echo_i "Adding domain longlong.longlong.long.long.name.example. to catalog-misc zone ($n)"
ret=0
$NSUPDATE -d <<END >>nsupdate.out.test$n 2>&1 || ret=1
server 10.53.0.1 ${PORT}
update add longlong.zones.catalog-misc.example. 3600 IN PTR longlong.longlong.long.long.name.example.
update add label1.primaries.ext.longlong.zones.catalog-misc.example. 3600 IN A 10.53.0.1
update add label1.primaries.ext.longlong.zones.catalog-misc.example. 3600 IN TXT "longlonglongname0123456789abcdef"
update add label2.primaries.ext.longlong.zones.catalog-misc.example. 3600 IN A 10.53.0.1
update add label2.primaries.ext.longlong.zones.catalog-misc.example. 3600 IN TXT "longlonglongname0123456789abcdef"
update add label3.primaries.ext.longlong.zones.catalog-misc.example. 3600 IN A 10.53.0.1
update add label3.primaries.ext.longlong.zones.catalog-misc.example. 3600 IN TXT "longlonglongname0123456789abcdef"
update add label4.primaries.ext.longlong.zones.catalog-misc.example. 3600 IN A 10.53.0.1
update add label4.primaries.ext.longlong.zones.catalog-misc.example. 3600 IN TXT "longlonglongname0123456789abcdef"
update add label5.primaries.ext.longlong.zones.catalog-misc.example. 3600 IN A 10.53.0.1
update add label5.primaries.ext.longlong.zones.catalog-misc.example. 3600 IN TXT "longlonglongname0123456789abcdef"
update add label6.primaries.ext.longlong.zones.catalog-misc.example. 3600 IN A 10.53.0.1
update add label6.primaries.ext.longlong.zones.catalog-misc.example. 3600 IN TXT "longlonglongname0123456789abcdef"
update add label7.primaries.ext.longlong.zones.catalog-misc.example. 3600 IN A 10.53.0.1
update add label7.primaries.ext.longlong.zones.catalog-misc.example. 3600 IN TXT "longlonglongname0123456789abcdef"
update add label8.primaries.ext.longlong.zones.catalog-misc.example. 3600 IN A 10.53.0.1
update add label8.primaries.ext.longlong.zones.catalog-misc.example. 3600 IN TXT "longlonglongname0123456789abcdef"
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 ns4/named.run "catz: adding zone 'longlong.longlong.long.long.name.example' from catalog 'catalog-misc.example'" \
&& wait_for_message ns4/named.run "transfer of 'longlong.longlong.long.long.name.example/IN' from 10.53.0.1#${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 longlong.longlong.long.long.name.example. is served by secondary ($n)"
ret=0
wait_for_soa @10.53.0.4 longlong.longlong.long.long.name.example. dig.out.test$n || ret=1
if [ $ret -ne 0 ]; then echo_i "failed"; fi
status=$((status + ret))
##########################################################################
# GL #3777
nextpart ns4/named.run >/dev/null

View file

@ -21,6 +21,7 @@ pytestmark = pytest.mark.extra_artifacts(
"ns*/*.nzd*",
"ns*/catalog*.example.db",
"ns*/*dom*.example.db",
"ns1/longlong.longlong.long.long.name.example.db",
"ns1/tls1.example.db",
"ns2/__catz__*.db",
"ns2/named.conf.tmp",

View file

@ -1975,7 +1975,7 @@ dns_catz_generate_zonecfg(dns_catz_zone_t *catz, dns_catz_entry_t *entry,
uint32_t i;
isc_netaddr_t netaddr;
char pbuf[sizeof("65535")]; /* used for port number */
char zname[DNS_NAME_FORMATSIZE];
char namebuf[DNS_NAME_FORMATSIZE];
REQUIRE(DNS_CATZ_ZONE_VALID(catz));
REQUIRE(DNS_CATZ_ENTRY_VALID(entry));
@ -1988,7 +1988,8 @@ dns_catz_generate_zonecfg(dns_catz_zone_t *catz, dns_catz_entry_t *entry,
isc_buffer_allocate(catz->catzs->mctx, &buffer, ISC_BUFFER_INCR);
isc_buffer_putstr(buffer, "zone \"");
dns_name_totext(&entry->name, DNS_NAME_OMITFINALDOT, buffer);
dns_name_format(&entry->name, namebuf, sizeof(namebuf));
isc_buffer_putstr(buffer, namebuf);
isc_buffer_putstr(buffer, "\" { type secondary; primaries");
isc_buffer_putstr(buffer, " { ");
@ -2001,13 +2002,12 @@ dns_catz_generate_zonecfg(dns_catz_zone_t *catz, dns_catz_entry_t *entry,
case AF_INET6:
break;
default:
dns_name_format(&entry->name, zname,
DNS_NAME_FORMATSIZE);
dns_name_format(&entry->name, namebuf, sizeof(namebuf));
isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
DNS_LOGMODULE_MASTER, ISC_LOG_ERROR,
"catz: zone '%s' uses an invalid primary "
"(no IP address assigned)",
zname);
namebuf);
result = ISC_R_FAILURE;
goto cleanup;
}
@ -2024,20 +2024,16 @@ dns_catz_generate_zonecfg(dns_catz_zone_t *catz, dns_catz_entry_t *entry,
if (entry->opts.masters.keys[i] != NULL) {
isc_buffer_putstr(buffer, " key ");
result = dns_name_totext(entry->opts.masters.keys[i],
DNS_NAME_OMITFINALDOT, buffer);
if (result != ISC_R_SUCCESS) {
goto cleanup;
}
dns_name_format(entry->opts.masters.keys[i], namebuf,
sizeof(namebuf));
isc_buffer_putstr(buffer, namebuf);
}
if (entry->opts.masters.tlss[i] != NULL) {
isc_buffer_putstr(buffer, " tls ");
result = dns_name_totext(entry->opts.masters.tlss[i],
DNS_NAME_OMITFINALDOT, buffer);
if (result != ISC_R_SUCCESS) {
goto cleanup;
}
dns_name_format(entry->opts.masters.tlss[i], namebuf,
sizeof(namebuf));
isc_buffer_putstr(buffer, namebuf);
}
isc_buffer_putstr(buffer, "; ");
}