[9.18] new: usr: Add a new option to configure the maximum number of outgoing queries per client request

The configuration option 'max-query-count' sets how many outgoing queries per client request is allowed. The existing 'max-recursion-queries' is the number of permissible queries for a single name and is reset on every CNAME redirection. This new option is a global limit on the client request. The default is 200.

This allows us to send a bit more queries while looking up a single name. The default for 'max-recursion-queries' is changed from 32 to 50.

Closes #4980 Closes #4921

Backport of MR !9737

Merge branch 'backport-4980-global-limit-outgoing-queries-9.18' into 'bind-9.18'

See merge request isc-projects/bind9!9847
This commit is contained in:
Matthijs Mekking
2024-12-06 15:17:58 +00:00
36 changed files with 674 additions and 54 deletions
+2 -1
View File
@@ -174,7 +174,8 @@ options {\n\
max-clients-per-query 100;\n\
max-ncache-ttl 10800; /* 3 hours */\n\
max-recursion-depth 7;\n\
max-recursion-queries 32;\n\
max-recursion-queries 50;\n\
max-query-count 200;\n\
max-query-restarts 11;\n\
max-stale-ttl 86400; /* 1 day */\n\
message-compression yes;\n\
+6 -1
View File
@@ -5678,6 +5678,11 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config,
INSIST(result == ISC_R_SUCCESS);
dns_view_setmaxrestarts(view, cfg_obj_asuint32(obj));
obj = NULL;
result = named_config_get(maps, "max-query-count", &obj);
INSIST(result == ISC_R_SUCCESS);
dns_view_setmaxqueries(view, cfg_obj_asuint32(obj));
obj = NULL;
result = named_config_get(maps, "fetches-per-zone", &obj);
INSIST(result == ISC_R_SUCCESS);
@@ -7405,7 +7410,7 @@ tat_send(isc_task_t *task, isc_event_t *event) {
if (result == ISC_R_SUCCESS) {
result = dns_resolver_createfetch(
tat->view->resolver, tatname, dns_rdatatype_null,
domain, &nameservers, NULL, NULL, 0, 0, 0, NULL,
domain, &nameservers, NULL, NULL, 0, 0, 0, NULL, NULL,
tat->task, tat_done, tat, &tat->rdataset,
&tat->sigrdataset, &tat->fetch);
}
+1
View File
@@ -99,6 +99,7 @@ TESTS = \
autosign \
builtin \
cacheclean \
camp \
case \
catz \
cds \
+31
View File
@@ -0,0 +1,31 @@
/*
* 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.
*/
// NS1
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; };
listen-on-v6 { none; };
recursion no;
notify yes;
};
zone "." {
type primary;
file "root.db";
};
+51
View File
@@ -0,0 +1,51 @@
; 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.
$TTL 300
. IN SOA gson.nominum.com. a.root.servers.nil. (
2000042100 ; serial
600 ; refresh
600 ; retry
1200 ; expire
600 ; minimum
)
. NS a.root-servers.nil.
a.root-servers.nil. A 10.53.0.1
tld0. NS ns.tld0.
ns.tld0. A 10.53.0.2
tld1. NS ns.tld1.
ns.tld1. A 10.53.0.2
tld2. NS ns.tld2.
ns.tld2. A 10.53.0.2
tld3. NS ns.tld3.
ns.tld3. A 10.53.0.2
tld4. NS ns.tld4.
ns.tld4. A 10.53.0.2
tld5. NS ns.tld5.
ns.tld5. A 10.53.0.2
tld6. NS ns.tld6.
ns.tld6. A 10.53.0.2
tld7. NS ns.tld7.
ns.tld7. A 10.53.0.2
tld8. NS ns.tld8.
ns.tld8. A 10.53.0.2
tld9. NS ns.tld9.
ns.tld9. A 10.53.0.2
+31
View File
@@ -0,0 +1,31 @@
/*
* 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.
*/
// NS2
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; };
listen-on-v6 { none; };
recursion no;
notify yes;
};
zone "tld0" {
type primary;
file "tld0.db";
};
+57
View File
@@ -0,0 +1,57 @@
#!/bin/sh -e
# 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.
# shellcheck source=conf.sh
. ../../conf.sh
echo_i "ns2/setup.sh"
cp template.db.in tld0.db
echo "final.tld0. IN NS ns.final.tld0." >>tld0.db
echo "ns.final.tld0. IN A 10.53.0.3" >>tld0.db
DEPTH=5
tld=1
while [ $tld -le $DEPTH ]; do
cat >>"named.conf" <<EOF
zone "tld${tld}" {
type primary;
file "tld${tld}.db";
};
EOF
cp template.db.in tld${tld}.db
label=0
while [ $label -le $DEPTH ]; do
echo "label${label}.tld${tld}. IN NS ns.label${label}.tld${tld}." >>tld${tld}.db
echo "ns.label${label}.tld${tld}. IN A 10.53.0.3" >>tld${tld}.db
echo "" >>tld${tld}.db
label=$((label + 1))
done
tld=$((tld + 1))
done
goto=1
tld=1
while [ $goto -le $DEPTH ]; do
echo "goto${goto}.tld${tld}. IN NS ns.goto${goto}.tld${tld}." >>tld${tld}.db
echo "ns.goto${goto}.tld${tld}. IN A 10.53.0.3" >>tld${tld}.db
echo "" >>tld${tld}.db
goto=$((goto + 1))
done
+26
View File
@@ -0,0 +1,26 @@
; 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.
$TTL 300
@ IN SOA mname1. . (
1 ; serial
20 ; refresh (20 seconds)
20 ; retry (20 seconds)
1814400 ; expire (3 weeks)
3600 ; minimum (1 hour)
)
NS ns2
ns2 A 10.53.0.2
NS ns
ns A 10.53.0.2
; camp attack
+42
View File
@@ -0,0 +1,42 @@
/*
* 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.
*/
// NS3
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; };
listen-on-v6 { none; };
recursion yes;
dnssec-validation no;
max-query-count 150;
};
key rndc_key {
secret "1234abcd8765";
algorithm @DEFAULT_HMAC@;
};
controls {
inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
};
zone "final.tld0" {
type primary;
file "final.tld0.db";
};
+79
View File
@@ -0,0 +1,79 @@
#!/bin/sh -e
# 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.
# shellcheck source=conf.sh
. ../../conf.sh
echo_i "ns3/setup.sh"
cp template.db.in final.tld0.db
echo "q.final.tld0. IN A 1.2.3.4" >>final.tld0.db
DEPTH=5
tld=1
while [ $tld -le $DEPTH ]; do
nexttld=$((tld + 1))
label=1
while [ $label -le $DEPTH ]; do
nextlabel=$((label + 1))
cat >>"named.conf" <<EOF
zone "label${label}.tld${tld}" {
type primary;
file "label${label}.tld${tld}.db";
};
EOF
cp template.db.in label${label}.tld${tld}.db
if [ $label -eq $DEPTH ] && [ $tld -eq $DEPTH ]; then
echo "q.label${label}.tld${tld}. IN CNAME q.goto1.tld1." >>label${label}.tld${tld}.db
elif [ $tld -eq $DEPTH ]; then
nextlabel=$((label + 1))
echo "q.label${label}.tld${tld}. IN CNAME q.label${nextlabel}.tld1." >>label${label}.tld${tld}.db
else
echo "q.label${label}.tld${tld}. IN CNAME q.label${label}.tld${nexttld}." >>label${label}.tld${tld}.db
fi
label=$nextlabel
done
echo "" >>label${label}.tld${tld}.db
tld=$nexttld
done
goto=1
tld=1
while [ $goto -le $DEPTH ]; do
nextgoto=$((goto + 1))
cat >>"named.conf" <<EOF
zone "goto${goto}.tld${tld}" {
type primary;
file "goto${goto}.tld${tld}.db";
};
EOF
cp template.db.in goto${goto}.tld${tld}.db
if [ $goto -eq $DEPTH ]; then
echo "q.goto${goto}.tld${tld}. IN CNAME q.final.tld0." >>goto${goto}.tld${tld}.db
else
echo "q.goto${goto}.tld${tld}. IN CNAME q.goto${nextgoto}.tld${tld}." >>goto${goto}.tld${tld}.db
fi
echo "" >>label${label}.tld${tld}.db
goto=$nextgoto
done
+26
View File
@@ -0,0 +1,26 @@
; 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.
$TTL 300
@ IN SOA mname1. . (
1 ; serial
20 ; refresh (20 seconds)
20 ; retry (20 seconds)
1814400 ; expire (3 weeks)
3600 ; minimum (1 hour)
)
NS ns
NS ns3
ns A 10.53.0.3
ns3 A 10.53.0.3
; camp attack
+13
View File
@@ -0,0 +1,13 @@
; 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.
. 60 IN NS a.root-servers.nil.
a.root-servers.nil. A 10.53.0.1
+41
View File
@@ -0,0 +1,41 @@
/*
* 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.
*/
// NS9
options {
query-source address 10.53.0.9;
notify-source 10.53.0.9;
transfer-source 10.53.0.9;
port @PORT@;
pid-file "named.pid";
listen-on { 10.53.0.9; };
listen-on-v6 { none; };
recursion yes;
dnssec-validation no;
max-recursion-queries 50;
max-query-restarts 50;
max-query-count 100;
};
key rndc_key {
secret "1234abcd8765";
algorithm @DEFAULT_HMAC@;
};
controls {
inet 10.53.0.9 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
};
zone "." { type hint; file "hints.db"; };
+32
View File
@@ -0,0 +1,32 @@
#!/bin/sh -e
# 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.
# shellcheck source=conf.sh
. ../conf.sh
set -e
copy_setports ns1/named.conf.in ns1/named.conf
copy_setports ns2/named.conf.in ns2/named.conf
copy_setports ns3/named.conf.in ns3/named.conf
copy_setports ns9/named.conf.in ns9/named.conf
(
cd ns3
$SHELL setup.sh
)
(
cd ns2
$SHELL setup.sh
)
+36
View File
@@ -0,0 +1,36 @@
#!/bin/sh
# 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.
set -e
# shellcheck source=../conf.sh
. ../conf.sh
dig_with_opts() {
"${DIG}" -p "${PORT}" "${@}"
}
status=0
n=0
n=$((n + 1))
echo_i "checking max-query-count is in effect ($n)"
ret=0
dig_with_opts q.label1.tld1. @10.53.0.9 a >dig.out.ns9.test${n} || ret=1
grep "status: SERVFAIL" dig.out.ns9.test${n} >/dev/null || ret=1
grep "exceeded global max queries resolving" ns9/named.run >/dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=$((status + ret))
echo_i "exit status: $status"
[ $status -eq 0 ] || exit 1
+25
View File
@@ -0,0 +1,25 @@
# 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 pytest
pytestmark = pytest.mark.extra_artifacts(
[
"dig.out*",
"ans*/ans.run",
"ns*/*.jnl",
"ns*/*tld*.db",
]
)
def test_camp(run_tests_sh):
run_tests_sh()
+1
View File
@@ -77,6 +77,7 @@ options {
check-names primary warn;
check-names secondary ignore;
max-cache-size 20000000000000;
max-query-count 100;
max-query-restarts 10;
nta-lifetime 604800;
nta-recheck 604800;
+10 -1
View File
@@ -4675,6 +4675,15 @@ Tuning
format is more human-readable, and is thus suitable when a zone is to
be edited by hand. The default is ``relative``.
.. namedconf:statement:: max-query-count
:tags: server, query
:short: Sets the maximum number of iterative queries while servicing a recursive query.
This sets the maximum number of iterative queries that may be sent
by a resolver while looking up a single name. If more queries than this
need to be sent before an answer is reached, then recursion is terminated
and a SERVFAIL response is returned to the client. The default is ``200``.
.. namedconf:statement:: max-recursion-depth
:tags: server
:short: Sets the maximum number of levels of recursion permitted at any one time while servicing a recursive query.
@@ -4695,7 +4704,7 @@ Tuning
need to be sent before an answer is reached, then recursion is terminated
and a SERVFAIL response is returned to the client. (Note: if the answer
is a CNAME, then the subsequent lookup for the target of the CNAME is
counted separately.) The default is 32.
counted separately.) The default is 50.
.. namedconf:statement:: max-query-restarts
:tags: server, query
+2
View File
@@ -180,6 +180,7 @@ options {
max-ixfr-ratio ( unlimited | <percentage> );
max-journal-size ( default | unlimited | <sizeval> );
max-ncache-ttl <duration>;
max-query-count <integer>;
max-query-restarts <integer>;
max-records <integer>;
max-records-per-type <integer>;
@@ -473,6 +474,7 @@ view <string> [ <class> ] {
max-ixfr-ratio ( unlimited | <percentage> );
max-journal-size ( default | unlimited | <sizeval> );
max-ncache-ttl <duration>;
max-query-count <integer>;
max-query-restarts <integer>;
max-records <integer>;
max-records-per-type <integer>;
+7 -7
View File
@@ -343,7 +343,7 @@ static isc_result_t
dbfind_name(dns_adbname_t *, isc_stdtime_t, dns_rdatatype_t);
static isc_result_t
fetch_name(dns_adbname_t *, bool, unsigned int, isc_counter_t *qc,
dns_rdatatype_t);
isc_counter_t *gqc, dns_rdatatype_t);
static void
check_exit(dns_adb_t *);
static void
@@ -2903,7 +2903,7 @@ dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action,
void *arg, const dns_name_t *name, const dns_name_t *qname,
dns_rdatatype_t qtype, unsigned int options,
isc_stdtime_t now, dns_name_t *target, in_port_t port,
unsigned int depth, isc_counter_t *qc,
unsigned int depth, isc_counter_t *qc, isc_counter_t *gqc,
dns_adbfind_t **findp) {
dns_adbfind_t *find = NULL;
dns_adbname_t *adbname = NULL;
@@ -3162,7 +3162,7 @@ fetch:
* Start V4.
*/
if (WANT_INET(wanted_fetches) &&
fetch_name(adbname, start_at_zone, depth, qc,
fetch_name(adbname, start_at_zone, depth, qc, gqc,
dns_rdatatype_a) == ISC_R_SUCCESS)
{
DP(DEF_LEVEL,
@@ -3175,7 +3175,7 @@ fetch:
* Start V6.
*/
if (WANT_INET6(wanted_fetches) &&
fetch_name(adbname, start_at_zone, depth, qc,
fetch_name(adbname, start_at_zone, depth, qc, gqc,
dns_rdatatype_aaaa) == ISC_R_SUCCESS)
{
DP(DEF_LEVEL,
@@ -4055,7 +4055,7 @@ out:
static isc_result_t
fetch_name(dns_adbname_t *adbname, bool start_at_zone, unsigned int depth,
isc_counter_t *qc, dns_rdatatype_t type) {
isc_counter_t *qc, isc_counter_t *gqc, dns_rdatatype_t type) {
isc_result_t result;
dns_adbfetch_t *fetch = NULL;
dns_adb_t *adb;
@@ -4105,8 +4105,8 @@ fetch_name(dns_adbname_t *adbname, bool start_at_zone, unsigned int depth,
*/
result = dns_resolver_createfetch(
adb->view->resolver, &adbname->name, type, name, nameservers,
NULL, NULL, 0, options, depth, qc, adb->task, fetch_callback,
adbname, &fetch->rdataset, NULL, &fetch->fetch);
NULL, NULL, 0, options, depth, qc, gqc, adb->task,
fetch_callback, adbname, &fetch->rdataset, NULL, &fetch->fetch);
if (result != ISC_R_SUCCESS) {
DP(ENTER_LEVEL, "fetch_name: createfetch failed with %s",
isc_result_totext(result));
+1 -1
View File
@@ -554,7 +554,7 @@ start_fetch(resctx_t *rctx) {
result = dns_resolver_createfetch(
rctx->view->resolver, dns_fixedname_name(&rctx->name),
rctx->type, NULL, NULL, NULL, NULL, 0, fopts, 0, NULL,
rctx->type, NULL, NULL, NULL, NULL, 0, fopts, 0, NULL, NULL,
rctx->task, fetch_done, rctx, rctx->rdataset, rctx->sigrdataset,
&rctx->fetch);
+2 -1
View File
@@ -341,7 +341,8 @@ dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action,
void *arg, const dns_name_t *name, const dns_name_t *qname,
dns_rdatatype_t qtype, unsigned int options,
isc_stdtime_t now, dns_name_t *target, in_port_t port,
unsigned int depth, isc_counter_t *qc, dns_adbfind_t **find);
unsigned int depth, isc_counter_t *qc, isc_counter_t *gqc,
dns_adbfind_t **find);
/*%<
* Main interface for clients. The adb will look up the name given in
* "name" and will build up a list of found addresses, and perhaps start
+2 -2
View File
@@ -279,8 +279,8 @@ dns_resolver_createfetch(dns_resolver_t *res, const dns_name_t *name,
dns_forwarders_t *forwarders,
const isc_sockaddr_t *client, dns_messageid_t id,
unsigned int options, unsigned int depth,
isc_counter_t *qc, isc_task_t *task,
isc_taskaction_t action, void *arg,
isc_counter_t *qc, isc_counter_t *gqc,
isc_task_t *task, isc_taskaction_t action, void *arg,
dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
dns_fetch_t **fetchp);
/*%<
+3 -1
View File
@@ -151,6 +151,7 @@ struct dns_validator {
bool failed;
isc_stdtime_t start;
isc_counter_t *qc;
isc_counter_t *gqc;
};
/*%
@@ -168,7 +169,8 @@ dns_validator_create(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
dns_message_t *message, unsigned int options,
isc_task_t *task, isc_taskaction_t action, void *arg,
isc_counter_t *qc, dns_validator_t **validatorp);
isc_counter_t *qc, isc_counter_t *gqc,
dns_validator_t **validatorp);
/*%<
* Start a DNSSEC validation.
*
+13
View File
@@ -193,6 +193,7 @@ struct dns_view {
dns_badcache_t *failcache;
uint32_t maxrrperset;
uint32_t maxtypepername;
uint16_t max_queries;
uint8_t max_restarts;
/*
@@ -1440,4 +1441,16 @@ dns_view_setmaxrestarts(dns_view_t *view, uint8_t max_restarts);
*\li 'max_restarts' is greater than 0.
*/
void
dns_view_setmaxqueries(dns_view_t *view, uint16_t max_queries);
/*%
* Set the number of permissible outgoing queries before we give up.
* This defaults to 200.
*
* Requires:
*
*\li 'view' is valid;
*\li 'max_queries' is greater than 0.
*/
ISC_LANG_ENDDECLS
+1 -1
View File
@@ -85,7 +85,7 @@ start_fetch(dns_lookup_t *lookup) {
result = dns_resolver_createfetch(
lookup->view->resolver, dns_fixedname_name(&lookup->name),
lookup->type, NULL, NULL, NULL, NULL, 0, 0, 0, NULL,
lookup->type, NULL, NULL, NULL, NULL, 0, 0, 0, NULL, NULL,
lookup->task, fetch_done, lookup, &lookup->rdataset,
&lookup->sigrdataset, &lookup->fetch);
+2 -2
View File
@@ -263,8 +263,8 @@ checkbogus(isc_task_t *task, isc_event_t *event) {
dns_view_weakattach(ntatable->view, &view);
result = dns_resolver_createfetch(
view->resolver, nta->name, dns_rdatatype_nsec, NULL, NULL, NULL,
NULL, 0, DNS_FETCHOPT_NONTA, 0, NULL, task, fetch_done, nta,
&nta->rdataset, &nta->sigrdataset, &nta->fetch);
NULL, 0, DNS_FETCHOPT_NONTA, 0, NULL, NULL, task, fetch_done,
nta, &nta->rdataset, &nta->sigrdataset, &nta->fetch);
if (result != ISC_R_SUCCESS) {
nta_detach(view->mctx, &nta);
dns_view_weakdetach(&view);
+69 -19
View File
@@ -380,6 +380,7 @@ struct fetchctx {
bool ns_ttl_ok;
uint32_t ns_ttl;
isc_counter_t *qc;
isc_counter_t *gqc;
bool minimized;
unsigned int qmin_labels;
isc_result_t qmin_warning;
@@ -581,6 +582,7 @@ struct dns_resolver {
unsigned int query_timeout;
unsigned int maxdepth;
unsigned int maxqueries;
unsigned int maxquerycount;
isc_result_t quotaresp[2];
/* Additions for serve-stale feature. */
@@ -975,7 +977,8 @@ valcreate(fetchctx_t *fctx, dns_message_t *message, dns_adbaddrinfo_t *addrinfo,
result = dns_validator_create(fctx->res->view, name, type, rdataset,
sigrdataset, message, valoptions, task,
validated, valarg, fctx->qc, &validator);
validated, valarg, fctx->qc, fctx->gqc,
&validator);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
if (result == ISC_R_SUCCESS) {
inc_stats(fctx->res, dns_resstatscounter_val);
@@ -3426,7 +3429,8 @@ findname(fetchctx_t *fctx, const dns_name_t *name, in_port_t port,
result = dns_adb_createfind(
fctx->adb, res->buckets[fctx->bucketnum].task, fctx_finddone,
fctx, name, fctx->name, fctx->type, options, now, NULL,
res->view->dstport, fctx->depth + 1, fctx->qc, &find);
res->view->dstport, fctx->depth + 1, fctx->qc, fctx->gqc,
&find);
isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
DNS_LOGMODULE_RESOLVER, ISC_LOG_DEBUG(3),
@@ -4136,6 +4140,9 @@ fctx_try(fetchctx_t *fctx, bool retrying, bool badcache) {
unsigned int bucketnum;
FCTXTRACE5("try", "fctx->qc=", isc_counter_used(fctx->qc));
if (fctx->gqc != NULL) {
FCTXTRACE5("try", "fctx->gqc=", isc_counter_used(fctx->gqc));
}
REQUIRE(!ADDRWAIT(fctx));
@@ -4143,13 +4150,27 @@ fctx_try(fetchctx_t *fctx, bool retrying, bool badcache) {
bucketnum = fctx->bucketnum;
/* We've already exceeded maximum query count */
if (isc_counter_used(fctx->qc) > res->maxqueries) {
if (isc_counter_used(fctx->qc) > isc_counter_getlimit(fctx->qc)) {
isc_log_write(
dns_lctx, DNS_LOGCATEGORY_RESOLVER,
DNS_LOGMODULE_RESOLVER, ISC_LOG_DEBUG(3),
"exceeded max queries resolving '%s' "
"(max-recursion-queries, querycount=%u, maxqueries=%u)",
fctx->info, isc_counter_used(fctx->qc),
isc_counter_getlimit(fctx->qc));
fctx_done_detach(&fctx, DNS_R_SERVFAIL);
return;
}
if (fctx->gqc != NULL &&
isc_counter_used(fctx->gqc) > isc_counter_getlimit(fctx->gqc))
{
isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
DNS_LOGMODULE_RESOLVER, ISC_LOG_DEBUG(3),
"exceeded max queries resolving '%s' "
"(querycount=%u, maxqueries=%u)",
fctx->info, isc_counter_used(fctx->qc),
res->maxqueries);
"exceeded global max queries resolving '%s' "
"(max-query-count, querycount=%u, maxqueries=%u)",
fctx->info, isc_counter_used(fctx->gqc),
isc_counter_getlimit(fctx->gqc));
fctx_done_detach(&fctx, DNS_R_SERVFAIL);
return;
}
@@ -4255,8 +4276,8 @@ fctx_try(fetchctx_t *fctx, bool retrying, bool badcache) {
result = dns_resolver_createfetch(
fctx->res, fctx->qminname, fctx->qmintype, fctx->domain,
&fctx->nameservers, NULL, NULL, 0, options, 0, fctx->qc,
task, resume_qmin, fctx, &fctx->qminrrset, NULL,
&fctx->qminfetch);
fctx->gqc, task, resume_qmin, fctx, &fctx->qminrrset,
NULL, &fctx->qminfetch);
if (result != ISC_R_SUCCESS) {
fctx_unref(fctx);
fctx_done_detach(&fctx, DNS_R_SERVFAIL);
@@ -4268,12 +4289,26 @@ fctx_try(fetchctx_t *fctx, bool retrying, bool badcache) {
if (result != ISC_R_SUCCESS) {
isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
DNS_LOGMODULE_RESOLVER, ISC_LOG_DEBUG(3),
"exceeded max queries resolving '%s'",
fctx->info);
"exceeded max queries resolving '%s' "
"(max-recursion-queries, querycount=%u)",
fctx->info, isc_counter_used(fctx->qc));
fctx_done_detach(&fctx, DNS_R_SERVFAIL);
return;
}
if (fctx->gqc != NULL) {
result = isc_counter_increment(fctx->gqc);
if (result != ISC_R_SUCCESS) {
isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
DNS_LOGMODULE_RESOLVER, ISC_LOG_DEBUG(3),
"exceeded global max queries resolving "
"'%s' (max-query-count, querycount=%u)",
fctx->info, isc_counter_used(fctx->gqc));
fctx_done_detach(&fctx, DNS_R_SERVFAIL);
return;
}
}
result = fctx_query(fctx, addrinfo, fctx->options);
if (result != ISC_R_SUCCESS) {
fctx_done_detach(&fctx, result);
@@ -4512,6 +4547,9 @@ fctx_destroy(fetchctx_t *fctx, bool exiting) {
}
isc_counter_detach(&fctx->qc);
if (fctx->gqc != NULL) {
isc_counter_detach(&fctx->gqc);
}
fcount_decr(fctx);
dns_message_detach(&fctx->qmessage);
if (dns_rdataset_isassociated(&fctx->nameservers)) {
@@ -4784,7 +4822,7 @@ fctx_create(dns_resolver_t *res, isc_task_t *task, const dns_name_t *name,
dns_rdatatype_t type, const dns_name_t *domain,
dns_rdataset_t *nameservers, const isc_sockaddr_t *client,
unsigned int options, unsigned int bucketnum, unsigned int depth,
isc_counter_t *qc, fetchctx_t **fctxp) {
isc_counter_t *qc, isc_counter_t *gqc, fetchctx_t **fctxp) {
fetchctx_t *fctx = NULL;
isc_result_t result;
isc_result_t iresult;
@@ -4848,6 +4886,15 @@ fctx_create(dns_resolver_t *res, isc_task_t *task, const dns_name_t *name,
fctx->info, fctx->qc);
}
if (gqc != NULL) {
isc_counter_attach(gqc, &fctx->gqc);
isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
DNS_LOGMODULE_RESOLVER, ISC_LOG_DEBUG(9),
"fctx %p(%s): attached to counter %p (%d)", fctx,
fctx->info, fctx->gqc,
isc_counter_used(fctx->gqc));
}
isc_refcount_init(&fctx->references, 1);
ISC_LIST_INIT(fctx->queries);
@@ -5104,6 +5151,9 @@ cleanup_nameservers:
}
isc_mem_free(res->mctx, fctx->info);
isc_counter_detach(&fctx->qc);
if (fctx->gqc != NULL) {
isc_counter_detach(&fctx->gqc);
}
cleanup_fetch:
dns_resolver_detach(&fctx->res);
@@ -7583,7 +7633,7 @@ resume_dslookup(isc_task_t *task, isc_event_t *event) {
options = fctx->options & ~DNS_FETCHOPT_TRYSTALE_ONTIMEOUT;
result = dns_resolver_createfetch(
res, fctx->nsname, dns_rdatatype_ns, domain, nsrdataset,
NULL, NULL, 0, options, 0, fctx->qc, task,
NULL, NULL, 0, options, 0, fctx->qc, fctx->gqc, task,
resume_dslookup, fctx, &fctx->nsrrset, NULL,
&fctx->nsfetch);
if (result != ISC_R_SUCCESS) {
@@ -9951,8 +10001,8 @@ rctx_chaseds(respctx_t *rctx, dns_message_t *message,
options = fctx->options & ~DNS_FETCHOPT_TRYSTALE_ONTIMEOUT;
result = dns_resolver_createfetch(
fctx->res, fctx->nsname, dns_rdatatype_ns, NULL, NULL, NULL,
NULL, 0, options, 0, fctx->qc, task, resume_dslookup, fctx,
&fctx->nsrrset, NULL, &fctx->nsfetch);
NULL, 0, options, 0, fctx->qc, fctx->gqc, task, resume_dslookup,
fctx, &fctx->nsrrset, NULL, &fctx->nsfetch);
if (result != ISC_R_SUCCESS) {
if (result == DNS_R_DUPLICATE) {
result = DNS_R_SERVFAIL;
@@ -10655,7 +10705,7 @@ dns_resolver_prime(dns_resolver_t *res) {
INSIST(res->primefetch == NULL);
result = dns_resolver_createfetch(
res, dns_rootname, dns_rdatatype_ns, NULL, NULL, NULL,
NULL, 0, DNS_FETCHOPT_NOFORWARD, 0, NULL,
NULL, 0, DNS_FETCHOPT_NOFORWARD, 0, NULL, NULL,
res->buckets[0].task, prime_done, res, rdataset, NULL,
&res->primefetch);
UNLOCK(&res->primelock);
@@ -10933,8 +10983,8 @@ dns_resolver_createfetch(dns_resolver_t *res, const dns_name_t *name,
dns_forwarders_t *forwarders,
const isc_sockaddr_t *client, dns_messageid_t id,
unsigned int options, unsigned int depth,
isc_counter_t *qc, isc_task_t *task,
isc_taskaction_t action, void *arg,
isc_counter_t *qc, isc_counter_t *gqc,
isc_task_t *task, isc_taskaction_t action, void *arg,
dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
dns_fetch_t **fetchp) {
dns_fetch_t *fetch;
@@ -11039,7 +11089,7 @@ dns_resolver_createfetch(dns_resolver_t *res, const dns_name_t *name,
if (fctx == NULL) {
result = fctx_create(res, task, name, type, domain, nameservers,
client, options, bucketnum, depth, qc,
client, options, bucketnum, depth, qc, gqc,
&fctx);
if (result != ISC_R_SUCCESS) {
goto unlock;
+10 -3
View File
@@ -1060,7 +1060,7 @@ create_fetch(dns_validator_t *val, dns_name_t *name, dns_rdatatype_t type,
validator_logcreate(val, name, type, caller, "fetch");
return dns_resolver_createfetch(
val->view->resolver, name, type, NULL, NULL, NULL, NULL, 0,
fopts, 0, NULL, val->event->ev_sender, callback, val,
fopts, 0, NULL, NULL, val->event->ev_sender, callback, val,
&val->frdataset, &val->fsigrdataset, &val->fetch);
}
@@ -1092,7 +1092,7 @@ create_validator(dns_validator_t *val, dns_name_t *name, dns_rdatatype_t type,
validator_logcreate(val, name, type, caller, "validator");
result = dns_validator_create(val->view, name, type, rdataset, sig,
NULL, vopts, val->task, action, val,
val->qc, &val->subvalidator);
val->qc, val->gqc, &val->subvalidator);
if (result == ISC_R_SUCCESS) {
val->subvalidator->parent = val;
val->subvalidator->depth = val->depth + 1;
@@ -3153,7 +3153,8 @@ dns_validator_create(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
dns_message_t *message, unsigned int options,
isc_task_t *task, isc_taskaction_t action, void *arg,
isc_counter_t *qc, dns_validator_t **validatorp) {
isc_counter_t *qc, isc_counter_t *gqc,
dns_validator_t **validatorp) {
isc_result_t result = ISC_R_FAILURE;
dns_validator_t *val;
isc_task_t *tclone = NULL;
@@ -3197,6 +3198,9 @@ dns_validator_create(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
if (qc != NULL) {
isc_counter_attach(qc, &val->qc);
}
if (gqc != NULL) {
isc_counter_attach(gqc, &val->gqc);
}
val->mustbesecure = dns_resolver_getmustbesecure(view->resolver, name);
dns_rdataset_init(&val->fdsset);
@@ -3305,6 +3309,9 @@ destroy(dns_validator_t *val) {
if (val->qc != NULL) {
isc_counter_detach(&val->qc);
}
if (val->gqc != NULL) {
isc_counter_detach(&val->gqc);
}
isc_mutex_destroy(&val->lock);
dns_view_weakdetach(&val->view);
isc_mem_put(mctx, val, sizeof(*val));
+8
View File
@@ -2806,3 +2806,11 @@ dns_view_setmaxrestarts(dns_view_t *view, uint8_t max_restarts) {
view->max_restarts = max_restarts;
}
void
dns_view_setmaxqueries(dns_view_t *view, uint16_t max_queries) {
REQUIRE(DNS_VIEW_VALID(view));
REQUIRE(max_queries > 0);
view->max_queries = max_queries;
}
+9 -9
View File
@@ -139,14 +139,14 @@
/*%
* KASP flags
*/
#define KASP_LOCK(k) \
if ((k) != NULL) { \
LOCK((&((k)->lock))); \
#define KASP_LOCK(k) \
if ((k) != NULL) { \
LOCK(&((k)->lock)); \
}
#define KASP_UNLOCK(k) \
if ((k) != NULL) { \
UNLOCK((&((k)->lock))); \
#define KASP_UNLOCK(k) \
if ((k) != NULL) { \
UNLOCK(&((k)->lock)); \
}
/*
@@ -11091,8 +11091,8 @@ do_keyfetch(isc_task_t *task, isc_event_t *event) {
NULL, NULL, 0,
DNS_FETCHOPT_NOVALIDATE | DNS_FETCHOPT_UNSHARED |
DNS_FETCHOPT_NOCACHED,
0, NULL, zone->task, keyfetch_done, kfetch, &kfetch->dnskeyset,
&kfetch->dnskeysigset, &kfetch->fetch);
0, NULL, NULL, zone->task, keyfetch_done, kfetch,
&kfetch->dnskeyset, &kfetch->dnskeysigset, &kfetch->fetch);
if (result != ISC_R_SUCCESS) {
retry_keyfetch(kfetch, kname);
@@ -12542,7 +12542,7 @@ notify_find_address(dns_notify_t *notify) {
result = dns_adb_createfind(
notify->zone->view->adb, notify->zone->task, process_adb_event,
notify, &notify->ns, dns_rootname, 0, options, 0, NULL,
notify->zone->view->dstport, 0, NULL, &notify->find);
notify->zone->view->dstport, 0, NULL, NULL, &notify->find);
/* Something failed? */
if (result != ISC_R_SUCCESS) {
+7
View File
@@ -80,6 +80,13 @@ isc_counter_setlimit(isc_counter_t *counter, int limit) {
atomic_store(&counter->limit, limit);
}
unsigned int
isc_counter_getlimit(isc_counter_t *counter) {
REQUIRE(VALID_COUNTER(counter));
return atomic_load_acquire(&counter->limit);
}
void
isc_counter_attach(isc_counter_t *source, isc_counter_t **targetp) {
REQUIRE(VALID_COUNTER(source));
+6
View File
@@ -68,6 +68,12 @@ isc_counter_setlimit(isc_counter_t *counter, int limit);
* Set the counter limit.
*/
unsigned int
isc_counter_getlimit(isc_counter_t *counter);
/*%<
* Get the counter limit.
*/
void
isc_counter_attach(isc_counter_t *source, isc_counter_t **targetp);
/*%<
+1
View File
@@ -2110,6 +2110,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-count", &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 },
+1
View File
@@ -54,6 +54,7 @@ typedef struct ns_query_recparam {
struct ns_query {
unsigned int attributes;
unsigned int restarts;
isc_counter_t *qc;
bool timerset;
dns_name_t *qname;
dns_name_t *origqname;
+20 -5
View File
@@ -18,6 +18,7 @@
#include <stdbool.h>
#include <string.h>
#include <isc/counter.h>
#include <isc/hex.h>
#include <isc/mem.h>
#include <isc/once.h>
@@ -764,6 +765,9 @@ query_reset(ns_client_t *client, bool everything) {
client->query.rpz_st = NULL;
}
}
if (client->query.qc != NULL) {
isc_counter_detach(&client->query.qc);
}
client->query.origqname = NULL;
client->query.dboptions = 0;
client->query.fetchoptions = 0;
@@ -2614,8 +2618,8 @@ query_prefetch(ns_client_t *client, dns_name_t *qname,
options = client->query.fetchoptions | DNS_FETCHOPT_PREFETCH;
result = dns_resolver_createfetch(
client->view->resolver, qname, rdataset->type, NULL, NULL, NULL,
peeraddr, client->message->id, options, 0, NULL, client->task,
prefetch_done, client, tmprdataset, NULL,
peeraddr, client->message->id, options, 0, NULL, NULL,
client->task, prefetch_done, client, tmprdataset, NULL,
&client->query.prefetch);
if (result != ISC_R_SUCCESS) {
if (client->recursionquota != NULL) {
@@ -2838,7 +2842,7 @@ query_rpzfetch(ns_client_t *client, dns_name_t *qname, dns_rdatatype_t type) {
isc_nmhandle_attach(client->handle, &client->prefetchhandle);
result = dns_resolver_createfetch(
client->view->resolver, qname, type, NULL, NULL, NULL, peeraddr,
client->message->id, options, 0, NULL, client->task,
client->message->id, options, 0, NULL, NULL, client->task,
prefetch_done, client, tmprdataset, NULL,
&client->query.prefetch);
if (result != ISC_R_SUCCESS) {
@@ -6614,8 +6618,8 @@ ns_query_recurse(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qname,
result = dns_resolver_createfetch(
client->view->resolver, qname, qtype, qdomain, nameservers,
NULL, peeraddr, client->message->id, client->query.fetchoptions,
0, NULL, client->task, fetch_callback, client, rdataset,
sigrdataset, &client->query.fetch);
0, NULL, client->query.qc, client->task, fetch_callback, client,
rdataset, sigrdataset, &client->query.fetch);
if (result != ISC_R_SUCCESS) {
if (client->recursionquota != NULL) {
isc_quota_detach(&client->recursionquota);
@@ -12546,5 +12550,16 @@ ns_query_start(ns_client_t *client, isc_nmhandle_t *handle) {
message->flags |= DNS_MESSAGEFLAG_AD;
}
/*
* Start global outgoing query count.
*/
result = isc_counter_create(client->manager->mctx,
client->view->max_queries,
&client->query.qc);
if (result != ISC_R_SUCCESS) {
query_next(client, result);
return;
}
(void)query_setup(client, qtype);
}