]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Add a limit to the number of RR types for single name
authorOndřej Surý <ondrej@isc.org>
Sat, 25 May 2024 09:46:56 +0000 (11:46 +0200)
committerNicki Křížek <nicki@isc.org>
Mon, 10 Jun 2024 16:50:06 +0000 (18:50 +0200)
Previously, the number of RR types for a single owner name was limited
only by the maximum number of the types (64k).  As the data structure
that holds the RR types for the database node is just a linked list, and
there are places where we just walk through the whole list (again and
again), adding a large number of RR types for a single owner named with
would slow down processing of such name (database node).

Add a configurable limit to cap the number of the RR types for a single
owner.  This is enforced at the database (rbtdb, qpzone, qpcache) level
and configured with new max-types-per-name configuration option that
can be configured globally, per-view and per-zone.

(cherry picked from commit 00d16211d6368b99f070c1182d8c76b3798ca1db)

25 files changed:
bin/named/config.c
bin/named/server.c
bin/named/zoneconf.c
bin/tests/system/dyndb/driver/db.c
doc/arm/reference.rst
doc/misc/mirror.zoneopt
doc/misc/options
doc/misc/primary.zoneopt
doc/misc/redirect.zoneopt
doc/misc/secondary.zoneopt
doc/misc/static-stub.zoneopt
doc/misc/stub.zoneopt
lib/dns/cache.c
lib/dns/db.c
lib/dns/dnsrps.c
lib/dns/include/dns/cache.h
lib/dns/include/dns/db.h
lib/dns/include/dns/view.h
lib/dns/include/dns/zone.h
lib/dns/rbtdb.c
lib/dns/sdb.c
lib/dns/sdlz.c
lib/dns/view.c
lib/dns/zone.c
lib/isccfg/namedconf.c

index 25f3715fc6b3ecb962d619f6aa6590cddbe50ad9..47549c54f81d3f966c12fa3718ff22dae784e51f 100644 (file)
@@ -236,6 +236,7 @@ options {\n\
        max-records-per-type 100;\n\
        max-refresh-time 2419200; /* 4 weeks */\n\
        max-retry-time 1209600; /* 2 weeks */\n\
+       max-types-per-name 100;\n\
        max-transfer-idle-in 60;\n\
        max-transfer-idle-out 60;\n\
        max-transfer-time-in 120;\n\
index 843f5566d05e6be383dddd85d00317ef3aa617c8..6ad090fd5fa8676b71acafab36f7bde9a4349e93 100644 (file)
@@ -5565,6 +5565,15 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config,
        INSIST(result == ISC_R_SUCCESS);
        dns_view_setmaxrrperset(view, cfg_obj_asuint32(obj));
 
+       /*
+        * This is used for the cache and also as a default value
+        * for zone databases.
+        */
+       obj = NULL;
+       result = named_config_get(maps, "max-types-per-name", &obj);
+       INSIST(result == ISC_R_SUCCESS);
+       dns_view_setmaxtypepername(view, cfg_obj_asuint32(obj));
+
        obj = NULL;
        result = named_config_get(maps, "max-recursion-depth", &obj);
        INSIST(result == ISC_R_SUCCESS);
index e6bf9377d649f8449c0363f35ba6723ec47a15e9..384a81e185018d5834429ed3e4f450f3a817aca1 100644 (file)
@@ -1091,6 +1091,14 @@ named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
                dns_zone_setmaxrrperset(zone, 0);
        }
 
