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\
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);
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);
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.
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>;
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-validation-failures-per-fetch <integer>; // experimental
max-validations-per-fetch <integer>; // experimental
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-validation-failures-per-fetch <integer>; // experimental
max-validations-per-fetch <integer>; // experimental
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> ); // deprecated
notify ( explicit | master-only | primary-only | <boolean> );
notify-delay <integer>;
masterfile-style ( full | relative );
max-records <integer>;
max-records-per-type <integer>;
+ max-types-per-name <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> );
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>;
forwarders [ port <integer> ] [ tls <string> ] { ( <ipv4_address> | <ipv6_address> ) [ port <integer> ] [ tls <string> ]; ... };
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> );
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>;
dns_ttl_t serve_stale_refresh;
isc_stats_t *stats;
uint32_t maxrrperset;
+ uint32_t maxtypepername;
};
/***
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);
/*
* XXX this is only used by the RBT cache, and can
}
}
+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
(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);
+ }
+}
* 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);
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);
+ void (*setmaxtypepername)(dns_db_t *db, uint32_t value);
} dns_dbmethods_t;
typedef isc_result_t (*dns_dbcreatefunc_t)(isc_mem_t *mctx,
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.
+ * 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.
+ */
+
+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, and if there are already 'value' RR types
+ * stored at a given node, then any subsequent attempt to add an rdataset
+ * with a new RR type will return ISC_R_TOOMANYRECORDS.
*/
ISC_LANG_ENDDECLS
dns_badcache_t *failcache;
unsigned int udpsize;
uint32_t maxrrperset;
+ uint32_t maxtypepername;
/*
* Configurable data for server use only,
* 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.
+ */
+
void
dns_view_setudpsize(dns_view_t *view, uint16_t udpsize);
/*%<
*\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);
/*%<
/* Locked by lock. */
unsigned int active;
- uint32_t maxrrperset; /* Maximum RRs per RRset */
+ uint32_t maxrrperset; /* Maximum RRs per RRset */
+ uint32_t maxtypepername; /* Maximum number of RR types per owner */
/*
* The time after a failed lookup, where stale answers from cache
dns_typepair_t negtype = 0, sigtype;
dns_trust_t trust;
int idx;
+ uint32_t ntypes;
if ((options & DNS_DBADD_FORCE) != 0) {
trust = dns_trust_ultimate;
{
mark_ancient(topheader);
}
+ ntypes = 0; /* Always add the negative entry */
goto find_header;
}
/*
* check for an extant non-ancient NODATA ncache
* entry which covers the same type as the RRSIG.
*/
+ ntypes = 0;
for (topheader = qpnode->data; topheader != NULL;
topheader = topheader->next)
{
+ ++ntypes;
if ((topheader->type == RDATATYPE_NCACHEANY) ||
(newheader->type == sigtype &&
topheader->type ==
}
}
+ ntypes = 0;
for (topheader = qpnode->data; topheader != NULL;
topheader = topheader->next)
{
+ ++ntypes;
+
if (prio_type(topheader->type)) {
prioheader = topheader;
}
/*
* No rdatasets of the given type exist at the node.
*/
+ if (trust != dns_trust_ultimate &&
+ qpdb->maxtypepername > 0 &&
+ ntypes >= qpdb->maxtypepername)
+ {
+ dns_slabheader_destroy(&newheader);
+ return (DNS_R_TOOMANYRECORDS);
+ }
+
INSIST(newheader->down == NULL);
if (prio_type(newheader->type)) {
qpdb->maxrrperset = value;
}
+static void
+setmaxtypepername(dns_db_t *db, uint32_t value) {
+ qpcache_t *qpdb = (qpcache_t *)db;
+
+ REQUIRE(VALID_QPDB(qpdb));
+
+ qpdb->maxtypepername = value;
+}
+
static dns_dbmethods_t qpdb_cachemethods = {
.destroy = qpdb_destroy,
.findnode = findnode,
.expiredata = expiredata,
.deletedata = deletedata,
.setmaxrrperset = setmaxrrperset,
+ .setmaxtypepername = setmaxtypepername,
};
static void
uint32_t current_serial;
uint32_t least_serial;
uint32_t next_serial;
- uint32_t maxrrperset;
+ uint32_t maxrrperset; /* Maximum RRs per RRset */
+ uint32_t maxtypepername; /* Maximum number of RR types per owner */
qpz_version_t *current_version;
qpz_version_t *future_version;
qpz_versionlist_t open_versions;
unsigned char *merged = NULL;
isc_result_t result;
bool merge = false;
+ uint32_t ntypes;
if ((options & DNS_DBADD_MERGE) != 0) {
REQUIRE(version != NULL);
changed = add_changed(newheader, version DNS__DB_FLARG_PASS);
}
+ ntypes = 0;
for (topheader = node->data; topheader != NULL;
topheader = topheader->next)
{
+ ++ntypes;
if (prio_type(topheader->type)) {
prioheader = topheader;
}
/*
* No rdatasets of the given type exist at the node.
*/
+
+ if (qpdb->maxtypepername > 0 &&
+ ntypes >= qpdb->maxtypepername)
+ {
+ dns_slabheader_destroy(&newheader);
+ return (DNS_R_TOOMANYRECORDS);
+ }
+
INSIST(newheader->down == NULL);
if (prio_type(newheader->type)) {
qpdb->maxrrperset = value;
}
+static void
+setmaxtypepername(dns_db_t *db, uint32_t value) {
+ qpzonedb_t *qpdb = (qpzonedb_t *)db;
+
+ REQUIRE(VALID_QPZONE(qpdb));
+
+ qpdb->maxtypepername = value;
+}
+
static dns_dbmethods_t qpdb_zonemethods = {
.destroy = qpdb_destroy,
.beginload = beginload,
.deletedata = deletedata,
.nodefullname = nodefullname,
.setmaxrrperset = setmaxrrperset,
+ .setmaxtypepername = setmaxtypepername,
};
static void
.expiredata = expiredata,
.deletedata = dns__rbtdb_deletedata,
.setmaxrrperset = dns__rbtdb_setmaxrrperset,
+ .setmaxtypepername = dns__rbtdb_setmaxtypepername,
};
/*
.deletedata = dns__rbtdb_deletedata,
.nodefullname = dns__rbtdb_nodefullname,
.setmaxrrperset = dns__rbtdb_setmaxrrperset,
+ .setmaxtypepername = dns__rbtdb_setmaxtypepername,
};
void
dns_typepair_t negtype = 0, sigtype;
dns_trust_t trust;
int idx;
+ uint32_t ntypes = 0;
if ((options & DNS_DBADD_MERGE) != 0) {
REQUIRE(rbtversion != NULL);
{
mark_ancient(topheader);
}
+ ntypes = 0; /* Always add the negative entry */
goto find_header;
}
/*
* 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 == RDATATYPE_NCACHEANY) ||
(newheader->type == sigtype &&
topheader->type ==
}
}
+ ntypes = 0;
for (topheader = rbtnode->data; topheader != NULL;
topheader = topheader->next)
{
+ ++ntypes;
if (prio_type(topheader->type)) {
prioheader = topheader;
}
/*
* No rdatasets of the given type exist at the node.
*/
+
+ if (rbtdb->maxtypepername > 0 &&
+ ntypes >= rbtdb->maxtypepername)
+ {
+ dns_slabheader_destroy(&newheader);
+ return (DNS_R_TOOMANYRECORDS);
+ }
+
INSIST(newheader->down == NULL);
if (prio_type(newheader->type)) {
rbtdb->maxrrperset = value;
}
+
+void
+dns__rbtdb_setmaxtypepername(dns_db_t *db, uint32_t maxtypepername) {
+ dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
+
+ REQUIRE(VALID_RBTDB(rbtdb));
+
+ rbtdb->maxtypepername = maxtypepername;
+}
uint32_t least_serial;
uint32_t next_serial;
uint32_t maxrrperset;
+ uint32_t maxtypepername;
dns_rbtdb_version_t *current_version;
dns_rbtdb_version_t *future_version;
rbtdb_versionlist_t open_versions;
*/
void
-dns__rbtdb_setmaxrrperset(dns_db_t *db, uint32_t value);
+dns__rbtdb_setmaxrrperset(dns_db_t *db, uint32_t maxrrperset);
+/*%<
+ * Set the max RRs per RRset limit.
+ */
+
+void
+dns__rbtdb_setmaxtypepername(dns_db_t *db, uint32_t maxtypepername);
/*%<
* Set the max RRs per RRset limit.
*/
INSIST(DNS_DB_VALID(view->cachedb));
dns_cache_setmaxrrperset(view->cache, view->maxrrperset);
+ dns_cache_setmaxtypepername(view->cache, view->maxtypepername);
}
bool
}
}
+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);
+ }
+}
+
void
dns_view_setudpsize(dns_view_t *view, uint16_t udpsize) {
REQUIRE(DNS_VIEW_VALID(view));
uint32_t maxrecords;
uint32_t maxrrperset;
+ uint32_t maxtypepername;
dns_remote_t primaries;
}
}
+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,
}
dns_db_setloop(stub->db, zone->loop);
dns_db_setmaxrrperset(stub->db, zone->maxrrperset);
+ dns_db_setmaxtypepername(stub->db,
+ zone->maxtypepername);
}
result = dns_db_newversion(stub->db, &stub->version);
zone_attachdb(zone, db);
dns_db_setloop(zone->db, zone->loop);
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);
dns_db_setloop(db, zone->loop);
dns_db_setmaxrrperset(db, zone->maxrrperset);
+ dns_db_setmaxtypepername(db, zone->maxtypepername);
*dbp = db;
{ "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,