bind/backport-CVE-2024-1737-records.patch
2025-04-23 15:37:46 +08:00

1158 lines
42 KiB
Diff

From 2df11e5a549a71a8f792ac5207254b6a9e09859c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ond=C5=99ej=20Sur=C3=BD?= <ondrej@isc.org>
Date: Fri, 1 Mar 2024 08:26:07 +0100
Subject: [PATCH] Add a limit to the number of RRs in RRSets
Previously, the number of RRs in the RRSets were internally unlimited.
As the data structure that holds the RRs is just a linked list, and
there are places where we just walk through all of the RRs, adding an
RRSet with huge number of RRs inside would slow down processing of said
RRSets.
Add a configurable limit to cap the number of the RRs in a single RRSet.
This is enforced at the database (rbtdb, qpzone, qpcache) level and
configured with new max-records-per-type configuration option that can
be configured globally, per-view and per-zone.
(cherry picked from commit 3fbd21f69a1bcbd26c4c00920e7b0a419e8762fc)
(cherry picked from commit f63d72fb7e5813585c92d7f92bdcc5885cd04edc)
Conflict:The default value of max-records-per-type is 100, which id
adapted to 5000
Reference:https://downloads.isc.org/isc/bind9/9.18.28/patches/0002-CVE-2024-1737.patch
---
bin/named/config.c | 1 +
bin/named/server.c | 9 ++++
bin/named/zoneconf.c | 8 ++++
bin/tests/system/dyndb/driver/db.c | 3 +-
doc/arm/reference.rst | 12 +++++
doc/misc/master.zoneopt | 2 +
doc/misc/mirror.zoneopt | 2 +
doc/misc/options | 44 +++++++++++-------
doc/misc/options.active | 44 +++++++++++-------
doc/misc/redirect.zoneopt | 2 +
doc/misc/slave.zoneopt | 2 +
doc/misc/static-stub.zoneopt | 2 +
doc/misc/stub.zoneopt | 2 +
lib/dns/cache.c | 13 ++++++
lib/dns/db.c | 9 ++++
lib/dns/dnsrps.c | 3 +-
lib/dns/ecdb.c | 8 +++-
lib/dns/include/dns/cache.h | 6 +++
lib/dns/include/dns/db.h | 8 ++++
lib/dns/include/dns/rdataslab.h | 6 ++-
lib/dns/include/dns/view.h | 7 +++
lib/dns/include/dns/zone.h | 26 +++++++++++
lib/dns/rbtdb.c | 45 ++++++++++++------
lib/dns/rdataslab.c | 10 ++--
lib/dns/sdb.c | 3 +-
lib/dns/sdlz.c | 3 +-
lib/dns/view.c | 11 +++++
lib/dns/xfrin.c | 24 ++--------
lib/dns/zone.c | 74 ++++++++++++++++++++++--------
lib/isccfg/namedconf.c | 3 ++
30 files changed, 296 insertions(+), 96 deletions(-)
diff --git a/bin/named/config.c b/bin/named/config.c
index 8c6f90c..a749995 100644
--- a/bin/named/config.c
+++ b/bin/named/config.c
@@ -215,6 +215,7 @@ options {\n\
ixfr-from-differences false;\n\
max-journal-size default;\n\
max-records 0;\n\
+ max-records-per-type 5000;\n\
max-refresh-time 2419200; /* 4 weeks */\n\
max-retry-time 1209600; /* 2 weeks */\n\
max-transfer-idle-in 60;\n\
diff --git a/bin/named/server.c b/bin/named/server.c
index be6aa77..e65dab9 100644
--- a/bin/named/server.c
+++ b/bin/named/server.c
@@ -5436,6 +5436,15 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config,
dns_resolver_setclientsperquery(view->resolver, cfg_obj_asuint32(obj),
max_clients_per_query);
+ /*
+ * This is used for the cache and also as a default value
+ * for zone databases.
+ */
+ obj = NULL;
+ result = named_config_get(maps, "max-records-per-type", &obj);
+ INSIST(result == ISC_R_SUCCESS);
+ dns_view_setmaxrrperset(view, cfg_obj_asuint32(obj));
+
obj = NULL;
result = named_config_get(maps, "max-recursion-depth", &obj);
INSIST(result == ISC_R_SUCCESS);
diff --git a/bin/named/zoneconf.c b/bin/named/zoneconf.c
index 8de3a88..f4ac298 100644
--- a/bin/named/zoneconf.c
+++ b/bin/named/zoneconf.c
@@ -1072,6 +1072,14 @@ named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
dns_zone_setmaxrecords(zone, 0);
}
+ obj = NULL;
+ result = named_config_get(maps, "max-records-per-type", &obj);
+ INSIST(result == ISC_R_SUCCESS && obj != NULL);
+ dns_zone_setmaxrrperset(mayberaw, cfg_obj_asuint32(obj));
+ if (zone != mayberaw) {
+ dns_zone_setmaxrrperset(zone, 0);
+ }
+
if (raw != NULL && filename != NULL) {
#define SIGNED ".signed"
size_t signedlen = strlen(filename) + sizeof(SIGNED);
diff --git a/bin/tests/system/dyndb/driver/db.c b/bin/tests/system/dyndb/driver/db.c
index 77d335e..6725a3b 100644
--- a/bin/tests/system/dyndb/driver/db.c
+++ b/bin/tests/system/dyndb/driver/db.c
@@ -592,7 +592,8 @@ static dns_dbmethods_t sampledb_methods = {
NULL, /* setservestalerefresh */
NULL, /* getservestalerefresh */
NULL, /* setgluecachestats */
- NULL /* adjusthashsize */
+ NULL, /* adjusthashsize */
+ NULL /* setmaxrrperset */
};
/* Auxiliary driver functions. */
diff --git a/doc/arm/reference.rst b/doc/arm/reference.rst
index d4ee9d2..bf2fea7 100644
--- a/doc/arm/reference.rst
+++ b/doc/arm/reference.rst
@@ -2890,6 +2890,18 @@ system.
This sets the maximum number of records permitted in a zone. The default is
zero, which means the maximum is unlimited.
+``max-records-per-type``
+ This sets the maximum number of resource records that can be stored
+ in an RRset in a database. When configured in ``options``
+ or ``view``, it controls the cache database; it also sets
+ the default value for zone databases, which can be overridden by setting
+ it at the ``zone`` level.
+
+ If set to a positive value, any attempt to cache or to add to a zone
+ an RRset with more than the specified number of records will result in
+ a failure. If set to 0, there is no cap on RRset size. The default is
+ 100.
+
``recursive-clients``
This sets the maximum number (a "hard quota") of simultaneous recursive lookups
the server performs on behalf of clients. The default is
diff --git a/doc/misc/master.zoneopt b/doc/misc/master.zoneopt
index cc8a33b..864a852 100644
--- a/doc/misc/master.zoneopt
+++ b/doc/misc/master.zoneopt
@@ -38,8 +38,10 @@ zone <string> [ <class> ] {
max-ixfr-ratio ( unlimited | <percentage> );
max-journal-size ( default | unlimited | <sizeval> );
max-records <integer>;
+ max-records-per-type <integer>;
max-transfer-idle-out <integer>;
max-transfer-time-out <integer>;
+ max-types-per-name <integer>;
max-zone-ttl ( unlimited | <duration> );
notify ( explicit | master-only | primary-only | <boolean> );
notify-delay <integer>;
diff --git a/doc/misc/mirror.zoneopt b/doc/misc/mirror.zoneopt
index 3d45a3d..701edce 100644
--- a/doc/misc/mirror.zoneopt
+++ b/doc/misc/mirror.zoneopt
@@ -19,12 +19,14 @@ zone <string> [ <class> ] {
max-ixfr-ratio ( unlimited | <percentage> );
max-journal-size ( default | unlimited | <sizeval> );
max-records <integer>;
+ max-records-per-type <integer>;
max-refresh-time <integer>;
max-retry-time <integer>;
max-transfer-idle-in <integer>;
max-transfer-idle-out <integer>;
max-transfer-time-in <integer>;
max-transfer-time-out <integer>;
+ max-types-per-name <integer>;
min-refresh-time <integer>;
min-retry-time <integer>;
multi-master <boolean>;
diff --git a/doc/misc/options b/doc/misc/options
index 90d07f5..ee152b8 100644
--- a/doc/misc/options
+++ b/doc/misc/options
@@ -170,13 +170,16 @@ options {
dnssec-secure-to-insecure <boolean>;
dnssec-update-mode ( maintain | no-resign );
dnssec-validation ( yes | no | auto );
- dnstap { ( all | auth | client | forwarder | resolver | update ) [
- ( query | response ) ]; ... };
- dnstap-identity ( <quoted_string> | none | hostname );
- dnstap-output ( file | unix ) <quoted_string> [ size ( unlimited |
- <size> ) ] [ versions ( unlimited | <integer> ) ] [ suffix (
- increment | timestamp ) ];
- dnstap-version ( <quoted_string> | none );
+ dnstap { ( all | auth | client | forwarder |
+ resolver | update ) [ ( query | response ) ];
+ ... }; // not configured
+ dnstap-identity ( <quoted_string> | none |
+ hostname ); // not configured
+ dnstap-output ( file | unix ) <quoted_string> [
+ size ( unlimited | <size> ) ] [ versions (
+ unlimited | <integer> ) ] [ suffix ( increment
+ | timestamp ) ]; // not configured
+ dnstap-version ( <quoted_string> | none ); // not configured
dscp <integer>;
dual-stack-servers [ port <integer> ] { ( <quoted_string> [ port
<integer> ] [ dscp <integer> ] | <ipv4_address> [ port
@@ -200,13 +203,13 @@ options {
forward ( first | only );
forwarders [ port <integer> ] [ dscp <integer> ] { ( <ipv4_address>
| <ipv6_address> ) [ port <integer> ] [ dscp <integer> ]; ... };
- fstrm-set-buffer-hint <integer>;
- fstrm-set-flush-timeout <integer>;
- fstrm-set-input-queue-size <integer>;
- fstrm-set-output-notify-threshold <integer>;
- fstrm-set-output-queue-model ( mpsc | spsc );
- fstrm-set-output-queue-size <integer>;
- fstrm-set-reopen-interval <duration>;
+ fstrm-set-buffer-hint <integer>; // not configured
+ fstrm-set-flush-timeout <integer>; // not configured
+ fstrm-set-input-queue-size <integer>; // not configured
+ fstrm-set-output-notify-threshold <integer>; // not configured
+ fstrm-set-output-queue-model ( mpsc | spsc ); // not configured
+ fstrm-set-output-queue-size <integer>; // not configured
+ fstrm-set-reopen-interval <duration>; // not configured
geoip-directory ( <quoted_string> | none );
geoip-use-ecs <boolean>; // obsolete
glue-cache <boolean>;
@@ -243,6 +246,7 @@ options {
max-journal-size ( default | unlimited | <sizeval> );
max-ncache-ttl <duration>;
max-records <integer>;
+ max-records-per-type <integer>;
max-recursion-depth <integer>;
max-recursion-queries <integer>;
max-refresh-time <integer>;
@@ -253,6 +257,7 @@ options {
max-transfer-idle-out <integer>;
max-transfer-time-in <integer>;
max-transfer-time-out <integer>;
+ max-types-per-name <integer>;
max-udp-size <integer>;
max-zone-ttl ( unlimited | <duration> );
memstatistics <boolean>;
@@ -569,8 +574,9 @@ view <string> [ <class> ] {
dnssec-secure-to-insecure <boolean>;
dnssec-update-mode ( maintain | no-resign );
dnssec-validation ( yes | no | auto );
- dnstap { ( all | auth | client | forwarder | resolver | update ) [
- ( query | response ) ]; ... };
+ dnstap { ( all | auth | client | forwarder |
+ resolver | update ) [ ( query | response ) ];
+ ... }; // not configured
dual-stack-servers [ port <integer> ] { ( <quoted_string> [ port
<integer> ] [ dscp <integer> ] | <ipv4_address> [ port
<integer> ] [ dscp <integer> ] | <ipv6_address> [ port
@@ -622,6 +628,7 @@ view <string> [ <class> ] {
max-journal-size ( default | unlimited | <sizeval> );
max-ncache-ttl <duration>;
max-records <integer>;
+ max-records-per-type <integer>;
max-recursion-depth <integer>;
max-recursion-queries <integer>;
max-refresh-time <integer>;
@@ -631,6 +638,7 @@ view <string> [ <class> ] {
max-transfer-idle-out <integer>;
max-transfer-time-in <integer>;
max-transfer-time-out <integer>;
+ max-types-per-name <integer>;
max-udp-size <integer>;
max-zone-ttl ( unlimited | <duration> );
message-compression <boolean>;
@@ -854,12 +862,14 @@ view <string> [ <class> ] {
max-ixfr-ratio ( unlimited | <percentage> );
max-journal-size ( default | unlimited | <sizeval> );
max-records <integer>;
+ max-records-per-type <integer>;
max-refresh-time <integer>;
max-retry-time <integer>;
max-transfer-idle-in <integer>;
max-transfer-idle-out <integer>;
max-transfer-time-in <integer>;
max-transfer-time-out <integer>;
+ max-types-per-name <integer>;
max-zone-ttl ( unlimited | <duration> );
min-refresh-time <integer>;
min-retry-time <integer>;
@@ -971,12 +981,14 @@ zone <string> [ <class> ] {
max-ixfr-ratio ( unlimited | <percentage> );
max-journal-size ( default | unlimited | <sizeval> );
max-records <integer>;
+ max-records-per-type <integer>;
max-refresh-time <integer>;
max-retry-time <integer>;
max-transfer-idle-in <integer>;
max-transfer-idle-out <integer>;
max-transfer-time-in <integer>;
max-transfer-time-out <integer>;
+ max-types-per-name <integer>;
max-zone-ttl ( unlimited | <duration> );
min-refresh-time <integer>;
min-retry-time <integer>;
diff --git a/doc/misc/options.active b/doc/misc/options.active
index 0229d8d..ad4e29a 100644
--- a/doc/misc/options.active
+++ b/doc/misc/options.active
@@ -156,13 +156,16 @@ options {
dnssec-secure-to-insecure <boolean>;
dnssec-update-mode ( maintain | no-resign );
dnssec-validation ( yes | no | auto );
- dnstap { ( all | auth | client | forwarder | resolver | update ) [
- ( query | response ) ]; ... };
- dnstap-identity ( <quoted_string> | none | hostname );
- dnstap-output ( file | unix ) <quoted_string> [ size ( unlimited |
- <size> ) ] [ versions ( unlimited | <integer> ) ] [ suffix (
- increment | timestamp ) ];
- dnstap-version ( <quoted_string> | none );
+ dnstap { ( all | auth | client | forwarder |
+ resolver | update ) [ ( query | response ) ];
+ ... }; // not configured
+ dnstap-identity ( <quoted_string> | none |
+ hostname ); // not configured
+ dnstap-output ( file | unix ) <quoted_string> [
+ size ( unlimited | <size> ) ] [ versions (
+ unlimited | <integer> ) ] [ suffix ( increment
+ | timestamp ) ]; // not configured
+ dnstap-version ( <quoted_string> | none ); // not configured
dscp <integer>;
dual-stack-servers [ port <integer> ] { ( <quoted_string> [ port
<integer> ] [ dscp <integer> ] | <ipv4_address> [ port
@@ -181,13 +184,13 @@ options {
forward ( first | only );
forwarders [ port <integer> ] [ dscp <integer> ] { ( <ipv4_address>
| <ipv6_address> ) [ port <integer> ] [ dscp <integer> ]; ... };
- fstrm-set-buffer-hint <integer>;
- fstrm-set-flush-timeout <integer>;
- fstrm-set-input-queue-size <integer>;
- fstrm-set-output-notify-threshold <integer>;
- fstrm-set-output-queue-model ( mpsc | spsc );
- fstrm-set-output-queue-size <integer>;
- fstrm-set-reopen-interval <duration>;
+ fstrm-set-buffer-hint <integer>; // not configured
+ fstrm-set-flush-timeout <integer>; // not configured
+ fstrm-set-input-queue-size <integer>; // not configured
+ fstrm-set-output-notify-threshold <integer>; // not configured
+ fstrm-set-output-queue-model ( mpsc | spsc ); // not configured
+ fstrm-set-output-queue-size <integer>; // not configured
+ fstrm-set-reopen-interval <duration>; // not configured
geoip-directory ( <quoted_string> | none );
glue-cache <boolean>;
heartbeat-interval <integer>;
@@ -217,6 +220,7 @@ options {
max-journal-size ( default | unlimited | <sizeval> );
max-ncache-ttl <duration>;
max-records <integer>;
+ max-records-per-type <integer>;
max-recursion-depth <integer>;
max-recursion-queries <integer>;
max-refresh-time <integer>;
@@ -227,6 +231,7 @@ options {
max-transfer-idle-out <integer>;
max-transfer-time-in <integer>;
max-transfer-time-out <integer>;
+ max-types-per-name <integer>;
max-udp-size <integer>;
max-zone-ttl ( unlimited | <duration> );
memstatistics <boolean>;
@@ -513,8 +518,9 @@ view <string> [ <class> ] {
dnssec-secure-to-insecure <boolean>;
dnssec-update-mode ( maintain | no-resign );
dnssec-validation ( yes | no | auto );
- dnstap { ( all | auth | client | forwarder | resolver | update ) [
- ( query | response ) ]; ... };
+ dnstap { ( all | auth | client | forwarder |
+ resolver | update ) [ ( query | response ) ];
+ ... }; // not configured
dual-stack-servers [ port <integer> ] { ( <quoted_string> [ port
<integer> ] [ dscp <integer> ] | <ipv4_address> [ port
<integer> ] [ dscp <integer> ] | <ipv6_address> [ port
@@ -559,6 +565,7 @@ view <string> [ <class> ] {
max-journal-size ( default | unlimited | <sizeval> );
max-ncache-ttl <duration>;
max-records <integer>;
+ max-records-per-type <integer>;
max-recursion-depth <integer>;
max-recursion-queries <integer>;
max-refresh-time <integer>;
@@ -568,6 +575,7 @@ view <string> [ <class> ] {
max-transfer-idle-out <integer>;
max-transfer-time-in <integer>;
max-transfer-time-out <integer>;
+ max-types-per-name <integer>;
max-udp-size <integer>;
max-zone-ttl ( unlimited | <duration> );
message-compression <boolean>;
@@ -774,12 +782,14 @@ view <string> [ <class> ] {
max-ixfr-ratio ( unlimited | <percentage> );
max-journal-size ( default | unlimited | <sizeval> );
max-records <integer>;
+ max-records-per-type <integer>;
max-refresh-time <integer>;
max-retry-time <integer>;
max-transfer-idle-in <integer>;
max-transfer-idle-out <integer>;
max-transfer-time-in <integer>;
max-transfer-time-out <integer>;
+ max-types-per-name <integer>;
max-zone-ttl ( unlimited | <duration> );
min-refresh-time <integer>;
min-retry-time <integer>;
@@ -884,12 +894,14 @@ zone <string> [ <class> ] {
max-ixfr-ratio ( unlimited | <percentage> );
max-journal-size ( default | unlimited | <sizeval> );
max-records <integer>;
+ max-records-per-type <integer>;
max-refresh-time <integer>;
max-retry-time <integer>;
max-transfer-idle-in <integer>;
max-transfer-idle-out <integer>;
max-transfer-time-in <integer>;
max-transfer-time-out <integer>;
+ max-types-per-name <integer>;
max-zone-ttl ( unlimited | <duration> );
min-refresh-time <integer>;
min-retry-time <integer>;
diff --git a/doc/misc/redirect.zoneopt b/doc/misc/redirect.zoneopt
index 6a5ef66..c4ab59d 100644
--- a/doc/misc/redirect.zoneopt
+++ b/doc/misc/redirect.zoneopt
@@ -8,6 +8,8 @@ zone <string> [ <class> ] {
masterfile-style ( full | relative );
masters [ port <integer> ] [ dscp <integer> ] { ( <remote-servers> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ]; ... };
max-records <integer>;
+ max-records-per-type <integer>;
+ max-types-per-name <integer>;
max-zone-ttl ( unlimited | <duration> );
primaries [ port <integer> ] [ dscp <integer> ] { ( <remote-servers> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ]; ... };
zone-statistics ( full | terse | none | <boolean> );
diff --git a/doc/misc/slave.zoneopt b/doc/misc/slave.zoneopt
index 8cb7c31..ccd88e5 100644
--- a/doc/misc/slave.zoneopt
+++ b/doc/misc/slave.zoneopt
@@ -31,12 +31,14 @@ zone <string> [ <class> ] {
max-ixfr-ratio ( unlimited | <percentage> );
max-journal-size ( default | unlimited | <sizeval> );
max-records <integer>;
+ max-records-per-type <integer>;
max-refresh-time <integer>;
max-retry-time <integer>;
max-transfer-idle-in <integer>;
max-transfer-idle-out <integer>;
max-transfer-time-in <integer>;
max-transfer-time-out <integer>;
+ max-types-per-name <integer>;
min-refresh-time <integer>;
min-retry-time <integer>;
multi-master <boolean>;
diff --git a/doc/misc/static-stub.zoneopt b/doc/misc/static-stub.zoneopt
index f89d462..102b980 100644
--- a/doc/misc/static-stub.zoneopt
+++ b/doc/misc/static-stub.zoneopt
@@ -5,6 +5,8 @@ zone <string> [ <class> ] {
forward ( first | only );
forwarders [ port <integer> ] [ dscp <integer> ] { ( <ipv4_address> | <ipv6_address> ) [ port <integer> ] [ dscp <integer> ]; ... };
max-records <integer>;
+ max-records-per-type <integer>;
+ max-types-per-name <integer>;
server-addresses { ( <ipv4_address> | <ipv6_address> ); ... };
server-names { <string>; ... };
zone-statistics ( full | terse | none | <boolean> );
diff --git a/doc/misc/stub.zoneopt b/doc/misc/stub.zoneopt
index 2db604d..ca4bf1c 100644
--- a/doc/misc/stub.zoneopt
+++ b/doc/misc/stub.zoneopt
@@ -13,10 +13,12 @@ zone <string> [ <class> ] {
masterfile-style ( full | relative );
masters [ port <integer> ] [ dscp <integer> ] { ( <remote-servers> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ]; ... };
max-records <integer>;
+ max-records-per-type <integer>;
max-refresh-time <integer>;
max-retry-time <integer>;
max-transfer-idle-in <integer>;
max-transfer-time-in <integer>;
+ max-types-per-name <integer>;
min-refresh-time <integer>;
min-retry-time <integer>;
multi-master <boolean>;
diff --git a/lib/dns/cache.c b/lib/dns/cache.c
index ae173b8..9f0412d 100644
--- a/lib/dns/cache.c
+++ b/lib/dns/cache.c
@@ -148,6 +148,8 @@ struct dns_cache {
/* Locked by 'filelock'. */
char *filename;
/* Access to the on-disk cache file is also locked by 'filelock'. */
+
+ uint32_t maxrrperset;
};
/***
@@ -175,6 +177,7 @@ cache_create_db(dns_cache_t *cache, dns_db_t **db) {
cache->db_argv, db);
if (result == ISC_R_SUCCESS) {
dns_db_setservestalettl(*db, cache->serve_stale_ttl);
+ dns_db_setmaxrrperset(*db, cache->maxrrperset);
}
return (result);
}
@@ -1277,6 +1280,16 @@ dns_cache_updatestats(dns_cache_t *cache, isc_result_t result) {
}
}
+void
+dns_cache_setmaxrrperset(dns_cache_t *cache, uint32_t value) {
+ REQUIRE(VALID_CACHE(cache));
+
+ cache->maxrrperset = value;
+ if (cache->db != NULL) {
+ dns_db_setmaxrrperset(cache->db, value);
+ }
+}
+
/*
* XXX: Much of the following code has been copied in from statschannel.c.
* We should refactor this into a generic function in stats.c that can be
diff --git a/lib/dns/db.c b/lib/dns/db.c
index 89110f1..0b3503a 100644
--- a/lib/dns/db.c
+++ b/lib/dns/db.c
@@ -1132,3 +1132,12 @@ dns_db_setgluecachestats(dns_db_t *db, isc_stats_t *stats) {
return (ISC_R_NOTIMPLEMENTED);
}
+
+void
+dns_db_setmaxrrperset(dns_db_t *db, uint32_t value) {
+ REQUIRE(DNS_DB_VALID(db));
+
+ if (db->methods->setmaxrrperset != NULL) {
+ (db->methods->setmaxrrperset)(db, value);
+ }
+}
diff --git a/lib/dns/dnsrps.c b/lib/dns/dnsrps.c
index 0f2ffb5..539090d 100644
--- a/lib/dns/dnsrps.c
+++ b/lib/dns/dnsrps.c
@@ -970,7 +970,8 @@ static dns_dbmethods_t rpsdb_db_methods = {
NULL, /* setservestalerefresh */
NULL, /* getservestalerefresh */
NULL, /* setgluecachestats */
- NULL /* adjusthashsize */
+ NULL, /* adjusthashsize */
+ NULL /* setmaxrrperset */
};
static dns_rdatasetmethods_t rpsdb_rdataset_methods = {
diff --git a/lib/dns/ecdb.c b/lib/dns/ecdb.c
index 1d93433..bab5da5 100644
--- a/lib/dns/ecdb.c
+++ b/lib/dns/ecdb.c
@@ -426,7 +426,7 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
}
result = dns_rdataslab_fromrdataset(rdataset, mctx, &r,
- sizeof(rdatasetheader_t));
+ sizeof(rdatasetheader_t), 0);
if (result != ISC_R_SUCCESS) {
goto unlock;
}
@@ -556,7 +556,11 @@ static dns_dbmethods_t ecdb_methods = {
NULL, /* getsize */
NULL, /* setservestalettl */
NULL, /* getservestalettl */
- NULL /* setgluecachestats */
+ NULL, /* setservestalerefresh */
+ NULL, /* getservestalerefresh */
+ NULL, /* setgluecachestats */
+ NULL, /* adjusthashsize */
+ NULL /* setmaxrrperset */
};
static isc_result_t
diff --git a/lib/dns/include/dns/cache.h b/lib/dns/include/dns/cache.h
index 22e94da..3fa2a89 100644
--- a/lib/dns/include/dns/cache.h
+++ b/lib/dns/include/dns/cache.h
@@ -337,6 +337,12 @@ dns_cache_updatestats(dns_cache_t *cache, isc_result_t result);
* Update cache statistics based on result code in 'result'
*/
+void
+dns_cache_setmaxrrperset(dns_cache_t *cache, uint32_t value);
+/*%<
+ * Set the maximum resource records per RRSet that can be cached.
+ */
+
#ifdef HAVE_LIBXML2
int
dns_cache_renderxml(dns_cache_t *cache, void *writer0);
diff --git a/lib/dns/include/dns/db.h b/lib/dns/include/dns/db.h
index 54ece83..881d4cf 100644
--- a/lib/dns/include/dns/db.h
+++ b/lib/dns/include/dns/db.h
@@ -182,6 +182,7 @@ typedef struct dns_dbmethods {
isc_result_t (*getservestalerefresh)(dns_db_t *db, uint32_t *interval);
isc_result_t (*setgluecachestats)(dns_db_t *db, isc_stats_t *stats);
isc_result_t (*adjusthashsize)(dns_db_t *db, size_t size);
+ void (*setmaxrrperset)(dns_db_t *db, uint32_t value);
} dns_dbmethods_t;
typedef isc_result_t (*dns_dbcreatefunc_t)(isc_mem_t *mctx,
@@ -1783,6 +1784,13 @@ dns_db_setgluecachestats(dns_db_t *db, isc_stats_t *stats);
* dns_rdatasetstats_create(); otherwise NULL.
*/
+void
+dns_db_setmaxrrperset(dns_db_t *db, uint32_t value);
+/*%<
+ * Set the maximum permissible number of RRs per RRset. If 'value'
+ * is nonzero, then any subsequent attempt to add an rdataset with
+ * more than 'value' RRs will return ISC_R_NOSPACE.
+ */
ISC_LANG_ENDDECLS
#endif /* DNS_DB_H */
diff --git a/lib/dns/include/dns/rdataslab.h b/lib/dns/include/dns/rdataslab.h
index 5a22f09..f2f3513 100644
--- a/lib/dns/include/dns/rdataslab.h
+++ b/lib/dns/include/dns/rdataslab.h
@@ -65,7 +65,8 @@ ISC_LANG_BEGINDECLS
isc_result_t
dns_rdataslab_fromrdataset(dns_rdataset_t *rdataset, isc_mem_t *mctx,
- isc_region_t *region, unsigned int reservelen);
+ isc_region_t *region, unsigned int reservelen,
+ uint32_t limit);
/*%<
* Slabify a rdataset. The slab area will be allocated and returned
* in 'region'.
@@ -121,7 +122,8 @@ isc_result_t
dns_rdataslab_merge(unsigned char *oslab, unsigned char *nslab,
unsigned int reservelen, isc_mem_t *mctx,
dns_rdataclass_t rdclass, dns_rdatatype_t type,
- unsigned int flags, unsigned char **tslabp);
+ unsigned int flags, uint32_t maxrrperset,
+ unsigned char **tslabp);
/*%<
* Merge 'oslab' and 'nslab'.
*/
diff --git a/lib/dns/include/dns/view.h b/lib/dns/include/dns/view.h
index 2cf7ece..0d502f4 100644
--- a/lib/dns/include/dns/view.h
+++ b/lib/dns/include/dns/view.h
@@ -186,6 +186,7 @@ struct dns_view {
dns_dlzdblist_t dlz_unsearched;
uint32_t fail_ttl;
dns_badcache_t *failcache;
+ uint32_t maxrrperset;
/*
* Configurable data for server use only,
@@ -1339,6 +1340,12 @@ dns_view_staleanswerenabled(dns_view_t *view);
*\li 'view' to be valid.
*/
+void
+dns_view_setmaxrrperset(dns_view_t *view, uint32_t value);
+/*%<
+ * Set the maximum resource records per RRSet that can be cached.
+ */
+
ISC_LANG_ENDDECLS
#endif /* DNS_VIEW_H */
diff --git a/lib/dns/include/dns/zone.h b/lib/dns/include/dns/zone.h
index 78f5694..c4b7577 100644
--- a/lib/dns/include/dns/zone.h
+++ b/lib/dns/include/dns/zone.h
@@ -162,6 +162,19 @@ dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx);
*\li #ISC_R_UNEXPECTED
*/
+isc_result_t
+dns_zone_makedb(dns_zone_t *zone, dns_db_t **dbp);
+/*%<
+ * Creates a new empty database for the 'zone'.
+ *
+ * Requires:
+ *\li 'zone' to be a valid zone.
+ *\li 'dbp' to point to NULL pointer.
+ *
+ * Returns:
+ *\li dns_db_create() error codes.
+ */
+
void
dns_zone_setclass(dns_zone_t *zone, dns_rdataclass_t rdclass);
/*%<
@@ -330,6 +343,19 @@ dns_zone_getmaxrecords(dns_zone_t *zone);
*\li uint32_t maxrecords.
*/
+void
+dns_zone_setmaxrrperset(dns_zone_t *zone, uint32_t maxrrperset);
+/*%<
+ * Sets the maximum number of records per rrset permitted in a zone.
+ * 0 implies unlimited.
+ *
+ * Requires:
+ *\li 'zone' to be valid initialised zone.
+ *
+ * Returns:
+ *\li void
+ */
+
void
dns_zone_setmaxttl(dns_zone_t *zone, uint32_t maxttl);
/*%<
diff --git a/lib/dns/rbtdb.c b/lib/dns/rbtdb.c
index e20aef7..f27f970 100644
--- a/lib/dns/rbtdb.c
+++ b/lib/dns/rbtdb.c
@@ -482,6 +482,7 @@ struct dns_rbtdb {
rbtdb_serial_t current_serial;
rbtdb_serial_t least_serial;
rbtdb_serial_t next_serial;
+ uint32_t maxrrperset;
rbtdb_version_t *current_version;
rbtdb_version_t *future_version;
rbtdb_versionlist_t open_versions;
@@ -6488,7 +6489,7 @@ find_header:
rbtdb->common.mctx,
rbtdb->common.rdclass,
(dns_rdatatype_t)header->type, flags,
- &merged);
+ rbtdb->maxrrperset, &merged);
}
if (result == ISC_R_SUCCESS) {
/*
@@ -6873,7 +6874,7 @@ delegating_type(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node,
static inline isc_result_t
addnoqname(dns_rbtdb_t *rbtdb, rdatasetheader_t *newheader,
- dns_rdataset_t *rdataset) {
+ uint32_t maxrrperset, dns_rdataset_t *rdataset) {
struct noqname *noqname;
isc_mem_t *mctx = rbtdb->common.mctx;
dns_name_t name;
@@ -6894,12 +6895,12 @@ addnoqname(dns_rbtdb_t *rbtdb, rdatasetheader_t *newheader,
noqname->negsig = NULL;
noqname->type = neg.type;
dns_name_dup(&name, mctx, &noqname->name);
- result = dns_rdataslab_fromrdataset(&neg, mctx, &r, 0);
+ result = dns_rdataslab_fromrdataset(&neg, mctx, &r, 0, maxrrperset);
if (result != ISC_R_SUCCESS) {
goto cleanup;
}
noqname->neg = r.base;
- result = dns_rdataslab_fromrdataset(&negsig, mctx, &r, 0);
+ result = dns_rdataslab_fromrdataset(&negsig, mctx, &r, 0, maxrrperset);
if (result != ISC_R_SUCCESS) {
goto cleanup;
}
@@ -6918,7 +6919,7 @@ cleanup:
static inline isc_result_t
addclosest(dns_rbtdb_t *rbtdb, rdatasetheader_t *newheader,
- dns_rdataset_t *rdataset) {
+ uint32_t maxrrperset, dns_rdataset_t *rdataset) {
struct noqname *closest;
isc_mem_t *mctx = rbtdb->common.mctx;
dns_name_t name;
@@ -6939,12 +6940,12 @@ addclosest(dns_rbtdb_t *rbtdb, rdatasetheader_t *newheader,
closest->negsig = NULL;
closest->type = neg.type;
dns_name_dup(&name, mctx, &closest->name);
- result = dns_rdataslab_fromrdataset(&neg, mctx, &r, 0);
+ result = dns_rdataslab_fromrdataset(&neg, mctx, &r, 0, maxrrperset);
if (result != ISC_R_SUCCESS) {
goto cleanup;
}
closest->neg = r.base;
- result = dns_rdataslab_fromrdataset(&negsig, mctx, &r, 0);
+ result = dns_rdataslab_fromrdataset(&negsig, mctx, &r, 0, maxrrperset);
if (result != ISC_R_SUCCESS) {
goto cleanup;
}
@@ -7021,7 +7022,8 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
}
result = dns_rdataslab_fromrdataset(rdataset, rbtdb->common.mctx,
- &region, sizeof(rdatasetheader_t));
+ &region, sizeof(rdatasetheader_t),
+ rbtdb->maxrrperset);
if (result != ISC_R_SUCCESS) {
return (result);
}
@@ -7079,7 +7081,8 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
RDATASET_ATTR_SET(newheader, RDATASET_ATTR_OPTOUT);
}
if ((rdataset->attributes & DNS_RDATASETATTR_NOQNAME) != 0) {
- result = addnoqname(rbtdb, newheader, rdataset);
+ result = addnoqname(rbtdb, newheader,
+ rbtdb->maxrrperset, rdataset);
if (result != ISC_R_SUCCESS) {
free_rdataset(rbtdb, rbtdb->common.mctx,
newheader);
@@ -7087,7 +7090,8 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
}
}
if ((rdataset->attributes & DNS_RDATASETATTR_CLOSEST) != 0) {
- result = addclosest(rbtdb, newheader, rdataset);
+ result = addclosest(rbtdb, newheader,
+ rbtdb->maxrrperset, rdataset);
if (result != ISC_R_SUCCESS) {
free_rdataset(rbtdb, rbtdb->common.mctx,
newheader);
@@ -7254,7 +7258,8 @@ subtractrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
nodefullname(db, node, nodename);
result = dns_rdataslab_fromrdataset(rdataset, rbtdb->common.mctx,
- &region, sizeof(rdatasetheader_t));
+ &region, sizeof(rdatasetheader_t),
+ 0);
if (result != ISC_R_SUCCESS) {
return (result);
}
@@ -7662,7 +7667,8 @@ loading_addrdataset(void *arg, const dns_name_t *name,
}
result = dns_rdataslab_fromrdataset(rdataset, rbtdb->common.mctx,
- &region, sizeof(rdatasetheader_t));
+ &region, sizeof(rdatasetheader_t),
+ rbtdb->maxrrperset);
if (result != ISC_R_SUCCESS) {
return (result);
}
@@ -8601,6 +8607,15 @@ setgluecachestats(dns_db_t *db, isc_stats_t *stats) {
return (ISC_R_SUCCESS);
}
+static void
+setmaxrrperset(dns_db_t *db, uint32_t maxrrperset) {
+ dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
+
+ REQUIRE(VALID_RBTDB(rbtdb));
+
+ rbtdb->maxrrperset = maxrrperset;
+}
+
static dns_stats_t *
getrrsetstats(dns_db_t *db) {
dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
@@ -8724,7 +8739,8 @@ static dns_dbmethods_t zone_methods = { attach,
NULL, /* setservestalerefresh */
NULL, /* getservestalerefresh */
setgluecachestats,
- adjusthashsize };
+ adjusthashsize,
+ setmaxrrperset };
static dns_dbmethods_t cache_methods = { attach,
detach,
@@ -8776,7 +8792,8 @@ static dns_dbmethods_t cache_methods = { attach,
setservestalerefresh,
getservestalerefresh,
NULL,
- adjusthashsize };
+ adjusthashsize,
+ setmaxrrperset };
isc_result_t
dns_rbtdb_create(isc_mem_t *mctx, const dns_name_t *origin, dns_dbtype_t type,
diff --git a/lib/dns/rdataslab.c b/lib/dns/rdataslab.c
index dda9038..b2d1e1c 100644
--- a/lib/dns/rdataslab.c
+++ b/lib/dns/rdataslab.c
@@ -116,7 +116,8 @@ fillin_offsets(unsigned char *offsetbase, unsigned int *offsettable,
isc_result_t
dns_rdataslab_fromrdataset(dns_rdataset_t *rdataset, isc_mem_t *mctx,
- isc_region_t *region, unsigned int reservelen) {
+ isc_region_t *region, unsigned int reservelen,
+ uint32_t maxrrperset) {
/*
* Use &removed as a sentinel pointer for duplicate
* rdata as rdata.data == NULL is valid.
@@ -158,7 +159,7 @@ dns_rdataslab_fromrdataset(dns_rdataset_t *rdataset, isc_mem_t *mctx,
return (ISC_R_SUCCESS);
}
- if (nitems > DNS_RDATASET_MAX_RECORDS) {
+ if (maxrrperset > 0 && nitems > maxrrperset) {
return (DNS_R_TOOMANYRECORDS);
}
@@ -488,7 +489,8 @@ isc_result_t
dns_rdataslab_merge(unsigned char *oslab, unsigned char *nslab,
unsigned int reservelen, isc_mem_t *mctx,
dns_rdataclass_t rdclass, dns_rdatatype_t type,
- unsigned int flags, unsigned char **tslabp) {
+ unsigned int flags, uint32_t maxrrperset,
+ unsigned char **tslabp) {
unsigned char *ocurrent, *ostart, *ncurrent, *tstart, *tcurrent, *data;
unsigned int ocount, ncount, count, olength, tlength, tcount, length;
dns_rdata_t ordata = DNS_RDATA_INIT;
@@ -528,7 +530,7 @@ dns_rdataslab_merge(unsigned char *oslab, unsigned char *nslab,
#endif /* if DNS_RDATASET_FIXED */
INSIST(ocount > 0 && ncount > 0);
- if (ocount + ncount > DNS_RDATASET_MAX_RECORDS) {
+ if (maxrrperset > 0 && ocount + ncount > maxrrperset) {
return (DNS_R_TOOMANYRECORDS);
}
diff --git a/lib/dns/sdb.c b/lib/dns/sdb.c
index d9de422..84cd324 100644
--- a/lib/dns/sdb.c
+++ b/lib/dns/sdb.c
@@ -1312,7 +1312,8 @@ static dns_dbmethods_t sdb_methods = {
NULL, /* setservestalerefresh */
NULL, /* getservestalerefresh */
NULL, /* setgluecachestats */
- NULL /* adjusthashsize */
+ NULL, /* adjusthashsize */
+ NULL /* setmaxrrperset */
};
static isc_result_t
diff --git a/lib/dns/sdlz.c b/lib/dns/sdlz.c
index 0b46fb9..f478913 100644
--- a/lib/dns/sdlz.c
+++ b/lib/dns/sdlz.c
@@ -1284,7 +1284,8 @@ static dns_dbmethods_t sdlzdb_methods = {
NULL, /* setservestalerefresh */
NULL, /* getservestalerefresh */
NULL, /* setgluecachestats */
- NULL /* adjusthashsize */
+ NULL, /* adjusthashsize */
+ NULL /* setmaxrrperset */
};
/*
diff --git a/lib/dns/view.c b/lib/dns/view.c
index 8c7e40a..90c2ac7 100644
--- a/lib/dns/view.c
+++ b/lib/dns/view.c
@@ -868,6 +868,8 @@ dns_view_setcache(dns_view_t *view, dns_cache_t *cache, bool shared) {
dns_cache_attach(cache, &view->cache);
dns_cache_attachdb(cache, &view->cachedb);
INSIST(DNS_DB_VALID(view->cachedb));
+
+ dns_cache_setmaxrrperset(view->cache, view->maxrrperset);
}
bool
@@ -2543,3 +2545,12 @@ dns_view_staleanswerenabled(dns_view_t *view) {
return (result);
}
+
+void
+dns_view_setmaxrrperset(dns_view_t *view, uint32_t value) {
+ REQUIRE(DNS_VIEW_VALID(view));
+ view->maxrrperset = value;
+ if (view->cache != NULL) {
+ dns_cache_setmaxrrperset(view->cache, value);
+ }
+}
diff --git a/lib/dns/xfrin.c b/lib/dns/xfrin.c
index a4569f5..c61e8f5 100644
--- a/lib/dns/xfrin.c
+++ b/lib/dns/xfrin.c
@@ -203,8 +203,6 @@ xfrin_create(isc_mem_t *mctx, dns_zone_t *zone, dns_db_t *db, isc_task_t *task,
static isc_result_t
axfr_init(dns_xfrin_ctx_t *xfr);
static isc_result_t
-axfr_makedb(dns_xfrin_ctx_t *xfr, dns_db_t **dbp);
-static isc_result_t
axfr_putdata(dns_xfrin_ctx_t *xfr, dns_diffop_t op, dns_name_t *name,
dns_ttl_t ttl, dns_rdata_t *rdata);
static isc_result_t
@@ -277,7 +275,11 @@ axfr_init(dns_xfrin_ctx_t *xfr) {
dns_db_detach(&xfr->db);
}
- CHECK(axfr_makedb(xfr, &xfr->db));
+ CHECK(dns_zone_makedb(xfr->zone, &xfr->db));
+
+ dns_zone_rpz_enable_db(xfr->zone, xfr->db);
+ dns_zone_catz_enable_db(xfr->zone, xfr->db);
+
dns_rdatacallbacks_init(&xfr->axfr);
CHECK(dns_db_beginload(xfr->db, &xfr->axfr));
result = ISC_R_SUCCESS;
@@ -285,22 +287,6 @@ failure:
return (result);
}
-static isc_result_t
-axfr_makedb(dns_xfrin_ctx_t *xfr, dns_db_t **dbp) {
- isc_result_t result;
-
- result = dns_db_create(xfr->mctx, /* XXX */
- "rbt", /* XXX guess */
- &xfr->name, dns_dbtype_zone, xfr->rdclass, 0,
- NULL, /* XXX guess */
- dbp);
- if (result == ISC_R_SUCCESS) {
- dns_zone_rpz_enable_db(xfr->zone, *dbp);
- dns_zone_catz_enable_db(xfr->zone, *dbp);
- }
- return (result);
-}
-
static isc_result_t
axfr_putdata(dns_xfrin_ctx_t *xfr, dns_diffop_t op, dns_name_t *name,
dns_ttl_t ttl, dns_rdata_t *rdata) {
diff --git a/lib/dns/zone.c b/lib/dns/zone.c
index 6a62de0..350f80f 100644
--- a/lib/dns/zone.c
+++ b/lib/dns/zone.c
@@ -276,6 +276,7 @@ struct dns_zone {
uint32_t minretry;
uint32_t maxrecords;
+ uint32_t maxrrperset;
isc_sockaddr_t *masters;
isc_dscp_t *masterdscps;
@@ -2292,31 +2293,13 @@ zone_load(dns_zone_t *zone, unsigned int flags, bool locked) {
dns_zone_logc(zone, DNS_LOGCATEGORY_ZONELOAD, ISC_LOG_DEBUG(1),
"starting load");
- result = dns_db_create(zone->mctx, zone->db_argv[0], &zone->origin,
- (zone->type == dns_zone_stub) ? dns_dbtype_stub
- : dns_dbtype_zone,
- zone->rdclass, zone->db_argc - 1,
- zone->db_argv + 1, &db);
-
+ result = dns_zone_makedb(zone, &db);
if (result != ISC_R_SUCCESS) {
dns_zone_logc(zone, DNS_LOGCATEGORY_ZONELOAD, ISC_LOG_ERROR,
"loading zone: creating database: %s",
isc_result_totext(result));
goto cleanup;
}
- dns_db_settask(db, zone->task);
-
- if (zone->type == dns_zone_primary ||
- zone->type == dns_zone_secondary || zone->type == dns_zone_mirror)
- {
- result = dns_db_setgluecachestats(db, zone->gluecachestats);
- if (result == ISC_R_NOTIMPLEMENTED) {
- result = ISC_R_SUCCESS;
- }
- if (result != ISC_R_SUCCESS) {
- goto cleanup;
- }
- }
if (!dns_db_ispersistent(db)) {
if (zone->masterfile != NULL) {
@@ -12211,6 +12194,16 @@ dns_zone_setmaxrecords(dns_zone_t *zone, uint32_t val) {
zone->maxrecords = val;
}
+void
+dns_zone_setmaxrrperset(dns_zone_t *zone, uint32_t val) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ zone->maxrrperset = val;
+ if (zone->db != NULL) {
+ dns_db_setmaxrrperset(zone->db, val);
+ }
+}
+
static bool
notify_isqueued(dns_zone_t *zone, unsigned int flags, dns_name_t *name,
isc_sockaddr_t *addr, dns_tsigkey_t *key) {
@@ -14615,6 +14608,7 @@ ns_query(dns_zone_t *zone, dns_rdataset_t *soardataset, dns_stub_t *stub) {
goto cleanup;
}
dns_db_settask(stub->db, zone->task);
+ dns_db_setmaxrrperset(stub->db, zone->maxrrperset);
}
result = dns_db_newversion(stub->db, &stub->version);
@@ -17351,6 +17345,7 @@ zone_replacedb(dns_zone_t *zone, dns_db_t *db, bool dump) {
}
zone_attachdb(zone, db);
dns_db_settask(zone->db, zone->task);
+ dns_db_setmaxrrperset(zone->db, zone->maxrrperset);
DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_LOADED | DNS_ZONEFLG_NEEDNOTIFY);
return (ISC_R_SUCCESS);
@@ -23513,3 +23508,44 @@ zone_nsecttl(dns_zone_t *zone) {
return (ISC_MIN(zone->minimum, zone->soattl));
}
+
+isc_result_t
+dns_zone_makedb(dns_zone_t *zone, dns_db_t **dbp) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+ REQUIRE(dbp != NULL && *dbp == NULL);
+
+ dns_db_t *db = NULL;
+
+ isc_result_t result = dns_db_create(
+ zone->mctx, zone->db_argv[0], &zone->origin,
+ (zone->type == dns_zone_stub) ? dns_dbtype_stub
+ : dns_dbtype_zone,
+ zone->rdclass, zone->db_argc - 1, zone->db_argv + 1, &db);
+ if (result != ISC_R_SUCCESS) {
+ return (result);
+ }
+
+ switch (zone->type) {
+ case dns_zone_primary:
+ case dns_zone_secondary:
+ case dns_zone_mirror:
+ result = dns_db_setgluecachestats(db, zone->gluecachestats);
+ if (result == ISC_R_NOTIMPLEMENTED) {
+ result = ISC_R_SUCCESS;
+ }
+ if (result != ISC_R_SUCCESS) {
+ dns_db_detach(&db);
+ return (result);
+ }
+ break;
+ default:
+ break;
+ }
+
+ dns_db_settask(db, zone->task);
+ dns_db_setmaxrrperset(db, zone->maxrrperset);
+
+ *dbp = db;
+
+ return (ISC_R_SUCCESS);
+}
diff --git a/lib/isccfg/namedconf.c b/lib/isccfg/namedconf.c
index aab0462..dce3053 100644
--- a/lib/isccfg/namedconf.c
+++ b/lib/isccfg/namedconf.c
@@ -2236,6 +2236,9 @@ static cfg_clausedef_t zone_clauses[] = {
{ "max-records", &cfg_type_uint32,
CFG_ZONE_PRIMARY | CFG_ZONE_SECONDARY | CFG_ZONE_MIRROR |
CFG_ZONE_STUB | CFG_ZONE_STATICSTUB | CFG_ZONE_REDIRECT },
+ { "max-records-per-type", &cfg_type_uint32,
+ CFG_ZONE_PRIMARY | CFG_ZONE_SECONDARY | CFG_ZONE_MIRROR |
+ CFG_ZONE_STUB | CFG_ZONE_STATICSTUB | CFG_ZONE_REDIRECT },
{ "max-refresh-time", &cfg_type_uint32,
CFG_ZONE_SECONDARY | CFG_ZONE_MIRROR | CFG_ZONE_STUB },
{ "max-retry-time", &cfg_type_uint32,
--
2.43.0