Don't cache lack of EDNS based on received responses

Caching prevents server upgrades being detected in a timely manner
and it can also prevent DNSSEC responses being requested.

(cherry picked from commit 90b2f94d9b)
This commit is contained in:
Mark Andrews 2025-01-16 16:24:05 +11:00 committed by Nicki Křížek
parent 6bf4390f25
commit c84d3ff4dc

View file

@ -391,7 +391,6 @@ struct fetchctx {
dns_fwdpolicy_t fwdpolicy;
isc_sockaddrlist_t bad;
ISC_LIST(struct tried) edns;
isc_sockaddrlist_t bad_edns;
dns_validator_t *validator;
ISC_LIST(dns_validator_t) validators;
dns_db_t *cache;
@ -2210,40 +2209,6 @@ cleanup_query:
return result;
}
static bool
bad_edns(fetchctx_t *fctx, isc_sockaddr_t *address) {
isc_sockaddr_t *sa;
for (sa = ISC_LIST_HEAD(fctx->bad_edns); sa != NULL;
sa = ISC_LIST_NEXT(sa, link))
{
if (isc_sockaddr_equal(sa, address)) {
return true;
}
}
return false;
}
static void
add_bad_edns(fetchctx_t *fctx, isc_sockaddr_t *address) {
isc_sockaddr_t *sa;
#ifdef ENABLE_AFL
if (dns_fuzzing_resolver) {
return;
}
#endif /* ifdef ENABLE_AFL */
if (bad_edns(fctx, address)) {
return;
}
sa = isc_mem_get(fctx->mctx, sizeof(*sa));
*sa = *address;
ISC_LIST_INITANDAPPEND(fctx->bad_edns, sa, link);
}
static struct tried *
triededns(fetchctx_t *fctx, isc_sockaddr_t *address) {
struct tried *tried;
@ -4386,12 +4351,6 @@ fctx_destroy(fetchctx_t *fctx) {
isc_mem_put(fctx->mctx, tried, sizeof(*tried));
}
for (sa = ISC_LIST_HEAD(fctx->bad_edns); sa != NULL; sa = next_sa) {
next_sa = ISC_LIST_NEXT(sa, link);
ISC_LIST_UNLINK(fctx->bad_edns, sa, link);
isc_mem_put(fctx->mctx, sa, sizeof(*sa));
}
if (fctx->nfails != NULL) {
isc_counter_detach(&fctx->nfails);
}
@ -4657,7 +4616,6 @@ fctx_create(dns_resolver_t *res, isc_loop_t *loop, const dns_name_t *name,
ISC_LIST_INIT(fctx->forwarders);
ISC_LIST_INIT(fctx->bad);
ISC_LIST_INIT(fctx->edns);
ISC_LIST_INIT(fctx->bad_edns);
ISC_LIST_INIT(fctx->validators);
atomic_init(&fctx->attributes, 0);
@ -8067,7 +8025,6 @@ rctx_parse(respctx_t *rctx) {
*/
rctx->retryopts |= DNS_FETCHOPT_NOEDNS0;
rctx->resend = true;
add_bad_edns(fctx, &query->addrinfo->sockaddr);
inc_stats(fctx->res, dns_resstatscounter_edns0fail);
} else {
rctx->broken_server = result;
@ -8085,7 +8042,6 @@ rctx_parse(respctx_t *rctx) {
*/
rctx->retryopts |= DNS_FETCHOPT_NOEDNS0;
rctx->resend = true;
add_bad_edns(fctx, &query->addrinfo->sockaddr);
inc_stats(fctx->res, dns_resstatscounter_edns0fail);
} else {
rctx->broken_server = DNS_R_UNEXPECTEDRCODE;
@ -8199,54 +8155,6 @@ rctx_edns(respctx_t *rctx) {
resquery_t *query = rctx->query;
fetchctx_t *fctx = rctx->fctx;
/*
* We have an affirmative response to the query and we have
* previously got a response from this server which indicated
* EDNS may not be supported so we can now cache the lack of
* EDNS support.
*/
if (rctx->opt == NULL && !EDNSOK(query->addrinfo) &&
(query->rmessage->rcode == dns_rcode_noerror ||
query->rmessage->rcode == dns_rcode_nxdomain ||
query->rmessage->rcode == dns_rcode_refused ||
query->rmessage->rcode == dns_rcode_yxdomain) &&
bad_edns(fctx, &query->addrinfo->sockaddr))
{
dns_message_logpacket(
query->rmessage, "received packet (bad edns) from",
&query->addrinfo->sockaddr, DNS_LOGCATEGORY_RESOLVER,
DNS_LOGMODULE_RESOLVER, ISC_LOG_DEBUG(3), fctx->mctx);
dns_adb_changeflags(fctx->adb, query->addrinfo,
FCTX_ADDRINFO_NOEDNS0,
FCTX_ADDRINFO_NOEDNS0);
} else if (rctx->opt == NULL &&
(query->rmessage->flags & DNS_MESSAGEFLAG_TC) == 0 &&
!EDNSOK(query->addrinfo) &&
(query->rmessage->rcode == dns_rcode_noerror ||
query->rmessage->rcode == dns_rcode_nxdomain) &&
(rctx->retryopts & DNS_FETCHOPT_NOEDNS0) == 0)
{
/*
* We didn't get a OPT record in response to a EDNS
* query.
*
* Old versions of named incorrectly drop the OPT record
* when there is a signed, truncated response so we
* check that TC is not set.
*
* Record that the server is not talking EDNS. While
* this should be safe to do for any rcode we limit it
* to NOERROR and NXDOMAIN.
*/
dns_message_logpacket(
query->rmessage, "received packet (no opt) from",
&query->addrinfo->sockaddr, DNS_LOGCATEGORY_RESOLVER,
DNS_LOGMODULE_RESOLVER, ISC_LOG_DEBUG(3), fctx->mctx);
dns_adb_changeflags(fctx->adb, query->addrinfo,
FCTX_ADDRINFO_NOEDNS0,
FCTX_ADDRINFO_NOEDNS0);
}
/*
* If we get a non error EDNS response record the fact so we
* won't fallback to plain DNS in the future for this server.
@ -9861,7 +9769,6 @@ rctx_badserver(respctx_t *rctx, isc_result_t result) {
/*
* Remember that they may not like EDNS0.
*/
add_bad_edns(fctx, &query->addrinfo->sockaddr);
inc_stats(fctx->res, dns_resstatscounter_edns0fail);
} else if (rcode == dns_rcode_formerr) {
if (query->rmessage->cc_echoed) {