+       obj = NULL;
+       result = named_config_get(maps, "max-types-per-name", &obj);
+       INSIST(result == ISC_R_SUCCESS && obj != NULL);
+       dns_zone_setmaxtypepername(mayberaw, cfg_obj_asuint32(obj));
+       if (zone != mayberaw) {
+               dns_zone_setmaxtypepername(zone, 0);
+       }
+
        if (raw != NULL && filename != NULL) {
 #define SIGNED ".signed"
                size_t signedlen = strlen(filename) + sizeof(SIGNED);
index 4e08edca5e948340ab3324db87411461907cf68e..d9cdfa016a9c4300bdfc533defbbffc6ef2afa9a 100644 (file)
@@ -612,7 +612,8 @@ static dns_dbmethods_t sampledb_methods = {
        NULL, /* setservestalerefresh */
        NULL, /* getservestalerefresh */
        NULL, /* setgluecachestats */
-       NULL  /* setmaxrrperset */
+       NULL, /* setmaxrrperset */
+       NULL  /* setmaxtypepername */
 };
 
 /* Auxiliary driver functions. */
index f7cde02804db1453cefc53ce46a5bedcf4b90987..2ddc368514fffeed4abb91e03e555dc4218f24a9 100644 (file)
@@ -3781,6 +3781,21 @@ system.
    a failure.  If set to 0, there is no cap on RRset size.  The default is
    100.
 
+.. namedconf:statement:: max-types-per-name
+   :tags: server
+   :short: Sets the maximum number of RR types that can be stored for an owner name
+
+   This sets the maximum number of resource record types that can be stored
+   for a single owner name in a database. When configured in :namedconf:ref:`options`
+   or :namedconf:ref:`view`, it controls the cache database, and also sets
+   the default value for zone databases, which can be overridden by setting
+   it at the :namedconf:ref:`zone` level
+
+   If set to a positive value, any attempt to cache or to add to a zone an owner
+   name with more than the specified number of resource record types will result
+   in a failure.  If set to 0, there is no cap on RR types number.  The default is
+   100.
+
 .. namedconf:statement:: recursive-clients
    :tags: query
    :short: Specifies the maximum number of concurrent recursive queries the server can perform.
index 8d4a687ee8f223b464678479d01822c5b874f6ad..5f688ca3547d90595963c16d8e52b8e8f9441539 100644 (file)
@@ -25,6 +25,7 @@ zone <string> [ <class> ] {
        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>;
index 4fd272224c40ac98b6aaf10d7443e1f7c48126c8..a8cd16425c2ad79e703ff2e4ddd2099cfc855928 100644 (file)
@@ -192,6 +192,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>;
@@ -482,6 +483,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>;
index e8ef80cf6eabbd46cbcddd3cfca95598dea4b9b5..1de2f217d4ea952aaba4e3e4fcbf2140f8e15dc5 100644 (file)
@@ -41,6 +41,7 @@ zone <string> [ <class> ] {
        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>;
index 613dbdb890ea13e6ca1f397dc458a551672decb7..9d238c1a3e82e56745d47f40031361857780837c 100644 (file)
@@ -8,6 +8,7 @@ zone <string> [ <class> ] {
        masterfile-style ( full | relative );
        max-records <integer>;
        max-records-per-type <integer>;
+       max-types-per-name <integer>;
        max-zone-ttl ( unlimited | <duration> );
        primaries [ port <integer> ]  { ( <remote-servers> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... };
        zone-statistics ( full | terse | none | <boolean> );
index fc1c8526db51b53a90ae82cd51c6e5fc87bde4b8..169fa9bbb0364ef12c1df8a3de9679131cac69a1 100644 (file)
@@ -37,6 +37,7 @@ zone <string> [ <class> ] {
        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>;
index 706fa3cc88e7342b86d6e72337a73113ab40bcf0..93a3220017657a9b856aa3c87a335d97529b63b4 100644 (file)
@@ -6,6 +6,7 @@ zone <string> [ <class> ] {
        forwarders [ port <integer> ]  { ( <ipv4_address> | <ipv6_address> ) [ port <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> );
index c1c5d68566a3ea730204fa6102047933c6833de9..28346826e4fa2caa27ee020686b71a85236c3ea7 100644 (file)
@@ -17,6 +17,7 @@ zone <string> [ <class> ] {
        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>;
index 0669f4a9f6359559f10943e0eac5b07019107fcf..8fdc14290cc1c0c6695b4bfa01dd9f232fee96e3 100644 (file)
@@ -147,6 +147,7 @@ struct dns_cache {
        dns_ttl_t serve_stale_refresh;
        isc_stats_t *stats;
        uint32_t maxrrperset;
+       uint32_t maxtypepername;
 };
 
 /***
@@ -212,6 +213,7 @@ cache_create_db(dns_cache_t *cache, dns_db_t **dbp, isc_mem_t **tmctxp,
        dns_db_setservestalettl(db, cache->serve_stale_ttl);
        dns_db_setservestalerefresh(db, cache->serve_stale_refresh);
        dns_db_setmaxrrperset(db, cache->maxrrperset);
+       dns_db_setmaxtypepername(db, cache->maxtypepername);
 
        if (cache->taskmgr == NULL) {
                *dbp = db;
@@ -1251,6 +1253,16 @@ dns_cache_setmaxrrperset(dns_cache_t *cache, uint32_t value) {
        }
 }
 
+void
+dns_cache_setmaxtypepername(dns_cache_t *cache, uint32_t value) {
+       REQUIRE(VALID_CACHE(cache));
+
+       cache->maxtypepername = value;
+       if (cache->db != NULL) {
+               dns_db_setmaxtypepername(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
index 09bf9394b5b3faf61712f1aa86d3958b263d6efd..315b97dbd3b6c0f1863b89f9a6d2986639675448 100644 (file)
@@ -1130,3 +1130,12 @@ dns_db_setmaxrrperset(dns_db_t *db, uint32_t value) {
                (db->methods->setmaxrrperset)(db, value);
        }
 }
+
+void
+dns_db_setmaxtypepername(dns_db_t *db, uint32_t value) {
+       REQUIRE(DNS_DB_VALID(db));
+
+       if (db->methods->setmaxtypepername != NULL) {
+               (db->methods->setmaxtypepername)(db, value);
+       }
+}
index a8a6f9c6a3dad550c43f58f188e3bf69fc5f2f9a..73f11daacbd216e4ba8474299706debd43044a9f 100644 (file)
@@ -975,7 +975,8 @@ static dns_dbmethods_t rpsdb_db_methods = {
        NULL, /* setservestalerefresh */
        NULL, /* getservestalerefresh */
        NULL, /* setgluecachestats */
-       NULL  /* setmaxrrperset */
+       NULL, /* setmaxrrperset */
+       NULL  /* setmaxtypepername */
 };
 
 static dns_rdatasetmethods_t rpsdb_rdataset_methods = {
index 10911109265f41b00f65a2f79a50d67a1c4774ce..9f4a57fadbfec94b1e8801a30729e63673af527f 100644 (file)
@@ -286,6 +286,12 @@ dns_cache_setmaxrrperset(dns_cache_t *cache, uint32_t value);
  * Set the maximum resource records per RRSet that can be cached.
  */
 
+void
+dns_cache_setmaxtypepername(dns_cache_t *cache, uint32_t value);
+/*%<
+ * Set the maximum resource record types per owner name that can be cached.
+ */
+
 #ifdef HAVE_LIBXML2
 int
 dns_cache_renderxml(dns_cache_t *cache, void *writer0);
index 4157ae4ed989b17a4532529a46e798369985eb80..07ff9a43d5c20ce688ce46468bb1ce03e3ed5660 100644 (file)
@@ -186,6 +186,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);
        void (*setmaxrrperset)(dns_db_t *db, uint32_t value);
+       void (*setmaxtypepername)(dns_db_t *db, uint32_t value);
 } dns_dbmethods_t;
 
 typedef isc_result_t (*dns_dbcreatefunc_t)(isc_mem_t       *mctx,
@@ -1767,4 +1768,14 @@ dns_db_setmaxrrperset(dns_db_t *db, uint32_t value);
  * is nonzero, then any subsequent attempt to add an rdataset with
  * more than 'value' RRs will return ISC_R_NOSPACE.
  */
+
+void
+dns_db_setmaxtypepername(dns_db_t *db, uint32_t value);
+/*%<
+ * Set the maximum permissible number of RR types per owner name.
+ *
+ * If 'value' is nonzero, then any subsequent attempt to add an rdataset with a
+ * RR type that would exceed the number of already stored RR types will return
+ * ISC_R_NOSPACE.
+ */
 ISC_LANG_ENDDECLS
index 38ebb922dc86cee97faaf00f81b2331ac6f9071f..516c209b92734c983ada695c50d98b3e1f85b423 100644 (file)
@@ -192,6 +192,7 @@ struct dns_view {
        uint32_t          fail_ttl;
        dns_badcache_t   *failcache;
        uint32_t          maxrrperset;
+       uint32_t          maxtypepername;
 
        /*
         * Configurable data for server use only,
@@ -1420,4 +1421,10 @@ dns_view_setmaxrrperset(dns_view_t *view, uint32_t value);
  * Set the maximum resource records per RRSet that can be cached.
  */
 
+void
+dns_view_setmaxtypepername(dns_view_t *view, uint32_t value);
+/*%<
+ * Set the maximum resource record types per owner name that can be cached.
+ */
+
 ISC_LANG_ENDDECLS
index 2576119415475dfc6fb19f15c4746d6dad9bdcf5..9c63e8848cae637ab4c41ddb18706c24cc4d8cfa 100644 (file)
@@ -376,6 +376,19 @@ dns_zone_setmaxrrperset(dns_zone_t *zone, uint32_t maxrrperset);
  *\li  void
  */
 
+void
+dns_zone_setmaxtypepername(dns_zone_t *zone, uint32_t maxtypepername);
+/*%<
+ *     Sets the maximum number of resource record types per owner name
+ *     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);
 /*%<
index 7b2e62d7c8240a7ce79f6f17598132b9105b2eb6..50df5508e64429c0e67da615d2764262cf6ef130 100644 (file)
@@ -463,6 +463,7 @@ struct dns_rbtdb {
        rbtdb_serial_t least_serial;
        rbtdb_serial_t next_serial;
        uint32_t maxrrperset;
+       uint32_t maxtypepername;
        rbtdb_version_t *current_version;
        rbtdb_version_t *future_version;
        rbtdb_versionlist_t open_versions;
@@ -6260,6 +6261,7 @@ add32(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, const dns_name_t *nodename,
        rbtdb_rdatatype_t negtype, sigtype;
        dns_trust_t trust;
        int idx;
+       uint32_t ntypes = 0;
 
        /*
         * Add an rdatasetheader_t to a node.
@@ -6324,6 +6326,7 @@ add32(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, const dns_name_t *nodename,
                                        set_ttl(rbtdb, topheader, 0);
                                        mark_header_ancient(rbtdb, topheader);
                                }
+                               ntypes = 0; /* Always add the negative entry */
                                goto find_header;
                        }
                        /*
@@ -6347,9 +6350,11 @@ add32(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, const dns_name_t *nodename,
                         * check for an extant non-ancient NODATA ncache
                         * entry which covers the same type as the RRSIG.
                         */
+                       ntypes = 0;
                        for (topheader = rbtnode->data; topheader != NULL;
                             topheader = topheader->next)
                        {
+                               ++ntypes;
                                if ((topheader->type ==
                                     RBTDB_RDATATYPE_NCACHEANY) ||
                                    (newheader->type == sigtype &&
@@ -6394,9 +6399,11 @@ add32(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, const dns_name_t *nodename,
                }
        }
 
+       ntypes = 0;
        for (topheader = rbtnode->data; topheader != NULL;
             topheader = topheader->next)
        {
+               ++ntypes;
                if (prio_type(topheader->type)) {
                        prioheader = topheader;
                }
@@ -6766,6 +6773,14 @@ find_header:
                        /*
                         * No rdatasets of the given type exist at the node.
                         */
+                       if (rbtdb->maxtypepername > 0 &&
+                           ntypes >= rbtdb->maxtypepername)
+                       {
+                               free_rdataset(rbtdb, rbtdb->common.mctx,
+                                             newheader);
+                               return (DNS_R_TOOMANYRECORDS);
+                       }
+
                        newheader->down = NULL;
 
                        if (prio_type(newheader->type)) {
@@ -8127,6 +8142,15 @@ setmaxrrperset(dns_db_t *db, uint32_t maxrrperset) {
        rbtdb->maxrrperset = maxrrperset;
 }
 
+static void
+setmaxtypepername(dns_db_t *db, uint32_t maxtypepername) {
+       dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
+
+       REQUIRE(VALID_RBTDB(rbtdb));
+
+       rbtdb->maxtypepername = maxtypepername;
+}
+
 static dns_stats_t *
 getrrsetstats(dns_db_t *db) {
        dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
@@ -8249,7 +8273,8 @@ static dns_dbmethods_t zone_methods = { attach,
                                        NULL, /* setservestalerefresh */
                                        NULL, /* getservestalerefresh */
                                        setgluecachestats,
-                                       setmaxrrperset };
+                                       setmaxrrperset,
+                                       setmaxtypepername };
 
 static dns_dbmethods_t cache_methods = { attach,
                                         detach,
@@ -8300,7 +8325,8 @@ static dns_dbmethods_t cache_methods = { attach,
                                         setservestalerefresh,
                                         getservestalerefresh,
                                         NULL,
-                                        setmaxrrperset };
+                                        setmaxrrperset,
+                                        setmaxtypepername };
 
 isc_result_t
 dns_rbtdb_create(isc_mem_t *mctx, const dns_name_t *origin, dns_dbtype_t type,
index 3d841e351149b5f55013632927eee2f536273424..f4481d5ca01fc5f48bb7517564b85bcb8814756b 100644 (file)
@@ -1319,7 +1319,8 @@ static dns_dbmethods_t sdb_methods = {
        NULL, /* setservestalerefresh */
        NULL, /* getservestalerefresh */
        NULL, /* setgluecachestats */
-       NULL  /* setmaxrrperset */
+       NULL, /* setmaxrrperset */
+       NULL  /* setmaxtypepername */
 };
 
 static isc_result_t
index 2568485d3e3887f904a0a390b97091f71f7f5fa3..cb8fde52600f7a6203d45076c0d91a8ac44cbf88 100644 (file)
@@ -1292,7 +1292,8 @@ static dns_dbmethods_t sdlzdb_methods = {
        NULL, /* setservestalerefresh */
        NULL, /* getservestalerefresh */
        NULL, /* setgluecachestats */
-       NULL  /* setmaxrrperset */
+       NULL, /* setmaxrrperset */
+       NULL  /* setmaxtypepername */
 };
 
 /*
index 66c7d85cf735374ae4e49a1787b7ff583e18910f..231041efabd12ab3aa125cdca3ddb731926d7fd5 100644 (file)
@@ -894,6 +894,7 @@ dns_view_setcache(dns_view_t *view, dns_cache_t *cache, bool shared) {
        INSIST(DNS_DB_VALID(view->cachedb));
 
        dns_cache_setmaxrrperset(view->cache, view->maxrrperset);
+       dns_cache_setmaxtypepername(view->cache, view->maxtypepername);
 }
 
 bool
@@ -2770,3 +2771,12 @@ dns_view_setmaxrrperset(dns_view_t *view, uint32_t value) {
                dns_cache_setmaxrrperset(view->cache, value);
        }
 }
+
+void
+dns_view_setmaxtypepername(dns_view_t *view, uint32_t value) {
+       REQUIRE(DNS_VIEW_VALID(view));
+       view->maxtypepername = value;
+       if (view->cache != NULL) {
+               dns_cache_setmaxtypepername(view->cache, value);
+       }
+}
index 7f81c9b4399addfacfa7932cc4d7ec0a72660fd2..9b27c4a90a5b486bf5d48cea8dbd44c27d7c89f8 100644 (file)
@@ -310,6 +310,7 @@ struct dns_zone {
 
        uint32_t maxrecords;
        uint32_t maxrrperset;
+       uint32_t maxtypepername;
 
        isc_sockaddr_t *primaries;
        dns_name_t **primarykeynames;
@@ -12309,6 +12310,16 @@ dns_zone_setmaxrrperset(dns_zone_t *zone, uint32_t val) {
        }
 }
 
+void
+dns_zone_setmaxtypepername(dns_zone_t *zone, uint32_t val) {
+       REQUIRE(DNS_ZONE_VALID(zone));
+
+       zone->maxtypepername = val;
+       if (zone->db != NULL) {
+               dns_db_setmaxtypepername(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,
@@ -14798,6 +14809,8 @@ ns_query(dns_zone_t *zone, dns_rdataset_t *soardataset, dns_stub_t *stub) {
                        }
                        dns_db_settask(stub->db, zone->task, zone->task);
                        dns_db_setmaxrrperset(stub->db, zone->maxrrperset);
+                       dns_db_setmaxtypepername(stub->db,
+                                                zone->maxtypepername);
                }
 
                result = dns_db_newversion(stub->db, &stub->version);
@@ -17903,6 +17916,7 @@ zone_replacedb(dns_zone_t *zone, dns_db_t *db, bool dump) {
        zone_attachdb(zone, db);
        dns_db_settask(zone->db, zone->task, zone->task);
        dns_db_setmaxrrperset(zone->db, zone->maxrrperset);
+       dns_db_setmaxtypepername(zone->db, zone->maxtypepername);
        DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_LOADED | DNS_ZONEFLG_NEEDNOTIFY);
        return (ISC_R_SUCCESS);
 
@@ -24329,6 +24343,7 @@ dns_zone_makedb(dns_zone_t *zone, dns_db_t **dbp) {
 
        dns_db_settask(db, zone->task, zone->task);
        dns_db_setmaxrrperset(db, zone->maxrrperset);
+       dns_db_setmaxtypepername(db, zone->maxtypepername);
 
        *dbp = db;
 
index 7cbdab60d0a37b2e932a6d4b498c630ed47b7bc2..0b78e3c5d655c0c672ccf9bda1154e9f4e5cb856 100644 (file)
@@ -2303,6 +2303,9 @@ static cfg_clausedef_t zone_clauses[] = {
        { "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-types-per-name", &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,