From 71875eb25a88ded29b567df0180492fc46007ab0 Mon Sep 17 00:00:00 2001 From: Mark Andrews Date: Fri, 25 Oct 2024 14:43:03 +1100 Subject: [PATCH 1/3] Process NSID and DNS COOKIE options when returning BADVERS This will help identify the broken server if we happen to break EDNS version negotiation. It will also help protect the client from spoofed BADVERSION responses. (cherry picked from commit 0d9cab15551be8cdc06969c39eaf851732cda51d) --- lib/ns/client.c | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/lib/ns/client.c b/lib/ns/client.c index 0b38ffc078..048a6c72b7 100644 --- a/lib/ns/client.c +++ b/lib/ns/client.c @@ -1550,17 +1550,6 @@ process_opt(ns_client_t *client, dns_rdataset_t *opt) { * XXXRTH need library support for this! */ client->ednsversion = (opt->ttl & 0x00FF0000) >> 16; - if (client->ednsversion > DNS_EDNS_VERSION) { - ns_stats_increment(client->manager->sctx->nsstats, - ns_statscounter_badednsver); - result = ns_client_addopt(client, client->message, - &client->opt); - if (result == ISC_R_SUCCESS) { - result = DNS_R_BADVERS; - } - ns_client_error(client, result); - return result; - } /* Check for NSID request */ result = dns_rdataset_first(opt); @@ -1572,6 +1561,17 @@ process_opt(ns_client_t *client, dns_rdataset_t *opt) { while (isc_buffer_remaininglength(&optbuf) >= 4) { optcode = isc_buffer_getuint16(&optbuf); optlen = isc_buffer_getuint16(&optbuf); + /* + * When returning BADVERSION, only process + * DNS_OPT_NSID or DNS_OPT_COOKIE options. + */ + if (client->ednsversion > DNS_EDNS_VERSION && + optcode != DNS_OPT_NSID && + optcode != DNS_OPT_COOKIE) + { + isc_buffer_forward(&optbuf, optlen); + continue; + } switch (optcode) { case DNS_OPT_NSID: if (!WANTNSID(client)) { @@ -1643,6 +1643,18 @@ process_opt(ns_client_t *client, dns_rdataset_t *opt) { } } + if (client->ednsversion > DNS_EDNS_VERSION) { + ns_stats_increment(client->manager->sctx->nsstats, + ns_statscounter_badednsver); + result = ns_client_addopt(client, client->message, + &client->opt); + if (result == ISC_R_SUCCESS) { + result = DNS_R_BADVERS; + } + ns_client_error(client, result); + return result; + } + ns_stats_increment(client->manager->sctx->nsstats, ns_statscounter_edns0in); client->attributes |= NS_CLIENTATTR_WANTOPT; From 055253998e85ae3fd5ab603b35eab4c1e8610649 Mon Sep 17 00:00:00 2001 From: Mark Andrews Date: Thu, 27 Mar 2025 16:37:02 +1100 Subject: [PATCH 2/3] Extract and send server cookie with BADVERS retry A BADVERS response can also include EDNS SERVER COOKIE. Extract that from the OPT record and use it when resending the request. (cherry picked from commit 44140cad3b8e6567ec77175332f9da58da9d0617) --- bin/dig/dighost.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/bin/dig/dighost.c b/bin/dig/dighost.c index 90e8f0c0ad..ebd796ec65 100644 --- a/bin/dig/dighost.c +++ b/bin/dig/dighost.c @@ -4341,6 +4341,12 @@ recv_done(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region, dighost_comments(l, "BADVERS, retrying with EDNS version %u.", (unsigned int)newedns); l->edns = newedns; + /* + * Extract the server cookie so it can be sent in the retry. + */ + if (l->cookie == NULL && l->sendcookie) { + process_opt(l, msg); + } n = requeue_lookup(l, true); if (l->trace && l->trace_root) { n->rdtype = l->qrdtype; From 4f125b1e1c01916fa1520923b8e4694346498207 Mon Sep 17 00:00:00 2001 From: Mark Andrews Date: Fri, 28 Mar 2025 12:08:37 +1100 Subject: [PATCH 3/3] Check DNS COOKIE, NSID and BADVERS DNS COOKIE and NSID should also be being processed when returning BADVERS. Check that this has actually occured by looking for the cookie and nsid in the response. (cherry picked from commit f69b4bc5e0472035259dfc9df03ee0a9c02925dc) --- bin/tests/system/ednscompliance/ns1/named.conf.in | 1 + bin/tests/system/ednscompliance/tests.sh | 10 +++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/bin/tests/system/ednscompliance/ns1/named.conf.in b/bin/tests/system/ednscompliance/ns1/named.conf.in index 1334c85cf2..3a640fff22 100644 --- a/bin/tests/system/ednscompliance/ns1/named.conf.in +++ b/bin/tests/system/ednscompliance/ns1/named.conf.in @@ -21,6 +21,7 @@ options { listen-on-v6 { none; }; recursion no; dnssec-validation no; + server-id "ns1"; }; zone "." { diff --git a/bin/tests/system/ednscompliance/tests.sh b/bin/tests/system/ednscompliance/tests.sh index 515951adcf..3fae21142e 100644 --- a/bin/tests/system/ednscompliance/tests.sh +++ b/bin/tests/system/ednscompliance/tests.sh @@ -57,7 +57,7 @@ status=$((status + ret)) n=$((n + 1)) echo_i "Unknown EDNS version ($n)" ret=0 reason= -$DIG $DIGOPTS @10.53.0.1 +edns=100 +noednsnegotiation soa $zone >dig.out$n || ret=1 +$DIG $DIGOPTS @10.53.0.1 +edns=100 +nsid +noednsnegotiation soa $zone >dig.out$n || ret=1 grep "status: BADVERS," dig.out$n >/dev/null || { ret=1 reason="status" @@ -66,6 +66,14 @@ grep "EDNS: version: 0," dig.out$n >/dev/null || { ret=1 reason="version" } +grep "; COOKIE: .* (good)" dig.out$n >/dev/null || { + ret=1 + reason="cookie missing" +} +grep '; NSID: 6e 73 31 ("ns1")' dig.out$n >/dev/null || { + ret=1 + reason="nsid missing" +} grep "IN.SOA." dig.out$n >/dev/null && { ret=1 reason="soa"