mirror of
https://github.com/isc-projects/bind9.git
synced 2026-05-28 04:34:54 -04:00
chg: usr: Limit the number of glue records cached from a referral
When a delegation response contained many glue addresses per listed nameserver, all of them were cached without a per-nameserver bound, inflating resolver cache memory beyond what resolution could ever use. The cache now keeps at most 20 IPv4 and 20 IPv6 glue addresses per nameserver from a delegation. Closes #5701 Merge branch '5701-limit-the-number-of-GLUE-records-9.20' into 'bind-9.20' See merge request isc-projects/bind9!11972
This commit is contained in:
commit
eb401f6b92
8 changed files with 222 additions and 34 deletions
15
bin/tests/system/cap_glues/ns1/named.conf.j2
Normal file
15
bin/tests/system/cap_glues/ns1/named.conf.j2
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
options {
|
||||
query-source address 10.53.0.1;
|
||||
notify-source 10.53.0.1;
|
||||
transfer-source 10.53.0.1;
|
||||
port @PORT@;
|
||||
pid-file "named.pid";
|
||||
listen-on { 10.53.0.1; };
|
||||
recursion no;
|
||||
dnssec-validation no;
|
||||
};
|
||||
|
||||
zone "." {
|
||||
type primary;
|
||||
file "root.db";
|
||||
};
|
||||
13
bin/tests/system/cap_glues/ns1/root.db
Normal file
13
bin/tests/system/cap_glues/ns1/root.db
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
$TTL 300
|
||||
. IN SOA dnshoster.root-servers.nil. a.root.servers.nil. (
|
||||
2010 ; serial
|
||||
600 ; refresh
|
||||
600 ; retry
|
||||
1200 ; expire
|
||||
600 ; minimum
|
||||
)
|
||||
. NS a.root-servers.nil.
|
||||
a.root-servers.nil. A 10.53.0.1
|
||||
|
||||
tld. NS ns.tld.
|
||||
ns.tld. A 10.53.0.2
|
||||
15
bin/tests/system/cap_glues/ns2/named.conf.j2
Normal file
15
bin/tests/system/cap_glues/ns2/named.conf.j2
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
options {
|
||||
query-source address 10.53.0.2;
|
||||
notify-source 10.53.0.2;
|
||||
transfer-source 10.53.0.2;
|
||||
port @PORT@;
|
||||
pid-file "named.pid";
|
||||
listen-on { 10.53.0.2; };
|
||||
recursion no;
|
||||
dnssec-validation no;
|
||||
};
|
||||
|
||||
zone "tld" {
|
||||
type primary;
|
||||
file "tld.db";
|
||||
};
|
||||
63
bin/tests/system/cap_glues/ns2/tld.db
Normal file
63
bin/tests/system/cap_glues/ns2/tld.db
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
$TTL 300
|
||||
@ IN SOA hoster.tld. ns.tld. (
|
||||
2010 ; serial
|
||||
600 ; refresh
|
||||
600 ; retry
|
||||
1200 ; expire
|
||||
600 ; minimum
|
||||
)
|
||||
|
||||
NS ns
|
||||
ns A 10.52.0.2
|
||||
|
||||
example NS ns.example
|
||||
|
||||
ns.example A 10.53.0.20
|
||||
ns.example A 10.53.0.21
|
||||
ns.example A 10.53.0.22
|
||||
ns.example A 10.53.0.23
|
||||
ns.example A 10.53.0.24
|
||||
ns.example A 10.53.0.25
|
||||
ns.example A 10.53.0.26
|
||||
ns.example A 10.53.0.27
|
||||
ns.example A 10.53.0.28
|
||||
ns.example A 10.53.0.29
|
||||
ns.example A 10.53.0.30
|
||||
ns.example A 10.53.0.31
|
||||
ns.example A 10.53.0.32
|
||||
ns.example A 10.53.0.33
|
||||
ns.example A 10.53.0.34
|
||||
ns.example A 10.53.0.35
|
||||
ns.example A 10.53.0.36
|
||||
ns.example A 10.53.0.37
|
||||
ns.example A 10.53.0.38
|
||||
ns.example A 10.53.0.39
|
||||
ns.example A 10.53.0.40
|
||||
ns.example A 10.53.0.41
|
||||
ns.example A 10.53.0.42
|
||||
ns.example A 10.53.0.43
|
||||
|
||||
ns.example AAAA 2001:db8::20
|
||||
ns.example AAAA 2001:db8::21
|
||||
ns.example AAAA 2001:db8::22
|
||||
ns.example AAAA 2001:db8::23
|
||||
ns.example AAAA 2001:db8::24
|
||||
ns.example AAAA 2001:db8::25
|
||||
ns.example AAAA 2001:db8::26
|
||||
ns.example AAAA 2001:db8::27
|
||||
ns.example AAAA 2001:db8::28
|
||||
ns.example AAAA 2001:db8::29
|
||||
ns.example AAAA 2001:db8::30
|
||||
ns.example AAAA 2001:db8::31
|
||||
ns.example AAAA 2001:db8::32
|
||||
ns.example AAAA 2001:db8::33
|
||||
ns.example AAAA 2001:db8::34
|
||||
ns.example AAAA 2001:db8::35
|
||||
ns.example AAAA 2001:db8::36
|
||||
ns.example AAAA 2001:db8::37
|
||||
ns.example AAAA 2001:db8::38
|
||||
ns.example AAAA 2001:db8::39
|
||||
ns.example AAAA 2001:db8::40
|
||||
ns.example AAAA 2001:db8::41
|
||||
ns.example AAAA 2001:db8::42
|
||||
ns.example AAAA 2001:db8::43
|
||||
31
bin/tests/system/cap_glues/ns3/named.conf.j2
Normal file
31
bin/tests/system/cap_glues/ns3/named.conf.j2
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
options {
|
||||
query-source address 10.53.0.3;
|
||||
notify-source 10.53.0.3;
|
||||
transfer-source 10.53.0.3;
|
||||
port @PORT@;
|
||||
pid-file "named.pid";
|
||||
listen-on { 10.53.0.3; };
|
||||
recursion yes;
|
||||
dnssec-validation no;
|
||||
};
|
||||
|
||||
server 10.53.0.2 {
|
||||
// Avoid truncation of the additional section without TC, because some
|
||||
// mandatory glues would already be in the additional section, thus the
|
||||
// resolver wouldn't try again using TCP by itself.
|
||||
tcp-only yes;
|
||||
};
|
||||
|
||||
zone "." {
|
||||
type hint;
|
||||
file "root.hint";
|
||||
};
|
||||
|
||||
key rndc_key {
|
||||
secret "1234abcd8765";
|
||||
algorithm @DEFAULT_HMAC@;
|
||||
};
|
||||
|
||||
controls {
|
||||
inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
|
||||
};
|
||||
3
bin/tests/system/cap_glues/ns3/root.hint
Normal file
3
bin/tests/system/cap_glues/ns3/root.hint
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
$TTL 999999
|
||||
. IN NS a.root-servers.nil.
|
||||
a.root-servers.nil. IN A 10.53.0.1
|
||||
33
bin/tests/system/cap_glues/tests_cap_glues.py
Normal file
33
bin/tests/system/cap_glues/tests_cap_glues.py
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
#
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
#
|
||||
# See the COPYRIGHT file distributed with this work for additional
|
||||
# information regarding copyright ownership.
|
||||
|
||||
import isctest
|
||||
|
||||
|
||||
def test_cap_glues(ns3):
|
||||
msg = isctest.query.create("example.tld.", "A")
|
||||
isctest.query.udp(msg, ns3.ip)
|
||||
|
||||
with ns3.watch_log_from_here() as watcher:
|
||||
ns3.rndc("dumpdb -cache")
|
||||
watcher.wait_for_line("dumpdb complete")
|
||||
db = isctest.text.TextFile(f"{ns3.identifier}/named_dump.db")
|
||||
|
||||
allowed_suffixes = range(20, 40)
|
||||
skipped_suffixes = range(40, 44)
|
||||
|
||||
for n in allowed_suffixes:
|
||||
assert len(db.grep(f"10.53.0.{n}")) >= 1
|
||||
assert len(db.grep(f"2001:db8::{n}")) >= 1
|
||||
|
||||
for n in skipped_suffixes:
|
||||
assert len(db.grep(f"10.53.0.{n}")) == 0
|
||||
assert len(db.grep(f"2001:db8::{n}")) == 0
|
||||
|
|
@ -236,6 +236,15 @@
|
|||
*/
|
||||
#define NS_PROCESSING_LIMIT 20
|
||||
|
||||
/*
|
||||
* Cap on the number of glue addresses cached per NS owner from a referral.
|
||||
* The resolver only ever tries a handful of addresses per NS, so accepting
|
||||
* more than this from a single referral is wasted memory. Each NS owner
|
||||
* may contribute at most DELEG_MAX_GLUES_PER_NS A and DELEG_MAX_GLUES_PER_NS
|
||||
* AAAA glue records.
|
||||
*/
|
||||
#define DELEG_MAX_GLUES_PER_NS 20
|
||||
|
||||
/* Hash table for zone counters */
|
||||
#ifndef RES_DOMAIN_HASH_BITS
|
||||
#define RES_DOMAIN_HASH_BITS 12
|
||||
|
|
@ -6762,12 +6771,52 @@ unlock:
|
|||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Truncate 'rdataset' to at most 'max' rdata, by unlinking the trailing
|
||||
* rdata from the underlying rdatalist. The rdataset must be backed by a
|
||||
* dns_rdatalist, which is the case for rdatasets parsed from a message.
|
||||
*/
|
||||
static void
|
||||
truncate_rdataset(dns_rdataset_t *rdataset, unsigned int max) {
|
||||
dns_rdatalist_t *rdatalist = NULL;
|
||||
dns_rdata_t *keep = NULL;
|
||||
dns_rdata_t *next = NULL;
|
||||
unsigned int i;
|
||||
|
||||
REQUIRE(max > 0);
|
||||
|
||||
if (dns_rdataset_count(rdataset) <= max) {
|
||||
return;
|
||||
}
|
||||
|
||||
dns_rdatalist_fromrdataset(rdataset, &rdatalist);
|
||||
|
||||
keep = ISC_LIST_HEAD(rdatalist->rdata);
|
||||
for (i = 1; i < max && keep != NULL; i++) {
|
||||
keep = ISC_LIST_NEXT(keep, link);
|
||||
}
|
||||
INSIST(keep != NULL);
|
||||
|
||||
next = ISC_LIST_NEXT(keep, link);
|
||||
while (next != NULL) {
|
||||
dns_rdata_t *unlinked = next;
|
||||
next = ISC_LIST_NEXT(next, link);
|
||||
ISC_LIST_UNLINK(rdatalist->rdata, unlinked, link);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
mark_related(dns_name_t *name, dns_rdataset_t *rdataset, bool external,
|
||||
bool gluing) {
|
||||
name->attributes.cache = true;
|
||||
if (gluing) {
|
||||
rdataset->trust = dns_trust_glue;
|
||||
if (rdataset->type == dns_rdatatype_a ||
|
||||
rdataset->type == dns_rdatatype_aaaa)
|
||||
{
|
||||
truncate_rdataset(rdataset, DELEG_MAX_GLUES_PER_NS);
|
||||
}
|
||||
|
||||
/*
|
||||
* Glue with 0 TTL causes problems. We force the TTL to
|
||||
* 1 second to prevent this.
|
||||
|
|
@ -6901,12 +6950,6 @@ check_section(void *arg, const dns_name_t *addname, dns_rdatatype_t type,
|
|||
|
||||
REQUIRE(VALID_FCTX(fctx));
|
||||
|
||||
#if CHECK_FOR_GLUE_IN_ANSWER
|
||||
if (section == DNS_SECTION_ANSWER && type != dns_rdatatype_a) {
|
||||
return ISC_R_SUCCESS;
|
||||
}
|
||||
#endif /* if CHECK_FOR_GLUE_IN_ANSWER */
|
||||
|
||||
gluing = (GLUING(fctx) || (fctx->type == dns_rdatatype_ns &&
|
||||
dns_name_equal(fctx->name, dns_rootname)));
|
||||
|
||||
|
|
@ -6962,18 +7005,6 @@ check_related(void *arg, const dns_name_t *addname, dns_rdatatype_t type,
|
|||
return check_section(arg, addname, type, found, DNS_SECTION_ADDITIONAL);
|
||||
}
|
||||
|
||||
#ifndef CHECK_FOR_GLUE_IN_ANSWER
|
||||
#define CHECK_FOR_GLUE_IN_ANSWER 0
|
||||
#endif /* ifndef CHECK_FOR_GLUE_IN_ANSWER */
|
||||
|
||||
#if CHECK_FOR_GLUE_IN_ANSWER
|
||||
static isc_result_t
|
||||
check_answer(void *arg, const dns_name_t *addname, dns_rdatatype_t type,
|
||||
dns_rdataset_t *found) {
|
||||
return check_section(arg, addname, type, found, DNS_SECTION_ANSWER);
|
||||
}
|
||||
#endif /* if CHECK_FOR_GLUE_IN_ANSWER */
|
||||
|
||||
static bool
|
||||
is_answeraddress_allowed(dns_view_t *view, dns_name_t *name,
|
||||
dns_rdataset_t *rdataset) {
|
||||
|
|
@ -9518,22 +9549,6 @@ rctx_referral(respctx_t *rctx) {
|
|||
*/
|
||||
(void)dns_rdataset_additionaldata(rctx->ns_rdataset, rctx->ns_name,
|
||||
check_related, rctx, 0);
|
||||
#if CHECK_FOR_GLUE_IN_ANSWER
|
||||
/*
|
||||
* Look in the answer section for "glue" that is incorrectly
|
||||
* returned as a answer. This is needed if the server also
|
||||
* minimizes the response size by not adding records to the
|
||||
* additional section that are in the answer section or if
|
||||
* the record gets dropped due to message size constraints.
|
||||
*/
|
||||
if (rctx->glue_in_answer &&
|
||||
(fctx->type == dns_rdatatype_aaaa || fctx->type == dns_rdatatype_a))
|
||||
{
|
||||
(void)dns_rdataset_additionaldata(rctx->ns_rdataset,
|
||||
rctx->ns_name, check_answer,
|
||||
fctx, 0);
|
||||
}
|
||||
#endif /* if CHECK_FOR_GLUE_IN_ANSWER */
|
||||
FCTX_ATTR_CLR(fctx, FCTX_ATTR_GLUING);
|
||||
|
||||
/*
|
||||
|
|
|
|||
Loading…
Reference in a new issue