From 946931ccb710b45c538a57f9c9e404ea87591ed9 Mon Sep 17 00:00:00 2001 From: Aram Sargsyan Date: Thu, 6 Jun 2024 12:06:59 +0000 Subject: [PATCH] Return SERVFAIL for a too long CNAME chain Due to the maximum query restart limitation a long CNAME chain it is cut after 16 queries but named still returns NOERROR. Return SERVFAIL instead and the partial answer. (cherry picked from commit b621f1d88e2a8a4e22d871e90e58ef4bd4b6050f) --- lib/ns/query.c | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/lib/ns/query.c b/lib/ns/query.c index 132a151bed..866ea9d509 100644 --- a/lib/ns/query.c +++ b/lib/ns/query.c @@ -11910,7 +11910,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"); @@ -11944,13 +11944,36 @@ 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) { - qctx->client->query.restarts++; - return (ns__query_start(qctx)); + if (qctx->want_restart) { + if (qctx->client->query.restarts < MAX_RESTARTS) { + qctx->client->query.restarts++; + return (ns__query_start(qctx)); + } 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 ||