mirror of
https://github.com/isc-projects/bind9.git
synced 2026-05-28 04:34:54 -04:00
[9.20] new: usr: Tighten 'max-recursion-queries' and add 'max-query-restarts' option
There were cases in resolver.c when the `max-recursion-queries` quota was ineffective. It was possible to craft zones that would cause a resolver to waste resources by sending excessive queries while attempting to resolve a name. This has been addressed by correcting errors in the implementation of `max-recursion-queries`, and by reducing the default value from 100 to 32. In addition, a new `max-query-restarts` option has been added which limits the number of times a recursive server will follow CNAME or DNAME records before terminating resolution. This was previously a hard-coded limit of 16, and now defaults to 11. Closes #4741 Backport of MR !9281 Merge branch 'backport-4741-reclimit-restarts-9.20' into 'bind-9.20' See merge request isc-projects/bind9!9282
This commit is contained in:
commit
42e70b0f0e
24 changed files with 232 additions and 57 deletions
|
|
@ -88,6 +88,9 @@
|
|||
|
||||
#define MAXNAME (DNS_NAME_MAXTEXT + 1)
|
||||
|
||||
#define MAX_QUERIES 32
|
||||
#define MAX_RESTARTS 11
|
||||
|
||||
/* Variables used internally by delv. */
|
||||
char *progname = NULL;
|
||||
static isc_mem_t *mctx = NULL;
|
||||
|
|
@ -130,6 +133,9 @@ static bool showcomments = true, showdnssec = true, showtrust = true,
|
|||
multiline = false, short_form = false, print_unknown_format = false,
|
||||
yaml = false, fulltrace = false;
|
||||
|
||||
static uint32_t maxqueries = MAX_QUERIES;
|
||||
static uint32_t restarts = MAX_RESTARTS;
|
||||
|
||||
static bool resolve_trace = false, validator_trace = false,
|
||||
message_trace = false, send_trace = false;
|
||||
|
||||
|
|
@ -1191,6 +1197,23 @@ plus_option(char *option) {
|
|||
break;
|
||||
case 'm':
|
||||
switch (cmd[1]) {
|
||||
case 'a': /* maxqueries */
|
||||
FULLCHECK("maxqueries");
|
||||
if (value == NULL) {
|
||||
goto need_value;
|
||||
}
|
||||
if (!state) {
|
||||
goto invalid_option;
|
||||
}
|
||||
result = parse_uint(&maxqueries, value, UINT_MAX,
|
||||
"maxqueries");
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
fatal("Couldn't parse maxqueries");
|
||||
}
|
||||
if (maxqueries == 0) {
|
||||
fatal("maxqueries must be nonzero");
|
||||
}
|
||||
break;
|
||||
case 't': /* mtrace */
|
||||
FULLCHECK("mtrace");
|
||||
message_trace = state;
|
||||
|
|
@ -1243,6 +1266,22 @@ plus_option(char *option) {
|
|||
break;
|
||||
case 'r':
|
||||
switch (cmd[1]) {
|
||||
case 'e': /* restarts */
|
||||
FULLCHECK("restarts");
|
||||
if (value == NULL) {
|
||||
goto need_value;
|
||||
}
|
||||
if (!state) {
|
||||
goto invalid_option;
|
||||
}
|
||||
result = parse_uint(&restarts, value, 255, "restarts");
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
fatal("Couldn't parse restarts");
|
||||
}
|
||||
if (restarts == 0) {
|
||||
fatal("restarts must be between 1..255");
|
||||
}
|
||||
break;
|
||||
case 'o': /* root */
|
||||
FULLCHECK("root");
|
||||
if (state && no_sigs) {
|
||||
|
|
@ -1370,10 +1409,7 @@ plus_option(char *option) {
|
|||
break;
|
||||
default:
|
||||
invalid_option:
|
||||
/*
|
||||
* We can also add a "need_value:" case here if we ever
|
||||
* add a plus-option that requires a specified value
|
||||
*/
|
||||
need_value:
|
||||
fprintf(stderr, "Invalid option: +%s\n", option);
|
||||
usage();
|
||||
}
|
||||
|
|
@ -1898,6 +1934,7 @@ run_resolve(void *arg) {
|
|||
/* Create client */
|
||||
CHECK(dns_client_create(mctx, loopmgr, netmgr, 0, tlsctx_client_cache,
|
||||
&client, srcaddr4, srcaddr6));
|
||||
dns_client_setmaxrestarts(client, restarts);
|
||||
|
||||
/* Set the nameserver */
|
||||
if (server != NULL) {
|
||||
|
|
@ -2162,6 +2199,7 @@ run_server(void *arg) {
|
|||
dns_view_setcache(view, cache, false);
|
||||
dns_cache_detach(&cache);
|
||||
dns_view_setdstport(view, destport);
|
||||
dns_view_setmaxrestarts(view, restarts);
|
||||
|
||||
CHECK(dns_rootns_create(mctx, dns_rdataclass_in, hintfile, &roothints));
|
||||
dns_view_sethints(view, roothints);
|
||||
|
|
@ -2175,6 +2213,7 @@ run_server(void *arg) {
|
|||
|
||||
CHECK(dns_view_createresolver(view, netmgr, 0, tlsctx_client_cache,
|
||||
dispatch, NULL));
|
||||
dns_resolver_setmaxqueries(view->resolver, maxqueries);
|
||||
|
||||
isc_stats_create(mctx, &resstats, dns_resstatscounter_max);
|
||||
dns_resolver_setstats(view->resolver, resstats);
|
||||
|
|
|
|||
|
|
@ -337,6 +337,18 @@ assign values to options like the timeout interval. They have the form
|
|||
they are replaced by the string ``[omitted]`` or, in the DNSKEY case, the
|
||||
key ID is displayed as the replacement, e.g. ``[ key id = value ]``.
|
||||
|
||||
.. option:: +restarts
|
||||
|
||||
When name server mode (``delv +ns``) is in use, this option sets the
|
||||
maximum number of CNAME queries to follow before terminating resolution.
|
||||
This prevents ``delv`` from hanging in the event of a CNAME loop.
|
||||
The default is 11.
|
||||
|
||||
.. option:: +maxqueries
|
||||
|
||||
This option specifies the maximum number of queries to send to resolve
|
||||
a name before giving up. The default is 32.
|
||||
|
||||
.. option:: +trust, +notrust
|
||||
|
||||
This option controls whether to display the trust level when printing a record.
|
||||
|
|
|
|||
|
|
@ -170,7 +170,8 @@ options {\n\
|
|||
max-clients-per-query 100;\n\
|
||||
max-ncache-ttl 10800; /* 3 hours */\n\
|
||||
max-recursion-depth 7;\n\
|
||||
max-recursion-queries 100;\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\
|
||||
|
|
|
|||
|
|
@ -5502,6 +5502,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) {
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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)"
|
||||
|
|
@ -454,7 +456,7 @@ ret=0
|
|||
$DIG $DIGOPTS @10.53.0.2 loop.example >dig.out.test$n
|
||||
grep "status: SERVFAIL" dig.out.test$n >/dev/null || ret=1
|
||||
grep "max. restarts reached" dig.out.test$n >/dev/null || ret=1
|
||||
grep "ANSWER: 17" dig.out.test$n >/dev/null || ret=1
|
||||
grep "ANSWER: 12" dig.out.test$n >/dev/null || ret=1
|
||||
if [ $ret != 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
||||
|
|
|
|||
|
|
@ -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" {
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ options {
|
|||
listen-on-v6 { none; };
|
||||
servfail-ttl 0;
|
||||
qname-minimization disabled;
|
||||
max-recursion-queries 50;
|
||||
max-recursion-depth 12;
|
||||
recursion yes;
|
||||
dnssec-validation yes;
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ options {
|
|||
max-zone-ttl unlimited;
|
||||
resolver-query-timeout 5000; # 5 seconds
|
||||
attach-cache "globalcache";
|
||||
max-recursion-queries 50;
|
||||
};
|
||||
|
||||
trust-anchors { };
|
||||
|
|
|
|||
|
|
@ -149,7 +149,7 @@ dig_with_opts +tcp longcname1.example.net @10.53.0.1 a >dig.out.ns1.test${n} ||
|
|||
grep -F "status: SERVFAIL" dig.out.ns1.test${n} >/dev/null || ret=1
|
||||
grep -F "max. restarts reached" dig.out.ns1.test${n} >/dev/null || ret=1
|
||||
lines=$(grep -F "CNAME" dig.out.ns1.test${n} | wc -l)
|
||||
test ${lines:-1} -eq 17 || ret=1
|
||||
test ${lines:-1} -eq 12 || ret=1
|
||||
if [ $ret != 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
||||
|
|
|
|||
|
|
@ -4594,9 +4594,20 @@ Tuning
|
|||
: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 while
|
||||
servicing a recursive query. If more queries are sent, the recursive
|
||||
query is terminated and returns SERVFAIL. The default is 100.
|
||||
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. (Note: if the answer
|
||||
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
|
||||
|
|
|
|||
|
|
@ -182,6 +182,7 @@ options {
|
|||
max-ixfr-ratio ( unlimited | <percentage> );
|
||||
max-journal-size ( default | unlimited | <sizeval> );
|
||||
max-ncache-ttl <duration>;
|
||||
max-query-restarts <integer>;
|
||||
max-records <integer>;
|
||||
max-records-per-type <integer>;
|
||||
max-recursion-depth <integer>;
|
||||
|
|
@ -471,6 +472,7 @@ view <string> [ <class> ] {
|
|||
max-ixfr-ratio ( unlimited | <percentage> );
|
||||
max-journal-size ( default | unlimited | <sizeval> );
|
||||
max-ncache-ttl <duration>;
|
||||
max-query-restarts <integer>;
|
||||
max-records <integer>;
|
||||
max-records-per-type <integer>;
|
||||
max-recursion-depth <integer>;
|
||||
|
|
|
|||
|
|
@ -57,8 +57,6 @@
|
|||
#define UCTX_MAGIC ISC_MAGIC('U', 'c', 't', 'x')
|
||||
#define UCTX_VALID(c) ISC_MAGIC_VALID(c, UCTX_MAGIC)
|
||||
|
||||
#define MAX_RESTARTS 16
|
||||
|
||||
#define CHECK(r) \
|
||||
do { \
|
||||
result = (r); \
|
||||
|
|
@ -81,6 +79,7 @@ struct dns_client {
|
|||
|
||||
unsigned int find_timeout;
|
||||
unsigned int find_udpretries;
|
||||
uint8_t max_restarts;
|
||||
|
||||
isc_refcount_t references;
|
||||
|
||||
|
|
@ -90,6 +89,7 @@ struct dns_client {
|
|||
|
||||
#define DEF_FIND_TIMEOUT 5
|
||||
#define DEF_FIND_UDPRETRIES 3
|
||||
#define DEF_MAX_RESTARTS 11
|
||||
|
||||
/*%
|
||||
* Internal state for a single name resolution procedure
|
||||
|
|
@ -250,6 +250,7 @@ dns_client_create(isc_mem_t *mctx, isc_loopmgr_t *loopmgr, isc_nm_t *nm,
|
|||
*client = (dns_client_t){
|
||||
.loop = isc_loop_get(loopmgr, 0),
|
||||
.nm = nm,
|
||||
.max_restarts = DEF_MAX_RESTARTS,
|
||||
};
|
||||
|
||||
result = dns_dispatchmgr_create(mctx, loopmgr, nm,
|
||||
|
|
@ -384,6 +385,14 @@ dns_client_setservers(dns_client_t *client, dns_rdataclass_t rdclass,
|
|||
return (result);
|
||||
}
|
||||
|
||||
void
|
||||
dns_client_setmaxrestarts(dns_client_t *client, uint8_t max_restarts) {
|
||||
REQUIRE(DNS_CLIENT_VALID(client));
|
||||
REQUIRE(max_restarts > 0);
|
||||
|
||||
client->max_restarts = max_restarts;
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
getrdataset(isc_mem_t *mctx, dns_rdataset_t **rdatasetp) {
|
||||
dns_rdataset_t *rdataset;
|
||||
|
|
@ -778,7 +787,9 @@ client_resfind(resctx_t *rctx, dns_fetchresponse_t *resp) {
|
|||
/*
|
||||
* Limit the number of restarts.
|
||||
*/
|
||||
if (want_restart && rctx->restarts == MAX_RESTARTS) {
|
||||
if (want_restart &&
|
||||
rctx->restarts == rctx->client->max_restarts)
|
||||
{
|
||||
want_restart = false;
|
||||
result = ISC_R_QUOTA;
|
||||
send_event = true;
|
||||
|
|
|
|||
|
|
@ -174,6 +174,19 @@ dns_client_setservers(dns_client_t *client, dns_rdataclass_t rdclass,
|
|||
*\li Anything else Failure.
|
||||
*/
|
||||
|
||||
void
|
||||
dns_client_setmaxrestarts(dns_client_t *client, uint8_t max_restarts);
|
||||
/*%<
|
||||
* Set the number of permissible chained queries before we give up,
|
||||
* to prevent CNAME loops. This defaults to 11.
|
||||
*
|
||||
* Requires:
|
||||
*
|
||||
*\li 'client' is a valid client.
|
||||
|
||||
*\li 'max_restarts' is greater than 0.
|
||||
*/
|
||||
|
||||
typedef void (*dns_client_resolve_cb)(dns_client_t *client,
|
||||
const dns_name_t *name,
|
||||
dns_namelist_t *namelist,
|
||||
|
|
|
|||
|
|
@ -146,12 +146,13 @@ struct dns_validator {
|
|||
unsigned int authfail;
|
||||
isc_stdtime_t start;
|
||||
|
||||
bool digest_sha1;
|
||||
bool supported_algorithm;
|
||||
dns_rdata_t rdata;
|
||||
bool resume;
|
||||
uint32_t *nvalidations;
|
||||
uint32_t *nfails;
|
||||
bool digest_sha1;
|
||||
bool supported_algorithm;
|
||||
dns_rdata_t rdata;
|
||||
bool resume;
|
||||
uint32_t *nvalidations;
|
||||
uint32_t *nfails;
|
||||
isc_counter_t *qc;
|
||||
};
|
||||
|
||||
/*%
|
||||
|
|
@ -170,7 +171,7 @@ dns_validator_create(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
|
|||
dns_message_t *message, unsigned int options,
|
||||
isc_loop_t *loop, isc_job_cb cb, void *arg,
|
||||
uint32_t *nvalidations, uint32_t *nfails,
|
||||
dns_validator_t **validatorp);
|
||||
isc_counter_t *qc, dns_validator_t **validatorp);
|
||||
/*%<
|
||||
* Start a DNSSEC validation.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -185,6 +185,7 @@ struct dns_view {
|
|||
unsigned int udpsize;
|
||||
uint32_t maxrrperset;
|
||||
uint32_t maxtypepername;
|
||||
uint8_t max_restarts;
|
||||
|
||||
/*
|
||||
* Configurable data for server use only,
|
||||
|
|
@ -1327,4 +1328,16 @@ dns_view_getadb(dns_view_t *view, dns_adb_t **adbp);
|
|||
*\li 'adbp' is non-NULL and '*adbp' is NULL.
|
||||
*/
|
||||
|
||||
void
|
||||
dns_view_setmaxrestarts(dns_view_t *view, uint8_t max_restarts);
|
||||
/*%<
|
||||
* Set the number of permissible chained queries before we give up,
|
||||
* to prevent CNAME loops. This defaults to 11.
|
||||
*
|
||||
* Requires:
|
||||
*
|
||||
*\li 'view' is valid;
|
||||
*\li 'max_restarts' is greater than 0.
|
||||
*/
|
||||
|
||||
ISC_LANG_ENDDECLS
|
||||
|
|
|
|||
|
|
@ -215,7 +215,7 @@
|
|||
|
||||
/* The default maximum number of iterative queries to allow before giving up. */
|
||||
#ifndef DEFAULT_MAX_QUERIES
|
||||
#define DEFAULT_MAX_QUERIES 100
|
||||
#define DEFAULT_MAX_QUERIES 50
|
||||
#endif /* ifndef DEFAULT_MAX_QUERIES */
|
||||
|
||||
/*
|
||||
|
|
@ -991,7 +991,7 @@ 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, fctx->loop, validated, valarg, &fctx->nvalidations,
|
||||
&fctx->nfails, &validator);
|
||||
&fctx->nfails, fctx->qc, &validator);
|
||||
RUNTIME_CHECK(result == ISC_R_SUCCESS);
|
||||
inc_stats(fctx->res, dns_resstatscounter_val);
|
||||
if ((valoptions & DNS_VALIDATOR_DEFER) == 0) {
|
||||
|
|
@ -4520,16 +4520,6 @@ fctx_create(dns_resolver_t *res, isc_loop_t *loop, const dns_name_t *name,
|
|||
|
||||
isc_mutex_init(&fctx->lock);
|
||||
|
||||
if (qc != NULL) {
|
||||
isc_counter_attach(qc, &fctx->qc);
|
||||
} else {
|
||||
result = isc_counter_create(fctx->mctx, res->maxqueries,
|
||||
&fctx->qc);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
goto cleanup_fetch;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Make fctx->info point to a copy of a formatted string
|
||||
* "name/type". FCTXTRACE won't work until this is done.
|
||||
|
|
@ -4542,6 +4532,24 @@ fctx_create(dns_resolver_t *res, isc_loop_t *loop, const dns_name_t *name,
|
|||
|
||||
FCTXTRACE("create");
|
||||
|
||||
if (qc != NULL) {
|
||||
isc_counter_attach(qc, &fctx->qc);
|
||||
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->qc, isc_counter_used(fctx->qc));
|
||||
} else {
|
||||
result = isc_counter_create(fctx->mctx, res->maxqueries,
|
||||
&fctx->qc);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
goto cleanup_fetch;
|
||||
}
|
||||
isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
|
||||
DNS_LOGMODULE_RESOLVER, ISC_LOG_DEBUG(9),
|
||||
"fctx %p(%s): created counter %p", fctx,
|
||||
fctx->info, fctx->qc);
|
||||
}
|
||||
|
||||
#if DNS_RESOLVER_TRACE
|
||||
fprintf(stderr, "fetchctx__init:%s:%s:%d:%p:%p->references = 1\n",
|
||||
__func__, __FILE__, __LINE__, fctx, fctx);
|
||||
|
|
@ -7128,7 +7136,7 @@ resume_dslookup(void *arg) {
|
|||
fetchctx_ref(fctx);
|
||||
result = dns_resolver_createfetch(
|
||||
res, fctx->nsname, dns_rdatatype_ns, domain, nsrdataset,
|
||||
NULL, NULL, 0, fctx->options, 0, NULL, loop,
|
||||
NULL, NULL, 0, fctx->options, 0, fctx->qc, loop,
|
||||
resume_dslookup, fctx, &fctx->nsrrset, NULL,
|
||||
&fctx->nsfetch);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
|
|
@ -9556,8 +9564,8 @@ rctx_chaseds(respctx_t *rctx, dns_message_t *message,
|
|||
fetchctx_ref(fctx);
|
||||
result = dns_resolver_createfetch(
|
||||
fctx->res, fctx->nsname, dns_rdatatype_ns, NULL, NULL, NULL,
|
||||
NULL, 0, fctx->options, 0, NULL, fctx->loop, resume_dslookup,
|
||||
fctx, &fctx->nsrrset, NULL, &fctx->nsfetch);
|
||||
NULL, 0, fctx->options, 0, fctx->qc, fctx->loop,
|
||||
resume_dslookup, fctx, &fctx->nsrrset, NULL, &fctx->nsfetch);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
if (result == DNS_R_DUPLICATE) {
|
||||
result = DNS_R_SERVFAIL;
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#include <isc/async.h>
|
||||
#include <isc/base32.h>
|
||||
#include <isc/counter.h>
|
||||
#include <isc/job.h>
|
||||
#include <isc/md.h>
|
||||
#include <isc/mem.h>
|
||||
|
|
@ -974,9 +975,10 @@ create_validator(dns_validator_t *val, dns_name_t *name, dns_rdatatype_t type,
|
|||
(DNS_VALIDATOR_NOCDFLAG | DNS_VALIDATOR_NONTA));
|
||||
|
||||
validator_logcreate(val, name, type, caller, "validator");
|
||||
result = dns_validator_create(
|
||||
val->view, name, type, rdataset, sig, NULL, vopts, val->loop,
|
||||
cb, val, val->nvalidations, val->nfails, &val->subvalidator);
|
||||
result = dns_validator_create(val->view, name, type, rdataset, sig,
|
||||
NULL, vopts, val->loop, cb, val,
|
||||
val->nvalidations, val->nfails, val->qc,
|
||||
&val->subvalidator);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
dns_validator_attach(val, &val->subvalidator->parent);
|
||||
val->subvalidator->depth = val->depth + 1;
|
||||
|
|
@ -3355,7 +3357,7 @@ dns_validator_create(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
|
|||
dns_message_t *message, unsigned int options,
|
||||
isc_loop_t *loop, isc_job_cb cb, void *arg,
|
||||
uint32_t *nvalidations, uint32_t *nfails,
|
||||
dns_validator_t **validatorp) {
|
||||
isc_counter_t *qc, dns_validator_t **validatorp) {
|
||||
isc_result_t result = ISC_R_FAILURE;
|
||||
dns_validator_t *val = NULL;
|
||||
dns_keytable_t *kt = NULL;
|
||||
|
|
@ -3395,6 +3397,10 @@ dns_validator_create(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
|
|||
dns_message_attach(message, &val->message);
|
||||
}
|
||||
|
||||
if (qc != NULL) {
|
||||
isc_counter_attach(qc, &val->qc);
|
||||
}
|
||||
|
||||
val->mustbesecure = dns_resolver_getmustbesecure(view->resolver, name);
|
||||
dns_rdataset_init(&val->fdsset);
|
||||
dns_rdataset_init(&val->frdataset);
|
||||
|
|
@ -3470,6 +3476,9 @@ destroy_validator(dns_validator_t *val) {
|
|||
if (val->message != NULL) {
|
||||
dns_message_detach(&val->message);
|
||||
}
|
||||
if (val->qc != NULL) {
|
||||
isc_counter_detach(&val->qc);
|
||||
}
|
||||
dns_view_detach(&val->view);
|
||||
isc_mem_put(mctx, val, sizeof(*val));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,6 +74,12 @@
|
|||
|
||||
#define DNS_VIEW_DELONLYHASH 111
|
||||
|
||||
/*%
|
||||
* Default maximum number of chained queries before we give up
|
||||
* to prevent CNAME loops.
|
||||
*/
|
||||
#define DEFAULT_MAX_RESTARTS 11
|
||||
|
||||
/*%
|
||||
* Default EDNS0 buffer size
|
||||
*/
|
||||
|
|
@ -116,6 +122,7 @@ dns_view_create(isc_mem_t *mctx, dns_dispatchmgr_t *dispatchmgr,
|
|||
.trust_anchor_telemetry = true,
|
||||
.root_key_sentinel = true,
|
||||
.udpsize = DEFAULT_EDNS_BUFSIZE,
|
||||
.max_restarts = DEFAULT_MAX_RESTARTS,
|
||||
};
|
||||
|
||||
isc_refcount_init(&view->references, 1);
|
||||
|
|
@ -2455,3 +2462,11 @@ dns_view_getadb(dns_view_t *view, dns_adb_t **adbp) {
|
|||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
void
|
||||
dns_view_setmaxrestarts(dns_view_t *view, uint8_t max_restarts) {
|
||||
REQUIRE(DNS_VIEW_VALID(view));
|
||||
REQUIRE(max_restarts > 0);
|
||||
|
||||
view->max_restarts = max_restarts;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2108,6 +2108,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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -103,6 +103,7 @@ struct ns_server {
|
|||
uint16_t transfer_tcp_message_size;
|
||||
bool interface_auto;
|
||||
dns_tkeyctx_t *tkeyctx;
|
||||
uint8_t max_restarts;
|
||||
|
||||
/*% Server id for NSID */
|
||||
char *server_id;
|
||||
|
|
|
|||
|
|
@ -86,12 +86,6 @@
|
|||
#define dns64_bis_return_excluded_addresses 1
|
||||
#endif /* if 0 */
|
||||
|
||||
/*%
|
||||
* Maximum number of chained queries before we give up
|
||||
* to prevent CNAME loops.
|
||||
*/
|
||||
#define MAX_RESTARTS 16
|
||||
|
||||
#define QUERY_ERROR(qctx, r) \
|
||||
do { \
|
||||
(qctx)->result = r; \
|
||||
|
|
@ -2046,10 +2040,10 @@ addname:
|
|||
/*
|
||||
* In some cases, a record that has been added as additional
|
||||
* data may *also* trigger the addition of additional data.
|
||||
* This cannot go more than MAX_RESTARTS levels deep.
|
||||
* This cannot go more than 'max-restarts' levels deep.
|
||||
*/
|
||||
if (trdataset != NULL && dns_rdatatype_followadditional(type)) {
|
||||
if (client->additionaldepth++ < MAX_RESTARTS) {
|
||||
if (client->additionaldepth++ < client->view->max_restarts) {
|
||||
eresult = dns_rdataset_additionaldata(
|
||||
trdataset, fname, query_additional_cb, qctx);
|
||||
}
|
||||
|
|
@ -11580,7 +11574,9 @@ ns_query_done(query_ctx_t *qctx) {
|
|||
* Do we need to restart the query (e.g. for CNAME chaining)?
|
||||
*/
|
||||
if (qctx->want_restart) {
|
||||
if (qctx->client->query.restarts < MAX_RESTARTS) {
|
||||
if (qctx->client->query.restarts <
|
||||
qctx->client->view->max_restarts)
|
||||
{
|
||||
query_ctx_t *saved_qctx = NULL;
|
||||
qctx->client->query.restarts++;
|
||||
saved_qctx = isc_mem_get(qctx->client->manager->mctx,
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@
|
|||
void
|
||||
ns_server_create(isc_mem_t *mctx, ns_matchview_t matchingview,
|
||||
ns_server_t **sctxp) {
|
||||
ns_server_t *sctx;
|
||||
ns_server_t *sctx = NULL;
|
||||
|
||||
REQUIRE(sctxp != NULL && *sctxp == NULL);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue