mirror of
https://github.com/isc-projects/bind9.git
synced 2026-06-04 20:02:05 -04:00
Add EDE 22 No reachable authority code
Add support for Extended DNS Errors (EDE) error 22: No reachable
authority. This occurs when after a timeout delay when the resolver is
trying to query an authority server.
(cherry picked from commit d13e94b930)
Commit amended in order to fix usage of isc_log_write (adding dns_lctx
parameter)
This commit is contained in:
parent
fc14b62e92
commit
c586d9a658
14 changed files with 243 additions and 13 deletions
|
|
@ -7222,7 +7222,8 @@ tat_done(void *arg) {
|
|||
if (resp->db != NULL) {
|
||||
dns_db_detach(&resp->db);
|
||||
}
|
||||
isc_mem_putanddetach(&resp->mctx, resp, sizeof(*resp));
|
||||
|
||||
dns_resolver_freefresp(&resp);
|
||||
dns_resolver_destroyfetch(&tat->fetch);
|
||||
if (dns_rdataset_isassociated(&tat->rdataset)) {
|
||||
dns_rdataset_disassociate(&tat->rdataset);
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ echo_i "checking no response handling with a longer than resolver-query-timeout
|
|||
ret=0
|
||||
dig_with_opts +tcp +tries=1 +timeout=7 noresponse.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 "EDE: 22 (No Reachable Authority)" dig.out.ns1.test${n} >/dev/null || ret=1
|
||||
if [ $ret != 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
||||
|
|
|
|||
|
|
@ -2944,7 +2944,7 @@ check_result:
|
|||
out:
|
||||
dns_resolver_destroyfetch(&fetch->fetch);
|
||||
free_adbfetch(adb, &fetch);
|
||||
isc_mem_putanddetach(&resp->mctx, resp, sizeof(*resp));
|
||||
dns_resolver_freefresp(&resp);
|
||||
if (astat != DNS_ADB_CANCELED) {
|
||||
clean_finds_at_name(name, astat, address_type);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -555,7 +555,7 @@ client_resfind(resctx_t *rctx, dns_fetchresponse_t *resp) {
|
|||
fname = resp->foundname;
|
||||
INSIST(resp->rdataset == rctx->rdataset);
|
||||
INSIST(resp->sigrdataset == rctx->sigrdataset);
|
||||
isc_mem_putanddetach(&resp->mctx, resp, sizeof(*resp));
|
||||
dns_resolver_freefresp(&resp);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -151,6 +151,15 @@
|
|||
#define DNS_EDE_NETWORKERROR 23 /*%< Network Error */
|
||||
#define DNS_EDE_INVALIDDATA 24 /*%< Invalid Data */
|
||||
|
||||
typedef struct dns_ede dns_ede_t;
|
||||
struct dns_ede {
|
||||
uint16_t info_code;
|
||||
char *extra_text;
|
||||
ISC_LINK(dns_ede_t) link;
|
||||
};
|
||||
|
||||
typedef ISC_LIST(dns_ede_t) dns_edelist_t;
|
||||
|
||||
/*
|
||||
* From RFC 8914:
|
||||
* Because long EXTRA-TEXT fields may trigger truncation (which is undesirable
|
||||
|
|
@ -1520,4 +1529,32 @@ dns_message_createpools(isc_mem_t *mctx, isc_mempool_t **namepoolp,
|
|||
void
|
||||
dns_message_destroypools(isc_mempool_t **namepoolp, isc_mempool_t **rdspoolp);
|
||||
|
||||
void
|
||||
dns_ede_append(isc_mem_t *mctx, dns_edelist_t *list, uint16_t info_code,
|
||||
const char *extra_text);
|
||||
/*%<
|
||||
* Adds a new EDE message at the end of 'list'. If 'extra_text' is non
|
||||
* NULL, the string is synchronously copied internally, so the called
|
||||
* doesn't have to keep it alive once this call returns. RFC8914
|
||||
* section 4 define the valid range of possible numbers for
|
||||
* 'info_code'.
|
||||
*
|
||||
* Requires:
|
||||
* \li mctx to be non NULL;
|
||||
* \li list to be non NULL;
|
||||
* \li info_code to be valid;
|
||||
* \li extra_text can be NULL or non NULL, do not take ownership.
|
||||
*/
|
||||
|
||||
void
|
||||
dns_ede_unlinkall(isc_mem_t *mctx, dns_edelist_t *list);
|
||||
/*%<
|
||||
* Unlink all elements from from 'list' and free it from
|
||||
* memory. Optional text owned by elements is also freed.
|
||||
*
|
||||
* Requires:
|
||||
* \li mctx to be non NULL;
|
||||
* \li list to be non NULL;
|
||||
*/
|
||||
|
||||
ISC_LANG_ENDDECLS
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@
|
|||
#include <isc/types.h>
|
||||
|
||||
#include <dns/fixedname.h>
|
||||
#include <dns/message.h>
|
||||
#include <dns/types.h>
|
||||
|
||||
/* Add -DDNS_RESOLVER_TRACE=1 to CFLAGS for detailed reference tracing */
|
||||
|
|
@ -81,6 +82,7 @@ struct dns_fetchresponse {
|
|||
isc_mem_t *mctx;
|
||||
isc_result_t result;
|
||||
isc_result_t vresult;
|
||||
dns_edelist_t edelist;
|
||||
dns_rdatatype_t qtype;
|
||||
dns_db_t *db;
|
||||
dns_dbnode_t *node;
|
||||
|
|
@ -632,4 +634,15 @@ dns_resolver_getquerystats(dns_resolver_t *res, dns_stats_t **statsp);
|
|||
*
|
||||
*\li 'statsp' != NULL && '*statsp' != NULL
|
||||
*/
|
||||
|
||||
void
|
||||
dns_resolver_freefresp(dns_fetchresponse_t **frespp);
|
||||
/*%<
|
||||
* Free a dns_fetchresponse_t object and internal owned object as
|
||||
* well.
|
||||
*
|
||||
* Requires:
|
||||
* \li 'frespp' is valid. No-op if *frespp == NULL
|
||||
*/
|
||||
|
||||
ISC_LANG_ENDDECLS
|
||||
|
|
|
|||
|
|
@ -5015,3 +5015,57 @@ dns_message_destroypools(isc_mempool_t **namepoolp, isc_mempool_t **rdspoolp) {
|
|||
isc_mempool_destroy(rdspoolp);
|
||||
isc_mempool_destroy(namepoolp);
|
||||
}
|
||||
|
||||
void
|
||||
dns_ede_append(isc_mem_t *mctx, dns_edelist_t *list, uint16_t info_code,
|
||||
const char *extra_text) {
|
||||
REQUIRE(mctx);
|
||||
REQUIRE(list);
|
||||
REQUIRE(info_code <= 24);
|
||||
|
||||
dns_ede_t *ede = isc_mem_get(mctx, sizeof(*ede));
|
||||
*ede = (dns_ede_t){
|
||||
.info_code = info_code,
|
||||
.extra_text = NULL,
|
||||
.link = ISC_LINK_INITIALIZER,
|
||||
};
|
||||
|
||||
if (extra_text) {
|
||||
size_t len = strlen(extra_text);
|
||||
|
||||
if (len >= DNS_EDE_EXTRATEXT_LEN) {
|
||||
isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
|
||||
DNS_LOGMODULE_MESSAGE, ISC_LOG_PRINTTIME,
|
||||
"truncate EDE code %hu text: %s",
|
||||
info_code, extra_text);
|
||||
len = DNS_EDE_EXTRATEXT_LEN - 1;
|
||||
}
|
||||
|
||||
ede->extra_text = isc_mem_allocate(mctx, len + 1);
|
||||
strncpy(ede->extra_text, extra_text, len);
|
||||
ede->extra_text[len] = '\0';
|
||||
}
|
||||
|
||||
ISC_LIST_APPEND(*list, ede, link);
|
||||
}
|
||||
|
||||
void
|
||||
dns_ede_unlinkall(isc_mem_t *mctx, dns_edelist_t *list) {
|
||||
dns_ede_t *ede, *next;
|
||||
|
||||
REQUIRE(mctx);
|
||||
REQUIRE(list);
|
||||
|
||||
for (ede = ISC_LIST_HEAD(*list); ede != NULL; ede = next) {
|
||||
next = ISC_LIST_NEXT(ede, link);
|
||||
|
||||
ISC_LIST_UNLINK(*list, ede, link);
|
||||
if (ede->extra_text) {
|
||||
isc_mem_free(mctx, ede->extra_text);
|
||||
ede->extra_text = NULL;
|
||||
}
|
||||
isc_mem_put(mctx, ede, sizeof(*ede));
|
||||
}
|
||||
|
||||
INSIST(ISC_LIST_EMPTY(*list));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -179,7 +179,7 @@ fetch_done(void *arg) {
|
|||
dns_db_detach(&resp->db);
|
||||
}
|
||||
|
||||
isc_mem_putanddetach(&resp->mctx, resp, sizeof(*resp));
|
||||
dns_resolver_freefresp(&resp);
|
||||
|
||||
switch (eresult) {
|
||||
case ISC_R_SUCCESS:
|
||||
|
|
|
|||
|
|
@ -359,6 +359,7 @@ struct fetchctx {
|
|||
bool spilled;
|
||||
ISC_LINK(struct fetchctx) link;
|
||||
ISC_LIST(dns_fetchresponse_t) resps;
|
||||
dns_edelist_t edelist;
|
||||
|
||||
/*% Locked by loop event serialization. */
|
||||
dns_fixedname_t dfname;
|
||||
|
|
@ -1335,6 +1336,8 @@ fctx_cleanup(fetchctx_t *fctx) {
|
|||
ISC_LIST_UNLINK(fctx->altaddrs, addr, publink);
|
||||
dns_adb_freeaddrinfo(fctx->adb, &addr);
|
||||
}
|
||||
|
||||
dns_ede_unlinkall(fctx->mctx, &fctx->edelist);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -1597,6 +1600,17 @@ fctx_sendevents(fetchctx_t *fctx, isc_result_t result) {
|
|||
resp->result == DNS_R_NCACHENXRRSET);
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy EDE that occured during the resolution to all
|
||||
* clients
|
||||
*/
|
||||
for (dns_ede_t *ede = ISC_LIST_HEAD(fctx->edelist); ede != NULL;
|
||||
ede = ISC_LIST_NEXT(ede, link))
|
||||
{
|
||||
dns_ede_append(resp->mctx, &resp->edelist,
|
||||
ede->info_code, ede->extra_text);
|
||||
}
|
||||
|
||||
FCTXTRACE("post response event");
|
||||
isc_async_run(resp->loop, resp->cb, resp);
|
||||
}
|
||||
|
|
@ -4147,7 +4161,8 @@ resume_qmin(void *arg) {
|
|||
}
|
||||
|
||||
result = resp->result;
|
||||
isc_mem_putanddetach(&resp->mctx, resp, sizeof(*resp));
|
||||
|
||||
dns_resolver_freefresp(&resp);
|
||||
|
||||
LOCK(&fctx->lock);
|
||||
if (SHUTTINGDOWN(fctx)) {
|
||||
|
|
@ -4293,6 +4308,7 @@ fctx_destroy(fetchctx_t *fctx) {
|
|||
REQUIRE(ISC_LIST_EMPTY(fctx->queries));
|
||||
REQUIRE(ISC_LIST_EMPTY(fctx->finds));
|
||||
REQUIRE(ISC_LIST_EMPTY(fctx->altfinds));
|
||||
REQUIRE(ISC_LIST_EMPTY(fctx->edelist));
|
||||
REQUIRE(atomic_load_acquire(&fctx->pending) == 0);
|
||||
REQUIRE(ISC_LIST_EMPTY(fctx->validators));
|
||||
REQUIRE(fctx->state != fetchstate_active);
|
||||
|
|
@ -4356,6 +4372,12 @@ fctx_expired(void *arg) {
|
|||
DNS_LOGMODULE_RESOLVER, ISC_LOG_INFO,
|
||||
"shut down hung fetch while resolving %p(%s)", fctx,
|
||||
fctx->info);
|
||||
|
||||
LOCK(&fctx->lock);
|
||||
dns_ede_append(fctx->mctx, &fctx->edelist, DNS_EDE_NOREACHABLEAUTH,
|
||||
NULL);
|
||||
UNLOCK(&fctx->lock);
|
||||
|
||||
fctx_done_detach(&fctx, DNS_R_SERVFAIL);
|
||||
}
|
||||
|
||||
|
|
@ -4419,6 +4441,7 @@ fctx_add_event(fetchctx_t *fctx, isc_loop_t *loop, const isc_sockaddr_t *client,
|
|||
resp = isc_mem_get(fctx->mctx, sizeof(*resp));
|
||||
*resp = (dns_fetchresponse_t){
|
||||
.result = DNS_R_SERVFAIL,
|
||||
.edelist = ISC_LIST_INITIALIZER,
|
||||
.qtype = fctx->type,
|
||||
.rdataset = rdataset,
|
||||
.sigrdataset = sigrdataset,
|
||||
|
|
@ -4509,6 +4532,7 @@ fctx_create(dns_resolver_t *res, isc_loop_t *loop, const dns_name_t *name,
|
|||
.loop = loop,
|
||||
.nvalidations = atomic_load_relaxed(&res->maxvalidations),
|
||||
.nfails = atomic_load_relaxed(&res->maxvalidationfails),
|
||||
.edelist = ISC_LIST_INITIALIZER,
|
||||
};
|
||||
|
||||
isc_mem_attach(mctx, &fctx->mctx);
|
||||
|
|
@ -7029,7 +7053,8 @@ resume_dslookup(void *arg) {
|
|||
/* Preserve data from resp before freeing it. */
|
||||
frdataset = resp->rdataset; /* a.k.a. fctx->nsrrset */
|
||||
result = resp->result;
|
||||
isc_mem_putanddetach(&resp->mctx, resp, sizeof(*resp));
|
||||
|
||||
dns_resolver_freefresp(&resp);
|
||||
|
||||
LOCK(&fctx->lock);
|
||||
if (SHUTTINGDOWN(fctx)) {
|
||||
|
|
@ -10086,7 +10111,7 @@ prime_done(void *arg) {
|
|||
INSIST(resp->sigrdataset == NULL);
|
||||
|
||||
isc_mem_put(res->mctx, resp->rdataset, sizeof(*resp->rdataset));
|
||||
isc_mem_putanddetach(&resp->mctx, resp, sizeof(*resp));
|
||||
dns_resolver_freefresp(&resp);
|
||||
dns_resolver_destroyfetch(&fetch);
|
||||
}
|
||||
|
||||
|
|
@ -11021,3 +11046,18 @@ dns_resolver_getquerystats(dns_resolver_t *res, dns_stats_t **statsp) {
|
|||
dns_stats_attach(res->querystats, statsp);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
dns_resolver_freefresp(dns_fetchresponse_t **frespp) {
|
||||
REQUIRE(frespp);
|
||||
|
||||
if (*frespp == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
dns_fetchresponse_t *fresp = *frespp;
|
||||
|
||||
*frespp = NULL;
|
||||
dns_ede_unlinkall(fresp->mctx, &fresp->edelist);
|
||||
isc_mem_putanddetach(&fresp->mctx, fresp, sizeof(*fresp));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -448,7 +448,7 @@ fetch_callback_dnskey(void *arg) {
|
|||
}
|
||||
|
||||
cleanup:
|
||||
isc_mem_putanddetach(&resp->mctx, resp, sizeof(*resp));
|
||||
dns_resolver_freefresp(&resp);
|
||||
validate_async_done(val, result);
|
||||
dns_validator_detach(&val);
|
||||
}
|
||||
|
|
@ -578,7 +578,7 @@ fetch_callback_ds(void *arg) {
|
|||
}
|
||||
|
||||
cleanup:
|
||||
isc_mem_putanddetach(&resp->mctx, resp, sizeof(*resp));
|
||||
dns_resolver_freefresp(&resp);
|
||||
validate_async_done(val, result);
|
||||
dns_validator_detach(&val);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10801,9 +10801,9 @@ cleanup:
|
|||
dns_rdataset_disassociate(dnskeysigs);
|
||||
}
|
||||
|
||||
dns_resolver_freefresp(&resp);
|
||||
dns_name_free(keyname, mctx);
|
||||
isc_mem_putanddetach(&kfetch->mctx, kfetch, sizeof(dns_keyfetch_t));
|
||||
isc_mem_putanddetach(&resp->mctx, resp, sizeof(*resp));
|
||||
|
||||
if (secroots != NULL) {
|
||||
dns_keytable_detach(&secroots);
|
||||
|
|
@ -21781,7 +21781,8 @@ cleanup:
|
|||
if (dns_rdataset_isassociated(nssigset)) {
|
||||
dns_rdataset_disassociate(nssigset);
|
||||
}
|
||||
isc_mem_putanddetach(&resp->mctx, resp, sizeof(*resp));
|
||||
|
||||
dns_resolver_freefresp(&resp);
|
||||
|
||||
if (levelup) {
|
||||
UNLOCK_ZONE(zone);
|
||||
|
|
|
|||
|
|
@ -2560,8 +2560,7 @@ free_fresp(ns_client_t *client, dns_fetchresponse_t **frespp) {
|
|||
ns_client_putrdataset(client, &fresp->sigrdataset);
|
||||
}
|
||||
|
||||
*frespp = NULL;
|
||||
isc_mem_putanddetach(&fresp->mctx, fresp, sizeof(*fresp));
|
||||
dns_resolver_freefresp(frespp);
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
|
|
@ -6364,6 +6363,13 @@ fetch_callback(void *arg) {
|
|||
client->query.attributes &= ~NS_QUERYATTR_RECURSING;
|
||||
client->state = NS_CLIENTSTATE_WORKING;
|
||||
|
||||
for (dns_ede_t *ede = ISC_LIST_HEAD(resp->edelist); ede != NULL;
|
||||
ede = ISC_LIST_NEXT(ede, link))
|
||||
{
|
||||
ns_client_extendederror(client, ede->info_code,
|
||||
ede->extra_text);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize a new qctx and use it to either resume from
|
||||
* recursion or clean up after cancelation. Transfer
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ check_PROGRAMS = \
|
|||
dispatch_test \
|
||||
dns64_test \
|
||||
dst_test \
|
||||
ede_test \
|
||||
keytable_test \
|
||||
name_test \
|
||||
nametree_test \
|
||||
|
|
|
|||
76
tests/dns/ede_test.c
Normal file
76
tests/dns/ede_test.c
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <sched.h> /* IWYU pragma: keep */
|
||||
#include <setjmp.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define UNIT_TESTING
|
||||
#include <cmocka.h>
|
||||
|
||||
#include <isc/buffer.h>
|
||||
#include <isc/net.h>
|
||||
#include <isc/timer.h>
|
||||
#include <isc/tls.h>
|
||||
#include <isc/util.h>
|
||||
|
||||
#include <dns/message.h>
|
||||
|
||||
#include <tests/isc.h>
|
||||
|
||||
ISC_RUN_TEST_IMPL(ede_enqueue_unlink) {
|
||||
dns_edelist_t list;
|
||||
dns_ede_t *ede = NULL;
|
||||
const char *msg1 = "abcd";
|
||||
const char *msg2 = "abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabc"
|
||||
"dabcdabcdadcdabcd";
|
||||
|
||||
ISC_LIST_INIT(list);
|
||||
|
||||
dns_ede_append(mctx, &list, 22, NULL);
|
||||
dns_ede_append(mctx, &list, 12, msg1);
|
||||
dns_ede_append(mctx, &list, 4, msg2);
|
||||
|
||||
ede = ISC_LIST_HEAD(list);
|
||||
assert_non_null(ede);
|
||||
assert_int_equal(ede->info_code, 22);
|
||||
assert_null(ede->extra_text);
|
||||
|
||||
ede = ISC_LIST_NEXT(ede, link);
|
||||
assert_non_null(ede);
|
||||
assert_int_equal(ede->info_code, 12);
|
||||
assert_string_equal(ede->extra_text, msg1);
|
||||
assert_ptr_not_equal(ede->extra_text, msg1);
|
||||
|
||||
ede = ISC_LIST_NEXT(ede, link);
|
||||
assert_non_null(ede);
|
||||
assert_int_equal(ede->info_code, 4);
|
||||
assert_string_not_equal(ede->extra_text, msg2);
|
||||
assert_ptr_not_equal(ede->extra_text, msg2);
|
||||
assert_int_equal(strlen(ede->extra_text), 63);
|
||||
|
||||
dns_ede_unlinkall(mctx, &list);
|
||||
assert_true(ISC_LIST_EMPTY(list));
|
||||
}
|
||||
|
||||
ISC_TEST_LIST_START
|
||||
|
||||
ISC_TEST_ENTRY(ede_enqueue_unlink)
|
||||
|
||||
ISC_TEST_LIST_END
|
||||
|
||||
ISC_TEST_MAIN
|
||||
Loading…
Reference in a new issue