diff --git a/bin/named/config.c b/bin/named/config.c index 9b34b896c1..d0f70bddbc 100644 --- a/bin/named/config.c +++ b/bin/named/config.c @@ -171,6 +171,7 @@ options {\n\ max-ncache-ttl 10800; /* 3 hours */\n\ max-recursion-depth 7;\n\ max-recursion-queries 32;\n\ + max-query-restarts 11;\n\ max-stale-ttl 86400; /* 1 day */\n\ message-compression yes;\n\ min-ncache-ttl 0; /* 0 hours */\n\ diff --git a/bin/named/server.c b/bin/named/server.c index 4081047762..7a6c837c5f 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -5505,6 +5505,11 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config, INSIST(result == ISC_R_SUCCESS); dns_resolver_setmaxqueries(view->resolver, cfg_obj_asuint32(obj)); + obj = NULL; + result = named_config_get(maps, "max-query-restarts", &obj); + INSIST(result == ISC_R_SUCCESS); + dns_view_setmaxrestarts(view, cfg_obj_asuint32(obj)); + obj = NULL; result = named_config_get(maps, "max-validations-per-fetch", &obj); if (result == ISC_R_SUCCESS) { diff --git a/bin/tests/system/chain/ns7/named.conf.in b/bin/tests/system/chain/ns7/named.conf.in index 87931179d2..0d95bc88c8 100644 --- a/bin/tests/system/chain/ns7/named.conf.in +++ b/bin/tests/system/chain/ns7/named.conf.in @@ -37,11 +37,28 @@ key rndc_key { algorithm @DEFAULT_HMAC@; }; +key restart16 { + secret "1234abcd8765"; + algorithm @DEFAULT_HMAC@; +}; + controls { inet 10.53.0.7 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; }; -zone "." { - type hint; - file "root.hint"; +view restart16 { + match-clients { key restart16; none; }; + max-query-restarts 16; + + zone "." { + type hint; + file "root.hint"; + }; +}; + +view default { + zone "." { + type hint; + file "root.hint"; + }; }; diff --git a/bin/tests/system/chain/tests.sh b/bin/tests/system/chain/tests.sh index 996378d16c..7128b6cd8e 100644 --- a/bin/tests/system/chain/tests.sh +++ b/bin/tests/system/chain/tests.sh @@ -442,11 +442,13 @@ n=$((n + 1)) echo_i "checking CNAME loops are detected (resolver) ($n)" ret=0 $RNDCCMD 10.53.0.7 null --- start test$n --- 2>&1 | sed 's/^/ns7 /' | cat_i -$DIG $DIGOPTS @10.53.0.7 loop.example >dig.out.test$n -grep "status: SERVFAIL" dig.out.test$n >/dev/null || ret=1 -grep "ANSWER: 0" dig.out.test$n >/dev/null || ret=1 -if [ $ret != 0 ]; then echo_i "failed"; fi -status=$((status + ret)) +$DIG $DIGOPTS @10.53.0.7 loop.example >dig.out.1.test$n +grep "status: NOERROR" dig.out.1.test$n >/dev/null || ret=1 +grep "ANSWER: 12" dig.out.1.test$n >/dev/null || ret=1 +# also check with max-query-restarts 16: +$DIG $DIGOPTS @10.53.0.7 -y "${DEFAULT_HMAC}:restart16:1234abcd8765" loop.example >dig.out.2.test$n +grep "status: NOERROR" dig.out.2.test$n >/dev/null || ret=1 +grep "ANSWER: 17" dig.out.2.test$n >/dev/null || ret=1 n=$((n + 1)) echo_i "checking CNAME loops are detected (auth) ($n)" diff --git a/bin/tests/system/checkconf/good.conf.in b/bin/tests/system/checkconf/good.conf.in index 076ecc432d..e326f7ce74 100644 --- a/bin/tests/system/checkconf/good.conf.in +++ b/bin/tests/system/checkconf/good.conf.in @@ -81,6 +81,7 @@ options { check-names primary warn; check-names secondary ignore; max-cache-size 20000000000000; + max-query-restarts 10; nta-lifetime 604800; nta-recheck 604800; validate-except { @@ -112,6 +113,7 @@ view "first" { max-ixfr-ratio unlimited; }; dnssec-validation auto; + max-query-restarts 15; zone-statistics terse; }; view "second" { diff --git a/doc/arm/reference.rst b/doc/arm/reference.rst index b1a5462129..0a3075edc2 100644 --- a/doc/arm/reference.rst +++ b/doc/arm/reference.rst @@ -4601,6 +4601,14 @@ Tuning is a CNAME, then the subsequent lookup for the target of the CNAME is counted separately.) The default is 32. +.. namedconf:statement:: max-query-restarts + :tags: server, query + :short: Sets the maximum number of chained CNAMEs to follow + + This sets the maximum number of successive CNAME targets to follow + when resolving a client query, before terminating the query to avoid a + CNAME loop. Valid values are 1 to 255. The default is 11. + .. namedconf:statement:: notify-delay :tags: transfer, zone :short: Sets the delay (in seconds) between sending sets of NOTIFY messages for a zone. diff --git a/doc/misc/options b/doc/misc/options index 5e5f808704..ff3c95ddf6 100644 --- a/doc/misc/options +++ b/doc/misc/options @@ -182,6 +182,7 @@ options { max-ixfr-ratio ( unlimited | ); max-journal-size ( default | unlimited | ); max-ncache-ttl ; + max-query-restarts ; max-records ; max-records-per-type ; max-recursion-depth ; @@ -471,6 +472,7 @@ view [ ] { max-ixfr-ratio ( unlimited | ); max-journal-size ( default | unlimited | ); max-ncache-ttl ; + max-query-restarts ; max-records ; max-records-per-type ; max-recursion-depth ; diff --git a/lib/isccfg/check.c b/lib/isccfg/check.c index 6c16e34ad9..1bc045d33a 100644 --- a/lib/isccfg/check.c +++ b/lib/isccfg/check.c @@ -2106,6 +2106,20 @@ check_options(const cfg_obj_t *options, const cfg_obj_t *config, } } + obj = NULL; + (void)cfg_map_get(options, "max-query-restarts", &obj); + if (obj != NULL) { + uint32_t restarts = cfg_obj_asuint32(obj); + if (restarts == 0 || restarts > 255) { + cfg_obj_log(obj, logctx, ISC_LOG_ERROR, + "'max-query-restarts' is out of " + "range 1..255)"); + if (result == ISC_R_SUCCESS) { + result = ISC_R_RANGE; + } + } + } + if (actx != NULL) { cfg_aclconfctx_detach(&actx); } diff --git a/lib/isccfg/namedconf.c b/lib/isccfg/namedconf.c index 9daadc48a9..a1b9dc3d1f 100644 --- a/lib/isccfg/namedconf.c +++ b/lib/isccfg/namedconf.c @@ -2153,6 +2153,7 @@ static cfg_clausedef_t view_clauses[] = { { "max-ncache-ttl", &cfg_type_duration, 0 }, { "max-recursion-depth", &cfg_type_uint32, 0 }, { "max-recursion-queries", &cfg_type_uint32, 0 }, + { "max-query-restarts", &cfg_type_uint32, 0 }, { "max-stale-ttl", &cfg_type_duration, 0 }, { "max-udp-size", &cfg_type_uint32, 0 }, { "max-validations-per-fetch", &cfg_type_uint32,