Commit 670ca4c0e4 for bind

commit 670ca4c0e46a3e075f50b190bf2269b04f0f76be
Author: Evan Hunt <each@isc.org>
Date:   Wed Mar 25 17:18:04 2026 -0700

    Clean up confusing DNS_ZONEOPT_CHECKNS and _NOCHECKNS

    Previously, DNS_ZONEOPT_CHECKNS indicated that we should check at load
    time that the target of an NS record has a corresponding address.
    DNS_ZONEOPT_NOCHECKNS indicated that we should *not* check at load time
    for the existence of an NS rrset at the zone apex.

    This was unnecessarily confusing, so the two options have now
    been combined.  DNS_ZONEOPT_CHECKNS now checks that an NS rrset
    exists and that its in-bailiwick target names have addresses, and
    DNS_ZONEOPT_FATALNS indicates whether this is fatal.

    Incidentally also removed the dns_zone_setchecknames()/
    _getchecknames() mechanism, as it is not used.

diff --git a/bin/check/check-tool.c b/bin/check/check-tool.c
index 4301183a74..7932f577cd 100644
--- a/bin/check/check-tool.c
+++ b/bin/check/check-tool.c
@@ -79,9 +79,10 @@ bool dochecksrv = false;
 bool docheckns = false;
 #endif /* if CHECK_LOCAL */
 bool docheckrpz = false;
-dns_zoneopt_t zone_options = DNS_ZONEOPT_CHECKNS | DNS_ZONEOPT_CHECKMX |
-			     DNS_ZONEOPT_CHECKDUPRR | DNS_ZONEOPT_CHECKSPF |
-			     DNS_ZONEOPT_MANYERRORS | DNS_ZONEOPT_CHECKNAMES |
+dns_zoneopt_t zone_options = DNS_ZONEOPT_CHECKNS | DNS_ZONEOPT_FATALNS |
+			     DNS_ZONEOPT_CHECKMX | DNS_ZONEOPT_CHECKDUPRR |
+			     DNS_ZONEOPT_CHECKSPF | DNS_ZONEOPT_MANYERRORS |
+			     DNS_ZONEOPT_CHECKNAMES |
 			     DNS_ZONEOPT_CHECKINTEGRITY |
 #if CHECK_SIBLING
 			     DNS_ZONEOPT_CHECKSIBLING |
diff --git a/bin/named/server.c b/bin/named/server.c
index 83398cbdcb..f588dbe363 100644
--- a/bin/named/server.c
+++ b/bin/named/server.c
@@ -1806,7 +1806,7 @@ dns64_reverse(dns_view_t *view, isc_mem_t *mctx, isc_netaddr_t *na,
 	dns_zone_setcheckdstype(zone, dns_checkdstype_no);
 	dns_zone_setnotifytype(zone, dns_rdatatype_soa, dns_notifytype_no);
 	dns_zone_setnotifytype(zone, dns_rdatatype_cds, dns_notifytype_no);
-	dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, true);
+	dns_zone_setoption(zone, DNS_ZONEOPT_CHECKNS, false);
 	setquerystats(zone, mctx, dns_zonestat_none);
 	CHECK(dns_view_addzone(view, zone));
 	isc_log_write(NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER,
@@ -3174,8 +3174,7 @@ create_empty_zone(dns_zone_t *pzone, dns_name_t *name, dns_view_t *view,
 		dns_zone_attach(pzone, &zone);
 	}

-	dns_zone_setoption(zone, ~DNS_ZONEOPT_NOCHECKNS, false);
-	dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, true);
+	dns_zone_setoption(zone, DNS_ZONEOPT_CHECKNS, false);
 	dns_zone_setoption(zone, DNS_ZONEOPT_ZONEVERSION, false);
 	dns_zone_setcheckdstype(zone, dns_checkdstype_no);
 	dns_zone_setnotifytype(zone, dns_rdatatype_soa, dns_notifytype_no);
@@ -3282,7 +3281,7 @@ create_ipv4only_zone(dns_zone_t *pzone, dns_view_t *view,
 		dns_zone_setnotifytype(zone, dns_rdatatype_cds,
 				       dns_notifytype_no);
 		dns_zone_setautomatic(zone, true);
-		dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, true);
+		dns_zone_setoption(zone, DNS_ZONEOPT_CHECKNS, false);
 	} else {
 		dns_zone_attach(pzone, &zone);
 	}
@@ -6222,6 +6221,7 @@ configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig,
 		dns_zone_setview(zone, view);
 		dns_zone_setstats(zone, named_g_server->zonestats);
 	}
