RRset limits in zones
  • 23 Jul 2024
  • 3 Minutes to read
  • Contributors
  • Dark
    Light
  • PDF

RRset limits in zones

  • Dark
    Light
  • PDF

Article summary

Two new configuration statements have been added to BIND for version 9.20.0. They are configurable options to allow operators of secondary servers and recursive resolvers to set an upper bound on the growth of data in their zones or caches.

9.18.28

Please note: these statements have also been added to the 9.18 major version in release 9.18.28 because they are required as the mitigation for CVE-2024-1737

The new statements are:

max-records-per-type
max-types-per-name

max-records-per-type

This statement can be used inside the options { block, to set a global value for the server, inside a view { block, if user-defined views are in use, or inside a zone <zone_name> { block, to override both global and view settings, per zone.

From the CHANGES file:

Excessively large rdatasets can slow down database query processing, so a limit has been placed on the number of records that can be stored per rdataset, in a cache or zone database. This is configured with the new "max-records-per-type" option and defaults to 100.

For authoritative servers, what this means in practice is that (by default) BIND will now not load zones containing RRsets where a single owner name has greater than 100 records of the same type. For example:

name	300	IN  A	a.b.c.1
name	300	IN  A	a.b.c.2
...
name	300	IN  A	a.b.c.101

The graph below was derived during testing of the new option and shows the potential performance degradation as the value of this option is increased
Testing max-records-per-type

Lab test results only

The graph above has been produced from in-house testing, not field testing by customers. Therefore it should be taken only as an indication of the general shape of the potential performance hit and does not represent or guarantee values that might be achieved in real world installations.

max-types-per-name

This statement can also be used inside options {, to set a global value for the server, or inside a view {, if user-defined views are in use.

From the CHANGES file:

An excessively large number of rrtypes per owner can slow down database query processing, so a limit has been placed on the number of rrtypes that can be stored per owner (node) in a cache or zone database. This is configured with the new "max-types-per-name" option and defaults to 100. Default 100

For authoritative servers, what this means in practice is that (by default) BIND will now not load zones containing RRsets where a single name has greater than 100 records of different types. For example:

name	300	IN  A	a.b.c.1
name	300	IN  AAAA	aa:bb:cc::1
name	300	IN  NS	ns.mydomain.net.
...

The number of defined RRtypes is currently quite low, at around 50. However, the RRtype field has a length of 16 bits, allowing for 64k possible values. An attacker could fill a zone with many thousand RRs, all with the same name but of different (even though invalid) types, which would cause a server to slow down. Therefore this option limits that exposure by setting a ceiling on the number of different types permitted, per name.

Recursive servers

Recursive servers handle these new limits as follows.

If max-types-per-name is set to a positive number, an attempt to add a new resource record set (from a received response) to a name in cache that already has the specified number of types will temporarily succeed, so that the query can be answered. However, once that operation has completed the newly added RRset will be purged immediately.

Certain high-priority RRtypes - including SOA, CNAME, DNSKEY, and their corresponding signatures - are always cached. If max-types-per-name is set to a very low value then it may be ignored, to allow high-priority types to be cached.

If max-records-per-type is set to a positive number, an attempt to add a new resource record set (from a received response) to a name in cache that already has the specified number of records will fail, the error will be logged and the client will be sent a SERVFAIL response.

Defaults and removal of the limits

The default value of 100 for both statements was chosen as a compromise, given the following operational considerations:

  • A limit that (from experience of zone data) should be high enough for most use cases, including DNSSEC-signed data.
  • A sufficiently low value that would cap performance degradation to no greater than about a third.
  • A value that would be comfortably larger than know or planned RRtypes.

Both of these statements will accept a value of 0, which removes the cap completely and causes BIND to behave as it did prior to 9.20 or 9.18.28.