]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Limit the number of addresses returned per ADB find
authorColin Vidal <colin@isc.org>
Thu, 5 Feb 2026 08:46:01 +0000 (09:46 +0100)
committerMichał Kępień <michal@isc.org>
Thu, 7 May 2026 11:09:18 +0000 (13:09 +0200)
Add a hard limit on the number of addresses that ADB returns from a
single NS lookup (dns_adbfind_t).  This mitigates a flood attack
where an attacker controls a zone with many addresses for a
nameserver, each returning an invalid response.  The global
max-query count (default 50) also limits this, but significant harm
can be done before that limit is reached.

The default limit is now 6 (v4 and/or v6) addresses for an ADB find (so,
ADB looking up for A/AAAA addresses of a name server name). It can be
overridden for testing via 'named -T adbaddrslimit=N'.

(cherry picked from commit 3ec37fc69356ee682bee7f67940613ac31d93d7b)

bin/named/main.c
lib/dns/adb.c

index f3b2ec80f5a9a75b7a6abb7e768bac3ab23ad536..b298d6e98d2078731d83a96b19d0f8f17be86e3f 100644 (file)
@@ -123,6 +123,7 @@ extern unsigned int dns_zone_mkey_month;
 extern unsigned int dns_adb_entrywindow;
 extern unsigned int dns_adb_cachemin;
 extern size_t dns_dispatch_tcppipelining;
+extern size_t dns_adb_addrslimit;
 
 static bool want_stats = false;
 static char program_name[NAME_MAX] = "named";
@@ -817,6 +818,13 @@ parse_T_opt(char *option) {
                                              "least 1");
                }
                dns_dispatch_tcppipelining = pipelining;
+       } else if (!strncmp(option, "adbaddrslimit=", 14)) {
+               size_t adb_addrslimit = atoi(option + 14);
+               if (adb_addrslimit < 1) {
+                       named_main_earlyfatal("adbaddrslimit must be at "
+                                             "least 1");
+               }
+               dns_adb_addrslimit = adb_addrslimit;
        } else {
                fprintf(stderr, "unknown -T flag '%s'\n", option);
        }
index 50d4d83bf3056c3887f2a3142ce22516c4c18f80..1514fb46b9b1b398b62efdc5af9aedbf64d4fda4 100644 (file)
 
 #define DNS_ADB_MINADBSIZE (1024U * 1024U) /*%< 1 Megabyte */
 
+/*
+ * Default and override for the per-find address limit, the sum of the number of
+ * A and AAAA RR from an ADB NS name resolution.  When non-zero, this value is
+ * used instead of the default.  Can be set via 'named -T adbaddrslimit=N' for
+ * testing.
+ */
+#define DEFAULT_ADDRSLIMIT 6
+size_t dns_adb_addrslimit = 0;
+
 typedef ISC_LIST(dns_adbname_t) dns_adbnamelist_t;
 typedef struct dns_adbnamehook dns_adbnamehook_t;
 typedef ISC_LIST(dns_adbnamehook_t) dns_adbnamehooklist_t;
@@ -1473,6 +1482,9 @@ static void
 copy_namehook_lists(dns_adb_t *adb, dns_adbfind_t *find, dns_adbname_t *name) {
        dns_adbnamehook_t *namehook = NULL;
        dns_adbentry_t *entry = NULL;
+       size_t count = 0;
+       size_t limit = dns_adb_addrslimit != 0 ? dns_adb_addrslimit
+                                              : DEFAULT_ADDRSLIMIT;
 
        if ((find->options & DNS_ADBFIND_INET) != 0) {
                namehook = ISC_LIST_HEAD(name->v4);
@@ -1493,6 +1505,12 @@ copy_namehook_lists(dns_adb_t *adb, dns_adbfind_t *find, dns_adbname_t *name) {
                         * Found a valid entry.  Add it to the find's list.
                         */
                        ISC_LIST_APPEND(find->list, addrinfo, publink);
+
+                       if (++count >= limit) {
+                               DP(ISC_LOG_DEBUG(3), "skipping addresses");
+                               return;
+                       }
+
                nextv4:
                        namehook = ISC_LIST_NEXT(namehook, name_link);
                }
@@ -1517,6 +1535,12 @@ copy_namehook_lists(dns_adb_t *adb, dns_adbfind_t *find, dns_adbname_t *name) {
                         * Found a valid entry.  Add it to the find's list.
                         */
                        ISC_LIST_APPEND(find->list, addrinfo, publink);
+
+                       if (++count >= limit) {
+                               DP(ISC_LOG_DEBUG(3), "skipping addresses");
+                               return;
+                       }
+
                nextv6:
                        namehook = ISC_LIST_NEXT(namehook, name_link);
                }