Projects
Mega:24.03:SP1:Everything
bind
_service:tar_scm:backport-CVE-2024-1737.patch
Sign Up
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File _service:tar_scm:backport-CVE-2024-1737.patch of Package bind
From 39d3e2a8ecc1cb4dccefa3ddea477a2887989485 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Sur=C3=BD?= <ondrej@isc.org> Date: Sat, 25 May 2024 11:46:56 +0200 Subject: [PATCH] Add a limit to the number of RR types for single name 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) Conflict:Adaptation of the dns_db_settask Function Context Reference:https://downloads.isc.org/isc/bind9/9.18.28/patches/0002-CVE-2024-1737.patch --- bin/named/config.c | 2 + bin/named/server.c | 18 ++++ bin/named/zoneconf.c | 16 +++ bin/tests/system/doth/ns2/named.conf.in | 1 + bin/tests/system/doth/ns3/named.conf.in | 1 + bin/tests/system/doth/ns4/named.conf.in | 1 + bin/tests/system/doth/ns5/named.conf.in | 1 + bin/tests/system/dyndb/driver/db.c | 69 ++++++++---- doc/arm/reference.rst | 30 ++++++ doc/misc/mirror.zoneopt | 2 + doc/misc/options | 4 + doc/misc/primary.zoneopt | 2 + doc/misc/redirect.zoneopt | 2 + doc/misc/secondary.zoneopt | 2 + doc/misc/static-stub.zoneopt | 2 + doc/misc/stub.zoneopt | 2 + lib/dns/cache.c | 24 +++++ lib/dns/db.c | 18 ++++ lib/dns/dnsrps.c | 2 + lib/dns/include/dns/cache.h | 12 +++ lib/dns/include/dns/db.h | 19 ++++ lib/dns/include/dns/rdataslab.h | 6 +- lib/dns/include/dns/view.h | 14 +++ lib/dns/include/dns/zone.h | 39 +++++++ lib/dns/rbtdb.c | 138 +++++++++++++++++++++--- lib/dns/rdataslab.c | 14 ++- lib/dns/sdb.c | 46 +++++--- lib/dns/sdlz.c | 79 +++++++++----- lib/dns/view.c | 21 ++++ lib/dns/xfrin.c | 24 +---- lib/dns/zone.c | 96 +++++++++++++---- lib/isccfg/namedconf.c | 6 ++ lib/ns/update.c | 15 ++- 33 files changed, 602 insertions(+), 126 deletions(-) diff --git a/bin/named/config.c b/bin/named/config.c index f95e433..af8637e 100644 --- a/bin/named/config.c +++ b/bin/named/config.c @@ -233,8 +233,10 @@ options {\n\ ixfr-from-differences false;\n\ max-journal-size default;\n\ max-records 0;\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\ diff --git a/bin/named/server.c b/bin/named/server.c index bfe6df3..8d7f56e 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -5563,6 +5563,24 @@ 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)); + + /* + * 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); diff --git a/bin/named/zoneconf.c b/bin/named/zoneconf.c index 44c2242..384a81e 100644 --- a/bin/named/zoneconf.c +++ b/bin/named/zoneconf.c @@ -1083,6 +1083,22 @@ 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); + } + + 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); diff --git a/bin/tests/system/doth/ns2/named.conf.in b/bin/tests/system/doth/ns2/named.conf.in index e533f47..f10dac5 100644 --- a/bin/tests/system/doth/ns2/named.conf.in +++ b/bin/tests/system/doth/ns2/named.conf.in @@ -49,6 +49,7 @@ options { ixfr-from-differences yes; check-integrity no; dnssec-validation yes; + max-records-per-type 0; transfers-in 100; transfers-out 100; }; diff --git a/bin/tests/system/doth/ns3/named.conf.in b/bin/tests/system/doth/ns3/named.conf.in index cd1ab9c..cd9fc63 100644 --- a/bin/tests/system/doth/ns3/named.conf.in +++ b/bin/tests/system/doth/ns3/named.conf.in @@ -44,6 +44,7 @@ options { ixfr-from-differences yes; check-integrity no; dnssec-validation yes; + max-records-per-type 0; }; zone "." { diff --git a/bin/tests/system/doth/ns4/named.conf.in b/bin/tests/system/doth/ns4/named.conf.in index c7c6c91..43b7c78 100644 --- a/bin/tests/system/doth/ns4/named.conf.in +++ b/bin/tests/system/doth/ns4/named.conf.in @@ -52,6 +52,7 @@ options { ixfr-from-differences yes; check-integrity no; dnssec-validation yes; + max-records-per-type 0; }; zone "." { diff --git a/bin/tests/system/doth/ns5/named.conf.in b/bin/tests/system/doth/ns5/named.conf.in index 6808618..9323637 100644 --- a/bin/tests/system/doth/ns5/named.conf.in +++ b/bin/tests/system/doth/ns5/named.conf.in @@ -40,6 +40,7 @@ options { ixfr-from-differences yes; check-integrity no; dnssec-validation yes; + max-records-per-type 0; }; zone "." { diff --git a/bin/tests/system/dyndb/driver/db.c b/bin/tests/system/dyndb/driver/db.c index 334fd54..d34d1e0 100644 --- a/bin/tests/system/dyndb/driver/db.c +++ b/bin/tests/system/dyndb/driver/db.c @@ -563,28 +563,57 @@ hashsize(dns_db_t *db) { * determine which implementation of dns_db_*() function to call. */ static dns_dbmethods_t sampledb_methods = { - attach, detach, beginload, - endload, dump, currentversion, - newversion, attachversion, closeversion, - findnode, find, findzonecut, - attachnode, detachnode, expirenode, - printnode, createiterator, findrdataset, - allrdatasets, addrdataset, subtractrdataset, - deleterdataset, issecure, nodecount, - ispersistent, overmem, settask, - getoriginnode, transfernode, getnsec3parameters, - findnsec3node, setsigningtime, getsigningtime, - resigned, isdnssec, getrrsetstats, + attach, + detach, + beginload, + endload, + dump, + currentversion, + newversion, + attachversion, + closeversion, + findnode, + find, + findzonecut, + attachnode, + detachnode, + expirenode, + printnode, + createiterator, + findrdataset, + allrdatasets, + addrdataset, + subtractrdataset, + deleterdataset, + issecure, + nodecount, + ispersistent, + overmem, + settask, + getoriginnode, + transfernode, + getnsec3parameters, + findnsec3node, + setsigningtime, + getsigningtime, + resigned, + isdnssec, + getrrsetstats, NULL, /* rpz_attach */ NULL, /* rpz_ready */ - findnodeext, findext, setcachestats, - hashsize, NULL, /* nodefullname */ - NULL, /* getsize */ - NULL, /* setservestalettl */ - NULL, /* getservestalettl */ - NULL, /* setservestalerefresh */ - NULL, /* getservestalerefresh */ - NULL, /* setgluecachestats */ + findnodeext, + findext, + setcachestats, + hashsize, + NULL, /* nodefullname */ + NULL, /* getsize */ + NULL, /* setservestalettl */ + NULL, /* getservestalettl */ + NULL, /* setservestalerefresh */ + NULL, /* getservestalerefresh */ + NULL, /* setgluecachestats */ + NULL, /* setmaxrrperset */ + NULL /* setmaxtypepername */ }; /* Auxiliary driver functions. */ diff --git a/doc/arm/reference.rst b/doc/arm/reference.rst index e1b8228..29e246b 100644 --- a/doc/arm/reference.rst +++ b/doc/arm/reference.rst @@ -3766,6 +3766,36 @@ system. This sets the maximum number of records permitted in a zone. The default is zero, which means the maximum is unlimited. +.. namedconf:statement:: max-records-per-type + :tags: server + :short: Sets the maximum number of records that can be stored in an RRset + + This sets the maximum number of resource records that can be stored + in an RRset in a database. When configured in :namedconf:ref:`options` + or :namedconf:ref:`view`, it controls the cache database; it 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 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. + +.. 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. diff --git a/doc/misc/mirror.zoneopt b/doc/misc/mirror.zoneopt index ac371cd..5f688ca 100644 --- a/doc/misc/mirror.zoneopt +++ b/doc/misc/mirror.zoneopt @@ -18,12 +18,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 a916701..5fe415d 100644 --- a/doc/misc/options +++ b/doc/misc/options @@ -180,6 +180,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>; @@ -190,6 +191,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>; @@ -470,6 +472,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>; @@ -479,6 +482,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>; diff --git a/doc/misc/primary.zoneopt b/doc/misc/primary.zoneopt index 8f646e3..1de2f21 100644 --- a/doc/misc/primary.zoneopt +++ b/doc/misc/primary.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/redirect.zoneopt b/doc/misc/redirect.zoneopt index bcd9a57..9d238c1 100644 --- a/doc/misc/redirect.zoneopt +++ b/doc/misc/redirect.zoneopt @@ -7,6 +7,8 @@ zone <string> [ <class> ] { masterfile-format ( raw | text ); 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> ); diff --git a/doc/misc/secondary.zoneopt b/doc/misc/secondary.zoneopt index 3237aab..169fa9b 100644 --- a/doc/misc/secondary.zoneopt +++ b/doc/misc/secondary.zoneopt @@ -30,12 +30,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 5357528..93a3220 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> ] { ( <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> ); diff --git a/doc/misc/stub.zoneopt b/doc/misc/stub.zoneopt index 29c1d56..2834682 100644 --- a/doc/misc/stub.zoneopt +++ b/doc/misc/stub.zoneopt @@ -12,10 +12,12 @@ zone <string> [ <class> ] { masterfile-format ( raw | text ); masterfile-style ( full | relative ); 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 7ffb6f8..782cf2b 100644 --- a/lib/dns/cache.c +++ b/lib/dns/cache.c @@ -144,6 +144,8 @@ struct dns_cache { dns_ttl_t serve_stale_ttl; dns_ttl_t serve_stale_refresh; isc_stats_t *stats; + uint32_t maxrrperset; + uint32_t maxtypepername; }; /*** @@ -175,6 +177,8 @@ cache_create_db(dns_cache_t *cache, dns_db_t **db) { if (result == ISC_R_SUCCESS) { 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); } return (result); } @@ -1194,6 +1198,26 @@ 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); + } +} + +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 diff --git a/lib/dns/db.c b/lib/dns/db.c index c95d19a..85f6daa 100644 --- a/lib/dns/db.c +++ b/lib/dns/db.c @@ -1119,3 +1119,21 @@ 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); + } +} + +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); + } +} diff --git a/lib/dns/dnsrps.c b/lib/dns/dnsrps.c index d4a1c65..73f11da 100644 --- a/lib/dns/dnsrps.c +++ b/lib/dns/dnsrps.c @@ -975,6 +975,8 @@ static dns_dbmethods_t rpsdb_db_methods = { NULL, /* setservestalerefresh */ NULL, /* getservestalerefresh */ NULL, /* setgluecachestats */ + NULL, /* setmaxrrperset */ + NULL /* setmaxtypepername */ }; static dns_rdatasetmethods_t rpsdb_rdataset_methods = { diff --git a/lib/dns/include/dns/cache.h b/lib/dns/include/dns/cache.h index 8fc9657..91e94c0 100644 --- a/lib/dns/include/dns/cache.h +++ b/lib/dns/include/dns/cache.h @@ -283,6 +283,18 @@ 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. + */ + +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); diff --git a/lib/dns/include/dns/db.h b/lib/dns/include/dns/db.h index 9b53f04..b6e826b 100644 --- a/lib/dns/include/dns/db.h +++ b/lib/dns/include/dns/db.h @@ -185,6 +185,8 @@ typedef struct dns_dbmethods { isc_result_t (*setservestalerefresh)(dns_db_t *db, uint32_t interval); 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, @@ -1756,4 +1758,21 @@ 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. + */ + +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 diff --git a/lib/dns/include/dns/rdataslab.h b/lib/dns/include/dns/rdataslab.h index 7364b8d..5729c00 100644 --- a/lib/dns/include/dns/rdataslab.h +++ b/lib/dns/include/dns/rdataslab.h @@ -66,7 +66,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'. @@ -122,7 +123,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 18b0b33..516c209 100644 --- a/lib/dns/include/dns/view.h +++ b/lib/dns/include/dns/view.h @@ -191,6 +191,8 @@ struct dns_view { dns_dlzdblist_t dlz_unsearched; uint32_t fail_ttl; dns_badcache_t *failcache; + uint32_t maxrrperset; + uint32_t maxtypepername; /* * Configurable data for server use only, @@ -1413,4 +1415,16 @@ dns_view_sfd_find(dns_view_t *view, const dns_name_t *name, *\li 'foundname' to be valid with a buffer sufficient to hold the name. */ +void +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 diff --git a/lib/dns/include/dns/zone.h b/lib/dns/include/dns/zone.h index 10ed86c..3449065 100644 --- a/lib/dns/include/dns/zone.h +++ b/lib/dns/include/dns/zone.h @@ -165,6 +165,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); /*%< @@ -350,6 +363,32 @@ 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_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); /*%< diff --git a/lib/dns/rbtdb.c b/lib/dns/rbtdb.c index bc0f8d8..c22e021 100644 --- a/lib/dns/rbtdb.c +++ b/lib/dns/rbtdb.c @@ -450,6 +450,8 @@ struct dns_rbtdb { rbtdb_serial_t current_serial; 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; @@ -913,6 +915,8 @@ prio_type(rbtdb_rdatatype_t type) { case RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_soa): case dns_rdatatype_a: case RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_a): + case dns_rdatatype_mx: + case RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_mx): case dns_rdatatype_aaaa: case RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_aaaa): case dns_rdatatype_nsec: @@ -925,6 +929,22 @@ prio_type(rbtdb_rdatatype_t type) { case RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_ds): case dns_rdatatype_cname: case RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_cname): + case dns_rdatatype_dname: + case RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_dname): + case dns_rdatatype_svcb: + case RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_svcb): + case dns_rdatatype_https: + case RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_https): + case dns_rdatatype_dnskey: + case RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_dnskey): + case dns_rdatatype_srv: + case RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_srv): + case dns_rdatatype_txt: + case RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_txt): + case dns_rdatatype_ptr: + case RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_ptr): + case dns_rdatatype_naptr: + case RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_naptr): return (true); } return (false); @@ -6180,6 +6200,24 @@ update_recordsandxfrsize(bool add, rbtdb_version_t *rbtversion, RWUNLOCK(&rbtversion->rwlock, isc_rwlocktype_write); } +static bool +overmaxtype(dns_rbtdb_t *rbtdb, uint32_t ntypes) { + if (rbtdb->maxtypepername == 0) { + return (false); + } + + return (ntypes >= rbtdb->maxtypepername); +} + +static bool +prio_header(rdatasetheader_t *header) { + if (NEGATIVE(header) && prio_type(RBTDB_RDATATYPE_EXT(header->type))) { + return (true); + } + + return (prio_type(header->type)); +} + /* * write lock on rbtnode must be held. */ @@ -6191,7 +6229,7 @@ add32(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, const dns_name_t *nodename, rbtdb_changed_t *changed = NULL; rdatasetheader_t *topheader = NULL, *topheader_prev = NULL; rdatasetheader_t *header = NULL, *sigheader = NULL; - rdatasetheader_t *prioheader = NULL; + rdatasetheader_t *prioheader = NULL, *expireheader = NULL; unsigned char *merged = NULL; isc_result_t result; bool header_nx; @@ -6201,6 +6239,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. @@ -6276,6 +6315,7 @@ add32(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, const dns_name_t *nodename, { if (topheader->type == sigtype) { sigheader = topheader; + break; } } negtype = RBTDB_RDATATYPE_VALUE(covers, 0); @@ -6338,7 +6378,13 @@ add32(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, const dns_name_t *nodename, for (topheader = rbtnode->data; topheader != NULL; topheader = topheader->next) { - if (prio_type(topheader->type)) { + if (IS_CACHE(rbtdb) && ACTIVE(topheader, now)) { + ++ntypes; + expireheader = topheader; + } else if (!IS_CACHE(rbtdb)) { + ++ntypes; + } + if (prio_header(topheader)) { prioheader = topheader; } if (topheader->type == newheader->type || @@ -6428,7 +6474,7 @@ find_header: rbtdb->common.mctx, rbtdb->common.rdclass, (dns_rdatatype_t)header->type, flags, - &merged); + rbtdb->maxrrperset, &merged); } if (result == ISC_R_SUCCESS) { /* @@ -6707,9 +6753,15 @@ find_header: /* * No rdatasets of the given type exist at the node. */ + if (!IS_CACHE(rbtdb) && overmaxtype(rbtdb, ntypes)) { + free_rdataset(rbtdb, rbtdb->common.mctx, + newheader); + return (DNS_R_TOOMANYRECORDS); + } + newheader->down = NULL; - if (prio_type(newheader->type)) { + if (prio_header(newheader)) { /* This is a priority type, prepend it */ newheader->next = rbtnode->data; rbtnode->data = newheader; @@ -6722,6 +6774,31 @@ find_header: newheader->next = rbtnode->data; rbtnode->data = newheader; } + + if (IS_CACHE(rbtdb) && overmaxtype(rbtdb, ntypes)) { + if (expireheader == NULL) { + expireheader = newheader; + } + if (NEGATIVE(newheader) && + !prio_header(newheader)) + { + /* + * Add the new non-priority negative + * header to the database only + * temporarily. + */ + expireheader = newheader; + } + + set_ttl(rbtdb, expireheader, 0); + mark_header_ancient(rbtdb, expireheader); + /* + * FIXME: In theory, we should mark the RRSIG + * and the header at the same time, but there is + * no direct link between those two header, so + * we would have to check the whole list again. + */ + } } } @@ -6767,7 +6844,7 @@ delegating_type(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, static 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; @@ -6788,12 +6865,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; } @@ -6812,7 +6889,7 @@ cleanup: static 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; @@ -6833,12 +6910,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; } @@ -6916,7 +6993,8 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, } result = dns_rdataslab_fromrdataset(rdataset, rbtdb->common.mctx, - ®ion, sizeof(rdatasetheader_t)); + ®ion, sizeof(rdatasetheader_t), + rbtdb->maxrrperset); if (result != ISC_R_SUCCESS) { return (result); } @@ -6974,7 +7052,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); @@ -6982,7 +7061,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); @@ -7148,7 +7228,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, - ®ion, sizeof(rdatasetheader_t)); + ®ion, sizeof(rdatasetheader_t), + 0); if (result != ISC_R_SUCCESS) { return (result); } @@ -7552,7 +7633,8 @@ loading_addrdataset(void *arg, const dns_name_t *name, } result = dns_rdataslab_fromrdataset(rdataset, rbtdb->common.mctx, - ®ion, sizeof(rdatasetheader_t)); + ®ion, sizeof(rdatasetheader_t), + rbtdb->maxrrperset); if (result != ISC_R_SUCCESS) { return (result); } @@ -8088,6 +8170,24 @@ 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 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; @@ -8209,7 +8309,9 @@ static dns_dbmethods_t zone_methods = { attach, NULL, /* getservestalettl */ NULL, /* setservestalerefresh */ NULL, /* getservestalerefresh */ - setgluecachestats }; + setgluecachestats, + setmaxrrperset, + setmaxtypepername }; static dns_dbmethods_t cache_methods = { attach, detach, @@ -8259,7 +8361,9 @@ static dns_dbmethods_t cache_methods = { attach, getservestalettl, setservestalerefresh, getservestalerefresh, - NULL }; + NULL, + setmaxrrperset, + setmaxtypepername }; 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 24fdaa8..5c30d44 100644 --- a/lib/dns/rdataslab.c +++ b/lib/dns/rdataslab.c @@ -114,7 +114,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. @@ -156,6 +157,10 @@ dns_rdataslab_fromrdataset(dns_rdataset_t *rdataset, isc_mem_t *mctx, return (ISC_R_SUCCESS); } + if (maxrrperset > 0 && nitems > maxrrperset) { + return (DNS_R_TOOMANYRECORDS); + } + if (nitems > 0xffff) { return (ISC_R_NOSPACE); } @@ -482,7 +487,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; @@ -522,6 +528,10 @@ dns_rdataslab_merge(unsigned char *oslab, unsigned char *nslab, #endif /* if DNS_RDATASET_FIXED */ INSIST(ocount > 0 && ncount > 0); + if (maxrrperset > 0 && ocount + ncount > maxrrperset) { + return (DNS_R_TOOMANYRECORDS); + } + #if DNS_RDATASET_FIXED oncount = ncount; #endif /* if DNS_RDATASET_FIXED */ diff --git a/lib/dns/sdb.c b/lib/dns/sdb.c index 317eeb0..07d720e 100644 --- a/lib/dns/sdb.c +++ b/lib/dns/sdb.c @@ -1269,20 +1269,33 @@ settask(dns_db_t *db, isc_task_t *task) { } static dns_dbmethods_t sdb_methods = { - attach, detach, - beginload, endload, - dump, currentversion, - newversion, attachversion, - closeversion, NULL, /* findnode */ - NULL, /* find */ - findzonecut, attachnode, - detachnode, expirenode, - printnode, createiterator, - findrdataset, allrdatasets, - addrdataset, subtractrdataset, - deleterdataset, issecure, - nodecount, ispersistent, - overmem, settask, + attach, + detach, + beginload, + endload, + dump, + currentversion, + newversion, + attachversion, + closeversion, + NULL, /* findnode */ + NULL, /* find */ + findzonecut, + attachnode, + detachnode, + expirenode, + printnode, + createiterator, + findrdataset, + allrdatasets, + addrdataset, + subtractrdataset, + deleterdataset, + issecure, + nodecount, + ispersistent, + overmem, + settask, getoriginnode, /* getoriginnode */ NULL, /* transfernode */ NULL, /* getnsec3parameters */ @@ -1294,7 +1307,8 @@ static dns_dbmethods_t sdb_methods = { NULL, /* getrrsetstats */ NULL, /* rpz_attach */ NULL, /* rpz_ready */ - findnodeext, findext, + findnodeext, + findext, NULL, /* setcachestats */ NULL, /* hashsize */ NULL, /* nodefullname */ @@ -1304,6 +1318,8 @@ static dns_dbmethods_t sdb_methods = { NULL, /* setservestalerefresh */ NULL, /* getservestalerefresh */ NULL, /* setgluecachestats */ + NULL, /* setmaxrrperset */ + NULL /* setmaxtypepername */ }; static isc_result_t diff --git a/lib/dns/sdlz.c b/lib/dns/sdlz.c index 7ab08f6..f9d123d 100644 --- a/lib/dns/sdlz.c +++ b/lib/dns/sdlz.c @@ -1242,34 +1242,57 @@ getoriginnode(dns_db_t *db, dns_dbnode_t **nodep) { } static dns_dbmethods_t sdlzdb_methods = { - attach, detach, beginload, - endload, dump, currentversion, - newversion, attachversion, closeversion, - findnode, find, findzonecut, - attachnode, detachnode, expirenode, - printnode, createiterator, findrdataset, - allrdatasets, addrdataset, subtractrdataset, - deleterdataset, issecure, nodecount, - ispersistent, overmem, settask, - getoriginnode, NULL, /* transfernode */ - NULL, /* getnsec3parameters */ - NULL, /* findnsec3node */ - NULL, /* setsigningtime */ - NULL, /* getsigningtime */ - NULL, /* resigned */ - NULL, /* isdnssec */ - NULL, /* getrrsetstats */ - NULL, /* rpz_attach */ - NULL, /* rpz_ready */ - findnodeext, findext, NULL, /* setcachestats */ - NULL, /* hashsize */ - NULL, /* nodefullname */ - NULL, /* getsize */ - NULL, /* setservestalettl */ - NULL, /* getservestalettl */ - NULL, /* setservestalerefresh */ - NULL, /* getservestalerefresh */ - NULL, /* setgluecachestats */ + attach, + detach, + beginload, + endload, + dump, + currentversion, + newversion, + attachversion, + closeversion, + findnode, + find, + findzonecut, + attachnode, + detachnode, + expirenode, + printnode, + createiterator, + findrdataset, + allrdatasets, + addrdataset, + subtractrdataset, + deleterdataset, + issecure, + nodecount, + ispersistent, + overmem, + settask, + getoriginnode, + NULL, /* transfernode */ + NULL, /* getnsec3parameters */ + NULL, /* findnsec3node */ + NULL, /* setsigningtime */ + NULL, /* getsigningtime */ + NULL, /* resigned */ + NULL, /* isdnssec */ + NULL, /* getrrsetstats */ + NULL, /* rpz_attach */ + NULL, /* rpz_ready */ + findnodeext, + findext, + NULL, /* setcachestats */ + NULL, /* hashsize */ + NULL, /* nodefullname */ + NULL, /* getsize */ + NULL, /* setservestalettl */ + NULL, /* getservestalettl */ + NULL, /* setservestalerefresh */ + NULL, /* getservestalerefresh */ + NULL, /* setgluecachestats */ + NULL, /* setmaxrrperset */ + NULL /* setmaxtypepername */ }; /* diff --git a/lib/dns/view.c b/lib/dns/view.c index 49c9aee..231041e 100644 --- a/lib/dns/view.c +++ b/lib/dns/view.c @@ -892,6 +892,9 @@ 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); + dns_cache_setmaxtypepername(view->cache, view->maxtypepername); } bool @@ -2759,3 +2762,21 @@ dns_view_sfd_find(dns_view_t *view, const dns_name_t *name, dns_name_copy(dns_rootname, foundname); } } + +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); + } +} + +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); + } +} diff --git a/lib/dns/xfrin.c b/lib/dns/xfrin.c index 1aa982a..e5f1e0b 100644 --- a/lib/dns/xfrin.c +++ b/lib/dns/xfrin.c @@ -211,8 +211,6 @@ xfrin_create(isc_mem_t *mctx, dns_zone_t *zone, dns_db_t *db, isc_nm_t *netmgr, 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 @@ -288,7 +286,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; @@ -296,22 +298,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 3b95136..f14a166 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -309,6 +309,8 @@ struct dns_zone { uint32_t minretry; uint32_t maxrecords; + uint32_t maxrrperset; + uint32_t maxtypepername; isc_sockaddr_t *primaries; dns_name_t **primarykeynames; @@ -2327,31 +2329,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 || zone->stream != NULL) { @@ -10063,6 +10047,7 @@ cleanup: } dns_diff_clear(&_sig_diff); + dns_diff_clear(&post_diff); for (i = 0; i < nkeys; i++) { dst_key_free(&zone_keys[i]); @@ -12332,6 +12317,26 @@ 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); + } +} + +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, @@ -14799,6 +14804,9 @@ 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); + dns_db_setmaxtypepername(stub->db, + zone->maxtypepername); } result = dns_db_newversion(stub->db, &stub->version); @@ -17516,6 +17524,8 @@ 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_db_setmaxtypepername(zone->db, zone->maxtypepername); DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_LOADED | DNS_ZONEFLG_NEEDNOTIFY); return (ISC_R_SUCCESS); @@ -22045,7 +22055,11 @@ failure: * Something went wrong; try again in ten minutes or * after a key refresh interval, whichever is shorter. */ - dnssec_log(zone, ISC_LOG_DEBUG(3), + int loglevel = ISC_LOG_DEBUG(3); + if (result != DNS_R_NOTLOADED) { + loglevel = ISC_LOG_ERROR; + } + dnssec_log(zone, loglevel, "zone_rekey failure: %s (retry in %u seconds)", isc_result_totext(result), ISC_MIN(zone->refreshkeyinterval, 600)); @@ -23706,3 +23720,45 @@ zmgr_tlsctx_attach(dns_zonemgr_t *zmgr, isc_tlsctx_cache_t **ptlsctx_cache) { RWUNLOCK(&zmgr->tlsctx_cache_rwlock, isc_rwlocktype_read); } + +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); + dns_db_setmaxtypepername(db, zone->maxtypepername); + + *dbp = db; + + return (ISC_R_SUCCESS); +} diff --git a/lib/isccfg/namedconf.c b/lib/isccfg/namedconf.c index 5a8ccb2..7938bcb 100644 --- a/lib/isccfg/namedconf.c +++ b/lib/isccfg/namedconf.c @@ -2300,6 +2300,12 @@ 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-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, diff --git a/lib/ns/update.c b/lib/ns/update.c index 983ca84..5d72686 100644 --- a/lib/ns/update.c +++ b/lib/ns/update.c @@ -3302,9 +3302,18 @@ update_action(isc_task_t *task, isc_event_t *event) { dns_diff_clear(&ctx.add_diff); goto failure; } - CHECK(update_one_rr(db, ver, &diff, - DNS_DIFFOP_ADD, - name, ttl, &rdata)); + result = update_one_rr( + db, ver, &diff, DNS_DIFFOP_ADD, + name, ttl, &rdata); + if (result != ISC_R_SUCCESS) { + update_log(client, zone, + LOGLEVEL_PROTOCOL, + "adding an RR " + "failed: %s", + isc_result_totext( + result)); + goto failure; + } } } } else if (update_class == dns_rdataclass_any) { -- 2.33.0
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.
浙ICP备2022010568号-2