+
 	if (rpz_num != DNS_RPZ_INVALID_NUM) {
 		result = dns_zone_rpz_enable(zone, view->rpzs, rpz_num);
 		if (result != ISC_R_SUCCESS) {
@@ -6235,6 +6235,9 @@ configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig,
 		}
 	}

+	dns_zone_setoption(zone, DNS_ZONEOPT_CHECKNS, true);
+	dns_zone_setoption(zone, DNS_ZONEOPT_FATALNS, true);
+
 	if (zone_is_catz) {
 		dns_zone_catz_enable(zone, view->catzs);
 	} else if (dns_zone_catz_is_enabled(zone)) {
@@ -6282,6 +6285,8 @@ configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig,
 			dns_zone_setorigin(raw, origin);
 			dns_zone_setview(raw, view);
 			dns_zone_setstats(raw, named_g_server->zonestats);
+			dns_zone_setoption(raw, DNS_ZONEOPT_CHECKNS, true);
+			dns_zone_setoption(zone, DNS_ZONEOPT_FATALNS, true);
 			CHECK(dns_zone_link(zone, raw));
 		}
 		named_config_findopt(zoptions, toptions,
@@ -6404,7 +6409,7 @@ add_keydata_zone(dns_view_t *view, const char *directory, isc_mem_t *mctx) {
 	dns_zone_setcheckdstype(zone, dns_checkdstype_no);
 	dns_zone_setnotifytype(zone, dns_rdatatype_soa, dns_notifytype_no);
 	dns_zone_setnotifytype(zone, dns_rdatatype_cds, dns_notifytype_no);
-	dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, true);
+	dns_zone_setoption(zone, DNS_ZONEOPT_CHECKNS, false);
 	dns_zone_setjournalsize(zone, 0);

 	dns_zone_setstats(zone, named_g_server->zonestats);
diff --git a/lib/dns/include/dns/zone.h b/lib/dns/include/dns/zone.h
index b06b40f783..114f849a67 100644
--- a/lib/dns/include/dns/zone.h
+++ b/lib/dns/include/dns/zone.h
@@ -105,29 +105,28 @@ typedef enum {
 	DNS_ZONEOPT_CHECKMX = 1 << 10,	    /*%< check-mx */
 	DNS_ZONEOPT_CHECKMXFAIL = 1 << 11,  /*%< fatal check-mx failures */
 	DNS_ZONEOPT_CHECKINTEGRITY = 1 << 12, /*%< perform integrity checks */
-	DNS_ZONEOPT_CHECKSIBLING = 1 << 13, /*%< perform sibling glue checks */
-	DNS_ZONEOPT_NOCHECKNS = 1 << 14,    /*%< disable IN NS address checks */
-	DNS_ZONEOPT_WARNMXCNAME = 1 << 15,  /*%< warn on MX CNAME check */
-	DNS_ZONEOPT_IGNOREMXCNAME = 1 << 16,  /*%< ignore MX CNAME check */
-	DNS_ZONEOPT_WARNSRVCNAME = 1 << 17,   /*%< warn on SRV CNAME check */
-	DNS_ZONEOPT_IGNORESRVCNAME = 1 << 18, /*%< ignore SRV CNAME check */
-	DNS_ZONEOPT_UPDATECHECKKSK = 1 << 19, /*%< check dnskey KSK flag */
-	DNS_ZONEOPT_TRYTCPREFRESH = 1 << 20, /*%< try tcp refresh on udp failure
+	DNS_ZONEOPT_CHECKSIBLING = 1 << 13,  /*%< perform sibling glue checks */
+	DNS_ZONEOPT_WARNMXCNAME = 1 << 14,   /*%< warn on MX CNAME check */
+	DNS_ZONEOPT_IGNOREMXCNAME = 1 << 15, /*%< ignore MX CNAME check */
+	DNS_ZONEOPT_WARNSRVCNAME = 1 << 16,  /*%< warn on SRV CNAME check */
+	DNS_ZONEOPT_IGNORESRVCNAME = 1 << 17, /*%< ignore SRV CNAME check */
+	DNS_ZONEOPT_UPDATECHECKKSK = 1 << 18, /*%< check dnskey KSK flag */
+	DNS_ZONEOPT_TRYTCPREFRESH = 1 << 19, /*%< try tcp refresh on udp failure
 					      */
-	DNS_ZONEOPT_NOTIFYTOSOA = 1 << 21,   /*%< Notify the SOA MNAME */
-	DNS_ZONEOPT_NSEC3TESTZONE = 1 << 22, /*%< nsec3-test-zone */
-	DNS_ZONEOPT_LOGREPORTS = 1 << 23,    /* Log error-reporting queries */
-	DNS_ZONEOPT_DNSKEYKSKONLY = 1 << 24, /*%< dnssec-dnskey-kskonly */
-	DNS_ZONEOPT_CHECKDUPRR = 1 << 25,    /*%< check-dup-records */
-	DNS_ZONEOPT_CHECKDUPRRFAIL = 1 << 26, /*%< fatal check-dup-records
+	DNS_ZONEOPT_NOTIFYTOSOA = 1 << 20,   /*%< Notify the SOA MNAME */
+	DNS_ZONEOPT_NSEC3TESTZONE = 1 << 21, /*%< nsec3-test-zone */
+	DNS_ZONEOPT_LOGREPORTS = 1 << 22,    /* Log error-reporting queries */
+	DNS_ZONEOPT_DNSKEYKSKONLY = 1 << 23, /*%< dnssec-dnskey-kskonly */
+	DNS_ZONEOPT_CHECKDUPRR = 1 << 24,    /*%< check-dup-records */
+	DNS_ZONEOPT_CHECKDUPRRFAIL = 1 << 25, /*%< fatal check-dup-records
 					       * failures */
-	DNS_ZONEOPT_CHECKSPF = 1 << 27,	      /*%< check SPF records */
-	DNS_ZONEOPT_CHECKTTL = 1 << 28,	      /*%< check max-zone-ttl */
-	DNS_ZONEOPT_AUTOEMPTY = 1 << 29,      /*%< automatic empty zone */
-	DNS_ZONEOPT_CHECKSVCB = 1 << 30,      /*%< check SVBC records */
-	DNS_ZONEOPT_ZONEVERSION = 1U << 31,   /*%< enable zoneversion */
-	DNS_ZONEOPT_FULLSIGN = 1ULL << 32,    /*%< fully sign zone */
-	DNS_ZONEOPT_FORCEKEYMGR = 1ULL << 33, /*%< force keymgr step */
+	DNS_ZONEOPT_CHECKSPF = 1 << 26,	      /*%< check SPF records */
+	DNS_ZONEOPT_CHECKTTL = 1 << 27,	      /*%< check max-zone-ttl */
+	DNS_ZONEOPT_AUTOEMPTY = 1 << 28,      /*%< automatic empty zone */
+	DNS_ZONEOPT_CHECKSVCB = 1 << 29,      /*%< check SVBC records */
+	DNS_ZONEOPT_ZONEVERSION = 1U << 30,   /*%< enable zoneversion */
+	DNS_ZONEOPT_FULLSIGN = 1ULL << 31,    /*%< fully sign zone */
+	DNS_ZONEOPT_FORCEKEYMGR = 1ULL << 32, /*%< force keymgr step */
 	DNS_ZONEOPT___MAX = UINT64_MAX, /* trick to make the ENUM 64-bit wide */
 } dns_zoneopt_t;

diff --git a/lib/dns/include/dns/zoneproperties.h b/lib/dns/include/dns/zoneproperties.h
index 41631b5527..dd92e8d12c 100644
--- a/lib/dns/include/dns/zoneproperties.h
+++ b/lib/dns/include/dns/zoneproperties.h
@@ -710,24 +710,6 @@ dns_zone_setzeronosoattl(dns_zone_t *zone, bool state);
  * Set zero-no-soa-ttl status.
  */

-void
-dns_zone_setchecknames(dns_zone_t *zone, dns_severity_t severity);
-/*%<
- * 	Set the severity of name checking when loading a zone.
- *
- * Require:
- * \li     'zone' to be a valid zone.
- */
-
-dns_severity_t
-dns_zone_getchecknames(dns_zone_t *zone);
-/*%<
- *	Return the current severity of name checking.
- *
- * Require:
- *\li	'zone' to be a valid zone.
- */
-
 void
 dns_zone_setjournalsize(dns_zone_t *zone, int32_t size);
 /*%<
diff --git a/lib/dns/zone.c b/lib/dns/zone.c
index 03dc3eeb26..e88cbca5f3 100644
--- a/lib/dns/zone.c
+++ b/lib/dns/zone.c
@@ -488,7 +488,6 @@ dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx, isc_tid_t tid) {
 		.minretry = DNS_ZONE_MINRETRY,
 		.checkdstype = dns_checkdstype_yes,
 		.zero_no_soa_ttl = true,
-		.check_names = dns_severity_ignore,
 		.idlein = DNS_DEFAULT_IDLEIN,
 		.idleout = DNS_DEFAULT_IDLEOUT,
 		.maxxfrin = MAX_XFER_TIME,
@@ -672,7 +671,6 @@ dns__zone_free(dns_zone_t *zone) {
 	dns_zone_setalsonotify(zone, NULL, NULL, NULL, NULL, 0);
 	dns_zone_setcdsendpoints(zone, NULL, NULL, NULL, NULL, 0);

-	zone->check_names = dns_severity_ignore;
 	if (zone->update_acl != NULL) {
 		dns_acl_detach(&zone->update_acl);
 	}
@@ -4186,15 +4184,15 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime,
 			dns_zone_logc(zone, DNS_LOGCATEGORY_ZONELOAD,
 				      ISC_LOG_ERROR, "has %d SOA records",
 				      soacount);
-			result = DNS_R_BADZONE;
+			RETERR(DNS_R_BADZONE);
 		}
-		if (nscount == 0) {
+		if (nscount == 0 && DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKNS))
+		{
 			dns_zone_logc(zone, DNS_LOGCATEGORY_ZONELOAD,
 				      ISC_LOG_ERROR, "has no NS records");
-			result = DNS_R_BADZONE;
-		}
-		if (result != ISC_R_SUCCESS) {
-			goto cleanup;
+			if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_FATALNS)) {
+				RETERR(DNS_R_BADZONE);
+			}
 		}
 		if (zone->type == dns_zone_primary && errors != 0) {
 			CLEANUP(DNS_R_BADZONE);
@@ -4629,7 +4627,7 @@ zone_check_ns(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *version,
 	dns_name_t *foundname;
 	int level;

-	if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_NOCHECKNS)) {
+	if (!DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKNS)) {
 		return true;
 	}

@@ -15269,14 +15267,14 @@ zone_replacedb(dns_zone_t *zone, dns_db_t *db, bool dump) {
 		if (soacount != 1) {
 			dns_zone_log(zone, ISC_LOG_ERROR, "has %d SOA records",
 				     soacount);
-			result = DNS_R_BADZONE;
+			RETERR(DNS_R_BADZONE);
 		}
-		if (nscount == 0 && zone->type != dns_zone_key) {
+		if (nscount == 0 && DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKNS))
+		{
 			dns_zone_log(zone, ISC_LOG_ERROR, "has no NS records");
-			result = DNS_R_BADZONE;
-		}
-		if (result != ISC_R_SUCCESS) {
-			return result;
+			if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_FATALNS)) {
+				RETERR(DNS_R_BADZONE);
+			}
 		}
 	} else {
 		dns_zone_log(zone, ISC_LOG_ERROR,
@@ -15539,19 +15537,29 @@ again:
 				zone_unload(zone);
 				goto next_primary;
 			}
-			if (nscount == 0) {
+			if (nscount == 0 &&
+			    DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKNS))
+			{
 				dns_zone_logc(zone, DNS_LOGCATEGORY_XFER_IN,
 					      ISC_LOG_ERROR,
 					      "transferred zone "
 					      "has no NS records");
-				if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_HAVETIMERS))
+				if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_FATALNS))
 				{
-					zone->refresh = DNS_ZONE_DEFAULTREFRESH;
-					zone->retry = DNS_ZONE_DEFAULTRETRY;
+					if (DNS_ZONE_FLAG(
+						    zone,
+						    DNS_ZONEFLG_HAVETIMERS))
+					{
+						zone->refresh =
+							DNS_ZONE_DEFAULTREFRESH;
+						zone->retry =
+							DNS_ZONE_DEFAULTRETRY;
+					}
+					DNS_ZONE_CLRFLAG(
+						zone, DNS_ZONEFLG_HAVETIMERS);
+					zone_unload(zone);
+					goto next_primary;
 				}
-				DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_HAVETIMERS);
-				zone_unload(zone);
-				goto next_primary;
 			}
 			zone->refresh = RANGE(refresh, zone->minrefresh,
 					      zone->maxrefresh);
diff --git a/lib/dns/zoneproperties.c b/lib/dns/zoneproperties.c
index 279ceebe30..85793c42b6 100644
--- a/lib/dns/zoneproperties.c
+++ b/lib/dns/zoneproperties.c
@@ -1223,20 +1223,6 @@ dns_zone_setzeronosoattl(dns_zone_t *zone, bool state) {
 	zone->zero_no_soa_ttl = state;
 }

-void
-dns_zone_setchecknames(dns_zone_t *zone, dns_severity_t severity) {
-	REQUIRE(DNS_ZONE_VALID(zone));
-
-	zone->check_names = severity;
-}
-
-dns_severity_t
-dns_zone_getchecknames(dns_zone_t *zone) {
-	REQUIRE(DNS_ZONE_VALID(zone));
-
-	return zone->check_names;
-}
-
 void
 dns_zone_setjournalsize(dns_zone_t *zone, int32_t size) {
 	REQUIRE(DNS_ZONE_VALID(zone));