mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-08-22 01:59:26 +00:00
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.
This commit is contained in:
parent
0b44383c5b
commit
32af7299eb
@ -222,6 +222,7 @@ 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-transfer-idle-in 60;\n\
|
||||
|
@ -5454,6 +5454,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);
|
||||
|
@ -1074,6 +1074,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);
|
||||
|
@ -52,6 +52,7 @@ options {
|
||||
ixfr-from-differences yes;
|
||||
check-integrity no;
|
||||
dnssec-validation yes;
|
||||
max-records-per-type 0;
|
||||
transfers-in 100;
|
||||
transfers-out 100;
|
||||
};
|
||||
|
@ -44,6 +44,7 @@ options {
|
||||
ixfr-from-differences yes;
|
||||
check-integrity no;
|
||||
dnssec-validation yes;
|
||||
max-records-per-type 0;
|
||||
};
|
||||
|
||||
trust-anchors { };
|
||||
|
@ -52,6 +52,7 @@ options {
|
||||
ixfr-from-differences yes;
|
||||
check-integrity no;
|
||||
dnssec-validation yes;
|
||||
max-records-per-type 0;
|
||||
};
|
||||
|
||||
trust-anchors { };
|
||||
|
@ -40,6 +40,7 @@ options {
|
||||
ixfr-from-differences yes;
|
||||
check-integrity no;
|
||||
dnssec-validation yes;
|
||||
max-records-per-type 0;
|
||||
};
|
||||
|
||||
trust-anchors { };
|
||||
|
@ -3681,6 +3681,21 @@ 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:: recursive-clients
|
||||
:tags: query
|
||||
:short: Specifies the maximum number of concurrent recursive queries the server can perform.
|
||||
|
@ -16,6 +16,7 @@ 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>;
|
||||
|
@ -183,6 +183,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>;
|
||||
@ -468,6 +469,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>;
|
||||
|
@ -37,6 +37,7 @@ 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-zone-ttl ( unlimited | <duration> ); // deprecated
|
||||
|
@ -7,6 +7,7 @@ zone <string> [ <class> ] {
|
||||
masterfile-format ( raw | text );
|
||||
masterfile-style ( full | relative );
|
||||
max-records <integer>;
|
||||
max-records-per-type <integer>;
|
||||
max-zone-ttl ( unlimited | <duration> ); // deprecated
|
||||
primaries [ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <remote-servers> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... };
|
||||
zone-statistics ( full | terse | none | <boolean> );
|
||||
|
@ -28,6 +28,7 @@ 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>;
|
||||
|
@ -5,6 +5,7 @@ zone <string> [ <class> ] {
|
||||
forward ( first | only );
|
||||
forwarders [ port <integer> ] [ tls <string> ] { ( <ipv4_address> | <ipv6_address> ) [ port <integer> ] [ tls <string> ]; ... };
|
||||
max-records <integer>;
|
||||
max-records-per-type <integer>;
|
||||
server-addresses { ( <ipv4_address> | <ipv6_address> ); ... };
|
||||
server-names { <string>; ... };
|
||||
zone-statistics ( full | terse | none | <boolean> );
|
||||
|
@ -11,6 +11,7 @@ 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>;
|
||||
|
@ -80,6 +80,7 @@ struct dns_cache {
|
||||
dns_ttl_t serve_stale_ttl;
|
||||
dns_ttl_t serve_stale_refresh;
|
||||
isc_stats_t *stats;
|
||||
uint32_t maxrrperset;
|
||||
};
|
||||
|
||||
/***
|
||||
@ -128,6 +129,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);
|
||||
|
||||
/*
|
||||
* XXX this is only used by the RBT cache, and can
|
||||
@ -546,6 +548,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
|
||||
|
@ -1170,3 +1170,12 @@ dns_db_nodefullname(dns_db_t *db, dns_dbnode_t *node, dns_name_t *name) {
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -246,6 +246,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);
|
||||
|
@ -183,6 +183,7 @@ typedef struct dns_dbmethods {
|
||||
void (*deletedata)(dns_db_t *db, dns_dbnode_t *node, void *data);
|
||||
isc_result_t (*nodefullname)(dns_db_t *db, dns_dbnode_t *node,
|
||||
dns_name_t *name);
|
||||
void (*setmaxrrperset)(dns_db_t *db, uint32_t value);
|
||||
} dns_dbmethods_t;
|
||||
|
||||
typedef isc_result_t (*dns_dbcreatefunc_t)(isc_mem_t *mctx,
|
||||
@ -1800,4 +1801,12 @@ dns_db_nodefullname(dns_db_t *db, dns_dbnode_t *node, dns_name_t *name);
|
||||
* \li 'db' is a valid database
|
||||
* \li 'node' and 'name' are not 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_TOOMANYRECORDS.
|
||||
*/
|
||||
ISC_LANG_ENDDECLS
|
||||
|
@ -169,7 +169,8 @@ extern dns_rdatasetmethods_t dns_rdataslab_rdatasetmethods;
|
||||
|
||||
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'.
|
||||
@ -225,7 +226,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'.
|
||||
*/
|
||||
|
@ -183,6 +183,7 @@ struct dns_view {
|
||||
uint32_t fail_ttl;
|
||||
dns_badcache_t *failcache;
|
||||
unsigned int udpsize;
|
||||
uint32_t maxrrperset;
|
||||
|
||||
/*
|
||||
* Configurable data for server use only,
|
||||
@ -1242,6 +1243,12 @@ dns_view_getresolver(dns_view_t *view, dns_resolver_t **resolverp);
|
||||
* Return the resolver associated with the view.
|
||||
*/
|
||||
|
||||
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_setudpsize(dns_view_t *view, uint16_t udpsize);
|
||||
/*%<
|
||||
|
@ -366,6 +366,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);
|
||||
/*%<
|
||||
|
@ -217,6 +217,8 @@ struct qpcache {
|
||||
/* Locked by lock. */
|
||||
unsigned int active;
|
||||
|
||||
uint32_t maxrrperset; /* Maximum RRs per RRset */
|
||||
|
||||
/*
|
||||
* The time after a failed lookup, where stale answers from cache
|
||||
* may be used directly in a DNS response without attempting a
|
||||
@ -3280,7 +3282,7 @@ find_header:
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
addnoqname(isc_mem_t *mctx, dns_slabheader_t *newheader,
|
||||
addnoqname(isc_mem_t *mctx, dns_slabheader_t *newheader, uint32_t maxrrperset,
|
||||
dns_rdataset_t *rdataset) {
|
||||
isc_result_t result;
|
||||
dns_slabheader_proof_t *noqname = NULL;
|
||||
@ -3291,12 +3293,12 @@ addnoqname(isc_mem_t *mctx, dns_slabheader_t *newheader,
|
||||
result = dns_rdataset_getnoqname(rdataset, &name, &neg, &negsig);
|
||||
RUNTIME_CHECK(result == ISC_R_SUCCESS);
|
||||
|
||||
result = dns_rdataslab_fromrdataset(&neg, mctx, &r1, 0);
|
||||
result = dns_rdataslab_fromrdataset(&neg, mctx, &r1, 0, maxrrperset);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
result = dns_rdataslab_fromrdataset(&negsig, mctx, &r2, 0);
|
||||
result = dns_rdataslab_fromrdataset(&negsig, mctx, &r2, 0, maxrrperset);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
goto cleanup;
|
||||
}
|
||||
@ -3319,7 +3321,7 @@ cleanup:
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
addclosest(isc_mem_t *mctx, dns_slabheader_t *newheader,
|
||||
addclosest(isc_mem_t *mctx, dns_slabheader_t *newheader, uint32_t maxrrperset,
|
||||
dns_rdataset_t *rdataset) {
|
||||
isc_result_t result;
|
||||
dns_slabheader_proof_t *closest = NULL;
|
||||
@ -3330,12 +3332,12 @@ addclosest(isc_mem_t *mctx, dns_slabheader_t *newheader,
|
||||
result = dns_rdataset_getclosest(rdataset, &name, &neg, &negsig);
|
||||
RUNTIME_CHECK(result == ISC_R_SUCCESS);
|
||||
|
||||
result = dns_rdataslab_fromrdataset(&neg, mctx, &r1, 0);
|
||||
result = dns_rdataslab_fromrdataset(&neg, mctx, &r1, 0, maxrrperset);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
result = dns_rdataslab_fromrdataset(&negsig, mctx, &r2, 0);
|
||||
result = dns_rdataslab_fromrdataset(&negsig, mctx, &r2, 0, maxrrperset);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
goto cleanup;
|
||||
}
|
||||
@ -3386,7 +3388,8 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
|
||||
}
|
||||
|
||||
result = dns_rdataslab_fromrdataset(rdataset, qpdb->common.mctx,
|
||||
®ion, sizeof(dns_slabheader_t));
|
||||
®ion, sizeof(dns_slabheader_t),
|
||||
qpdb->maxrrperset);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
return (result);
|
||||
}
|
||||
@ -3423,14 +3426,16 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
|
||||
DNS_SLABHEADER_SETATTR(newheader, DNS_SLABHEADERATTR_OPTOUT);
|
||||
}
|
||||
if ((rdataset->attributes & DNS_RDATASETATTR_NOQNAME) != 0) {
|
||||
result = addnoqname(qpdb->common.mctx, newheader, rdataset);
|
||||
result = addnoqname(qpdb->common.mctx, newheader,
|
||||
qpdb->maxrrperset, rdataset);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
dns_slabheader_destroy(&newheader);
|
||||
return (result);
|
||||
}
|
||||
}
|
||||
if ((rdataset->attributes & DNS_RDATASETATTR_CLOSEST) != 0) {
|
||||
result = addclosest(qpdb->common.mctx, newheader, rdataset);
|
||||
result = addclosest(qpdb->common.mctx, newheader,
|
||||
qpdb->maxrrperset, rdataset);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
dns_slabheader_destroy(&newheader);
|
||||
return (result);
|
||||
@ -4330,6 +4335,15 @@ expire_ttl_headers(qpcache_t *qpdb, unsigned int locknum,
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
setmaxrrperset(dns_db_t *db, uint32_t value) {
|
||||
qpcache_t *qpdb = (qpcache_t *)db;
|
||||
|
||||
REQUIRE(VALID_QPDB(qpdb));
|
||||
|
||||
qpdb->maxrrperset = value;
|
||||
}
|
||||
|
||||
static dns_dbmethods_t qpdb_cachemethods = {
|
||||
.destroy = qpdb_destroy,
|
||||
.findnode = findnode,
|
||||
@ -4354,6 +4368,7 @@ static dns_dbmethods_t qpdb_cachemethods = {
|
||||
.unlocknode = unlocknode,
|
||||
.expiredata = expiredata,
|
||||
.deletedata = deletedata,
|
||||
.setmaxrrperset = setmaxrrperset,
|
||||
};
|
||||
|
||||
static void
|
||||
|
@ -178,6 +178,7 @@ struct qpzonedb {
|
||||
uint32_t current_serial;
|
||||
uint32_t least_serial;
|
||||
uint32_t next_serial;
|
||||
uint32_t maxrrperset;
|
||||
qpz_version_t *current_version;
|
||||
qpz_version_t *future_version;
|
||||
qpz_versionlist_t open_versions;
|
||||
@ -1898,7 +1899,7 @@ add(qpzonedb_t *qpdb, qpznode_t *node, const dns_name_t *nodename,
|
||||
(unsigned int)(sizeof(*newheader)),
|
||||
qpdb->common.mctx, qpdb->common.rdclass,
|
||||
(dns_rdatatype_t)header->type, flags,
|
||||
&merged);
|
||||
qpdb->maxrrperset, &merged);
|
||||
}
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
/*
|
||||
@ -2147,7 +2148,8 @@ loading_addrdataset(void *arg, const dns_name_t *name,
|
||||
|
||||
loading_addnode(loadctx, name, rdataset->type, rdataset->covers, &node);
|
||||
result = dns_rdataslab_fromrdataset(rdataset, qpdb->common.mctx,
|
||||
®ion, sizeof(dns_slabheader_t));
|
||||
®ion, sizeof(dns_slabheader_t),
|
||||
qpdb->maxrrperset);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
return (result);
|
||||
}
|
||||
@ -4648,7 +4650,8 @@ addrdataset(dns_db_t *db, dns_dbnode_t *dbnode, dns_dbversion_t *dbversion,
|
||||
rdataset->covers != dns_rdatatype_nsec3)));
|
||||
|
||||
result = dns_rdataslab_fromrdataset(rdataset, qpdb->common.mctx,
|
||||
®ion, sizeof(dns_slabheader_t));
|
||||
®ion, sizeof(dns_slabheader_t),
|
||||
qpdb->maxrrperset);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
return (result);
|
||||
}
|
||||
@ -4767,7 +4770,8 @@ subtractrdataset(dns_db_t *db, dns_dbnode_t *dbnode, dns_dbversion_t *dbversion,
|
||||
|
||||
dns_name_copy(&node->name, nodename);
|
||||
result = dns_rdataslab_fromrdataset(rdataset, qpdb->common.mctx,
|
||||
®ion, sizeof(dns_slabheader_t));
|
||||
®ion, sizeof(dns_slabheader_t),
|
||||
0);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
return (result);
|
||||
}
|
||||
@ -5277,6 +5281,15 @@ addglue(dns_db_t *db, dns_dbversion_t *dbversion, dns_rdataset_t *rdataset,
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
static void
|
||||
setmaxrrperset(dns_db_t *db, uint32_t value) {
|
||||
qpzonedb_t *qpdb = (qpzonedb_t *)db;
|
||||
|
||||
REQUIRE(VALID_QPZONE(qpdb));
|
||||
|
||||
qpdb->maxrrperset = value;
|
||||
}
|
||||
|
||||
static dns_dbmethods_t qpdb_zonemethods = {
|
||||
.destroy = qpdb_destroy,
|
||||
.beginload = beginload,
|
||||
@ -5310,6 +5323,7 @@ static dns_dbmethods_t qpdb_zonemethods = {
|
||||
.addglue = addglue,
|
||||
.deletedata = deletedata,
|
||||
.nodefullname = nodefullname,
|
||||
.setmaxrrperset = setmaxrrperset,
|
||||
};
|
||||
|
||||
static void
|
||||
|
@ -1582,6 +1582,7 @@ dns_dbmethods_t dns__rbtdb_cachemethods = {
|
||||
.unlocknode = dns__rbtdb_unlocknode,
|
||||
.expiredata = expiredata,
|
||||
.deletedata = dns__rbtdb_deletedata,
|
||||
.setmaxrrperset = dns__rbtdb_setmaxrrperset,
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -1749,7 +1749,8 @@ loading_addrdataset(void *arg, const dns_name_t *name,
|
||||
}
|
||||
|
||||
result = dns_rdataslab_fromrdataset(rdataset, rbtdb->common.mctx,
|
||||
®ion, sizeof(dns_slabheader_t));
|
||||
®ion, sizeof(dns_slabheader_t),
|
||||
rbtdb->maxrrperset);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
return (result);
|
||||
}
|
||||
@ -2418,6 +2419,7 @@ dns_dbmethods_t dns__rbtdb_zonemethods = {
|
||||
.addglue = addglue,
|
||||
.deletedata = dns__rbtdb_deletedata,
|
||||
.nodefullname = dns__rbtdb_nodefullname,
|
||||
.setmaxrrperset = dns__rbtdb_setmaxrrperset,
|
||||
};
|
||||
|
||||
void
|
||||
|
@ -2780,7 +2780,7 @@ find_header:
|
||||
rbtdb->common.mctx,
|
||||
rbtdb->common.rdclass,
|
||||
(dns_rdatatype_t)header->type, flags,
|
||||
&merged);
|
||||
rbtdb->maxrrperset, &merged);
|
||||
}
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
/*
|
||||
@ -3141,7 +3141,7 @@ delegating_type(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, dns_typepair_t type) {
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
addnoqname(isc_mem_t *mctx, dns_slabheader_t *newheader,
|
||||
addnoqname(isc_mem_t *mctx, dns_slabheader_t *newheader, uint32_t maxrrperset,
|
||||
dns_rdataset_t *rdataset) {
|
||||
isc_result_t result;
|
||||
dns_slabheader_proof_t *noqname = NULL;
|
||||
@ -3152,12 +3152,12 @@ addnoqname(isc_mem_t *mctx, dns_slabheader_t *newheader,
|
||||
result = dns_rdataset_getnoqname(rdataset, &name, &neg, &negsig);
|
||||
RUNTIME_CHECK(result == ISC_R_SUCCESS);
|
||||
|
||||
result = dns_rdataslab_fromrdataset(&neg, mctx, &r1, 0);
|
||||
result = dns_rdataslab_fromrdataset(&neg, mctx, &r1, 0, maxrrperset);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
result = dns_rdataslab_fromrdataset(&negsig, mctx, &r2, 0);
|
||||
result = dns_rdataslab_fromrdataset(&negsig, mctx, &r2, 0, maxrrperset);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
goto cleanup;
|
||||
}
|
||||
@ -3180,7 +3180,7 @@ cleanup:
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
addclosest(isc_mem_t *mctx, dns_slabheader_t *newheader,
|
||||
addclosest(isc_mem_t *mctx, dns_slabheader_t *newheader, uint32_t maxrrperset,
|
||||
dns_rdataset_t *rdataset) {
|
||||
isc_result_t result;
|
||||
dns_slabheader_proof_t *closest = NULL;
|
||||
@ -3191,12 +3191,12 @@ addclosest(isc_mem_t *mctx, dns_slabheader_t *newheader,
|
||||
result = dns_rdataset_getclosest(rdataset, &name, &neg, &negsig);
|
||||
RUNTIME_CHECK(result == ISC_R_SUCCESS);
|
||||
|
||||
result = dns_rdataslab_fromrdataset(&neg, mctx, &r1, 0);
|
||||
result = dns_rdataslab_fromrdataset(&neg, mctx, &r1, 0, maxrrperset);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
result = dns_rdataslab_fromrdataset(&negsig, mctx, &r2, 0);
|
||||
result = dns_rdataslab_fromrdataset(&negsig, mctx, &r2, 0, maxrrperset);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
goto cleanup;
|
||||
}
|
||||
@ -3272,7 +3272,8 @@ dns__rbtdb_addrdataset(dns_db_t *db, dns_dbnode_t *node,
|
||||
}
|
||||
|
||||
result = dns_rdataslab_fromrdataset(rdataset, rbtdb->common.mctx,
|
||||
®ion, sizeof(dns_slabheader_t));
|
||||
®ion, sizeof(dns_slabheader_t),
|
||||
rbtdb->maxrrperset);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
return (result);
|
||||
}
|
||||
@ -3329,7 +3330,7 @@ dns__rbtdb_addrdataset(dns_db_t *db, dns_dbnode_t *node,
|
||||
}
|
||||
if ((rdataset->attributes & DNS_RDATASETATTR_NOQNAME) != 0) {
|
||||
result = addnoqname(rbtdb->common.mctx, newheader,
|
||||
rdataset);
|
||||
rbtdb->maxrrperset, rdataset);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
dns_slabheader_destroy(&newheader);
|
||||
return (result);
|
||||
@ -3337,7 +3338,7 @@ dns__rbtdb_addrdataset(dns_db_t *db, dns_dbnode_t *node,
|
||||
}
|
||||
if ((rdataset->attributes & DNS_RDATASETATTR_CLOSEST) != 0) {
|
||||
result = addclosest(rbtdb->common.mctx, newheader,
|
||||
rdataset);
|
||||
rbtdb->maxrrperset, rdataset);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
dns_slabheader_destroy(&newheader);
|
||||
return (result);
|
||||
@ -3487,7 +3488,8 @@ dns__rbtdb_subtractrdataset(dns_db_t *db, dns_dbnode_t *node,
|
||||
dns__rbtdb_nodefullname(db, node, nodename);
|
||||
|
||||
result = dns_rdataslab_fromrdataset(rdataset, rbtdb->common.mctx,
|
||||
®ion, sizeof(dns_slabheader_t));
|
||||
®ion, sizeof(dns_slabheader_t),
|
||||
0);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
return (result);
|
||||
}
|
||||
@ -4957,3 +4959,12 @@ expire_ttl_headers(dns_rbtdb_t *rbtdb, unsigned int locknum,
|
||||
dns_expire_ttl DNS__DB_FLARG_PASS);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
dns__rbtdb_setmaxrrperset(dns_db_t *db, uint32_t value) {
|
||||
dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
|
||||
|
||||
REQUIRE(VALID_RBTDB(rbtdb));
|
||||
|
||||
rbtdb->maxrrperset = value;
|
||||
}
|
||||
|
@ -114,6 +114,7 @@ struct dns_rbtdb {
|
||||
uint32_t current_serial;
|
||||
uint32_t least_serial;
|
||||
uint32_t next_serial;
|
||||
uint32_t maxrrperset;
|
||||
dns_rbtdb_version_t *current_version;
|
||||
dns_rbtdb_version_t *future_version;
|
||||
rbtdb_versionlist_t open_versions;
|
||||
@ -427,6 +428,12 @@ dns__rbtdb_setttl(dns_slabheader_t *header, dns_ttl_t newttl);
|
||||
* also update the TTL heap accordingly.
|
||||
*/
|
||||
|
||||
void
|
||||
dns__rbtdb_setmaxrrperset(dns_db_t *db, uint32_t value);
|
||||
/*%<
|
||||
* Set the max RRs per RRset limit.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Functions specific to zone databases that are also called from rbtdb.c.
|
||||
*/
|
||||
|
@ -168,7 +168,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.
|
||||
@ -208,6 +209,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);
|
||||
}
|
||||
@ -515,7 +520,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 = NULL, *ostart = NULL, *ncurrent = NULL;
|
||||
unsigned char *tstart = NULL, *tcurrent = NULL, *data = NULL;
|
||||
unsigned int ocount, ncount, count, olength, tlength, tcount, length;
|
||||
@ -554,6 +560,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 */
|
||||
|
@ -643,6 +643,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
|
||||
@ -2336,6 +2338,15 @@ dns_view_getresolver(dns_view_t *view, dns_resolver_t **resolverp) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
dns_view_setudpsize(dns_view_t *view, uint16_t udpsize) {
|
||||
REQUIRE(DNS_VIEW_VALID(view));
|
||||
|
@ -318,6 +318,7 @@ struct dns_zone {
|
||||
uint32_t minretry;
|
||||
|
||||
uint32_t maxrecords;
|
||||
uint32_t maxrrperset;
|
||||
|
||||
dns_remote_t primaries;
|
||||
|
||||
@ -12057,6 +12058,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,
|
||||
@ -14458,6 +14469,7 @@ ns_query(dns_zone_t *zone, dns_rdataset_t *soardataset, dns_stub_t *stub) {
|
||||
goto cleanup;
|
||||
}
|
||||
dns_db_setloop(stub->db, zone->loop);
|
||||
dns_db_setmaxrrperset(stub->db, zone->maxrrperset);
|
||||
}
|
||||
|
||||
result = dns_db_newversion(stub->db, &stub->version);
|
||||
@ -17514,6 +17526,7 @@ zone_replacedb(dns_zone_t *zone, dns_db_t *db, bool dump) {
|
||||
}
|
||||
zone_attachdb(zone, db);
|
||||
dns_db_setloop(zone->db, zone->loop);
|
||||
dns_db_setmaxrrperset(zone->db, zone->maxrrperset);
|
||||
DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_LOADED | DNS_ZONEFLG_NEEDNOTIFY);
|
||||
return (ISC_R_SUCCESS);
|
||||
|
||||
@ -24153,6 +24166,7 @@ dns_zone_makedb(dns_zone_t *zone, dns_db_t **dbp) {
|
||||
}
|
||||
|
||||
dns_db_setloop(db, zone->loop);
|
||||
dns_db_setmaxrrperset(db, zone->maxrrperset);
|
||||
|
||||
*dbp = db;
|
||||
|
||||
|
@ -2372,6 +2372,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,
|
||||
|
Loading…
x
Reference in New Issue
Block a user