mirror of
https://github.com/isc-projects/bind9.git
synced 2026-06-11 09:52:27 -04:00
[9.20] fix: usr: return SERVFAIL for a too long CNAME chain
When cutting a long CNAME chain, named was returning NOERROR instead of SERVFAIL (alongside with a partial answer). This has been fixed. Closes #4449 Backport of MR !9090 Merge branch 'backport-4449-return-servfail-for-a-long-cname-chain-9.20' into 'bind-9.20' See merge request isc-projects/bind9!9203
This commit is contained in:
commit
d7e5f7903d
4 changed files with 62 additions and 15 deletions
|
|
@ -439,11 +439,21 @@ if [ $ret != 0 ]; then echo_i "failed"; fi
|
|||
status=$((status + ret))
|
||||
|
||||
n=$((n + 1))
|
||||
echo_i "checking CNAME loops are detected ($n)"
|
||||
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: NOERROR" dig.out.test$n >/dev/null || ret=1
|
||||
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))
|
||||
|
||||
n=$((n + 1))
|
||||
echo_i "checking CNAME loops are detected (auth) ($n)"
|
||||
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
|
||||
if [ $ret != 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
|
|
|||
|
|
@ -102,6 +102,9 @@ sub handleQuery {
|
|||
$packet->push("answer",
|
||||
new Net::DNS::RR($qname .
|
||||
" 300 CNAME goodcname.example.org"));
|
||||
} elsif ($qname =~ /^longcname/) {
|
||||
$cname = $qname =~ s/longcname/longcnamex/r;
|
||||
$packet->push("answer", new Net::DNS::RR($qname . " 300 CNAME " . $cname));
|
||||
} elsif ($qname =~ /^nodata\.example\.net$/i) {
|
||||
$packet->header->aa(1);
|
||||
} elsif ($qname =~ /^nxdomain\.example\.net$/i) {
|
||||
|
|
|
|||
|
|
@ -120,6 +120,17 @@ grep "status: NOERROR" dig.out.ns1.test${n} >/dev/null || ret=1
|
|||
if [ $ret != 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
||||
n=$((n + 1))
|
||||
echo_i "checking long CNAME chain target filtering (deny) ($n)"
|
||||
ret=0
|
||||
dig_with_opts +tcp longcname1.example.net @10.53.0.1 a >dig.out.ns1.test${n} || ret=1
|
||||
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
|
||||
if [ $ret != 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
||||
n=$((n + 1))
|
||||
echo_i "checking DNAME target filtering (deny) ($n)"
|
||||
ret=0
|
||||
|
|
|
|||
|
|
@ -11546,7 +11546,7 @@ isc_result_t
|
|||
ns_query_done(query_ctx_t *qctx) {
|
||||
isc_result_t result = ISC_R_UNSET;
|
||||
const dns_namelist_t *secs = qctx->client->message->sections;
|
||||
bool nodetach;
|
||||
bool nodetach, partial_result_with_servfail = false;
|
||||
|
||||
CCTRACE(ISC_LOG_DEBUG(3), "ns_query_done");
|
||||
|
||||
|
|
@ -11580,21 +11580,44 @@ ns_query_done(query_ctx_t *qctx) {
|
|||
/*
|
||||
* Do we need to restart the query (e.g. for CNAME chaining)?
|
||||
*/
|
||||
if (qctx->want_restart && qctx->client->query.restarts < MAX_RESTARTS) {
|
||||
query_ctx_t *saved_qctx = NULL;
|
||||
qctx->client->query.restarts++;
|
||||
saved_qctx = isc_mem_get(qctx->client->manager->mctx,
|
||||
sizeof(*saved_qctx));
|
||||
qctx_save(qctx, saved_qctx);
|
||||
isc_nmhandle_attach(qctx->client->handle,
|
||||
&qctx->client->restarthandle);
|
||||
isc_async_run(qctx->client->manager->loop, async_restart,
|
||||
saved_qctx);
|
||||
return (DNS_R_CONTINUE);
|
||||
if (qctx->want_restart) {
|
||||
if (qctx->client->query.restarts < MAX_RESTARTS) {
|
||||
query_ctx_t *saved_qctx = NULL;
|
||||
qctx->client->query.restarts++;
|
||||
saved_qctx = isc_mem_get(qctx->client->manager->mctx,
|
||||
sizeof(*saved_qctx));
|
||||
qctx_save(qctx, saved_qctx);
|
||||
isc_nmhandle_attach(qctx->client->handle,
|
||||
&qctx->client->restarthandle);
|
||||
isc_async_run(qctx->client->manager->loop,
|
||||
async_restart, saved_qctx);
|
||||
return (DNS_R_CONTINUE);
|
||||
} else {
|
||||
/*
|
||||
* This is e.g. a long CNAME chain which we cut short.
|
||||
*/
|
||||
qctx->client->query.attributes |=
|
||||
NS_QUERYATTR_PARTIALANSWER;
|
||||
qctx->client->message->rcode = dns_rcode_servfail;
|
||||
qctx->result = DNS_R_SERVFAIL;
|
||||
|
||||
/*
|
||||
* Send the answer back with a SERVFAIL result even
|
||||
* if recursion was requested.
|
||||
*/
|
||||
partial_result_with_servfail = true;
|
||||
|
||||
ns_client_extendederror(qctx->client, 0,
|
||||
"max. restarts reached");
|
||||
ns_client_log(qctx->client, NS_LOGCATEGORY_CLIENT,
|
||||
NS_LOGMODULE_QUERY, ISC_LOG_INFO,
|
||||
"query iterations limit reached");
|
||||
}
|
||||
}
|
||||
|
||||
if (qctx->result != ISC_R_SUCCESS &&
|
||||
(!PARTIALANSWER(qctx->client) || WANTRECURSION(qctx->client) ||
|
||||
(!PARTIALANSWER(qctx->client) ||
|
||||
(WANTRECURSION(qctx->client) && !partial_result_with_servfail) ||
|
||||
qctx->result == DNS_R_DROP))
|
||||
{
|
||||
if (qctx->result == DNS_R_DUPLICATE ||
|
||||
|
|
|
|||
Loading…
Reference in a new issue