From e7e29278a8041fe4dd734c61402b679e0a8cee3d Mon Sep 17 00:00:00 2001 From: Mark Andrews Date: Mon, 8 May 2023 17:39:51 +1000 Subject: [PATCH] Handle FORMERR on unknown EDNS option that are echoed If the resolver received a FORMERR response to a request with an DNS COOKIE option present that echoes the option back, resend the request without an DNS COOKIE option present. (cherry picked from commit f3b24ba789bed8e561519909709e1671bb290c7f) --- lib/dns/include/dns/message.h | 1 + lib/dns/resolver.c | 42 ++++++++++++++++++++++++----------- 2 files changed, 30 insertions(+), 13 deletions(-) diff --git a/lib/dns/include/dns/message.h b/lib/dns/include/dns/message.h index d769fe94dc..b5d9a5a168 100644 --- a/lib/dns/include/dns/message.h +++ b/lib/dns/include/dns/message.h @@ -279,6 +279,7 @@ struct dns_message { unsigned int free_saved : 1; unsigned int cc_ok : 1; unsigned int cc_bad : 1; + unsigned int cc_echoed : 1; unsigned int tkey : 1; unsigned int rdclass_set : 1; unsigned int fuzzing : 1; diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index 0dddb43de7..f2c2e1cace 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -8380,12 +8380,18 @@ rctx_opt(respctx_t *rctx) { memcmp(cookie, optvalue, CLIENT_COOKIE_SIZE) == 0) { - query->rmessage->cc_ok = 1; - inc_stats(fctx->res, - dns_resstatscounter_cookieok); - addrinfo = query->addrinfo; - dns_adb_setcookie(fctx->adb, addrinfo, - optvalue, optlen); + if (optlen == CLIENT_COOKIE_SIZE) { + query->rmessage->cc_echoed = 1; + } else { + query->rmessage->cc_ok = 1; + inc_stats( + fctx->res, + dns_resstatscounter_cookieok); + addrinfo = query->addrinfo; + dns_adb_setcookie( + fctx->adb, addrinfo, + optvalue, optlen); + } } else { query->rmessage->cc_bad = 1; } @@ -10061,13 +10067,23 @@ rctx_badserver(respctx_t *rctx, isc_result_t result) { add_bad_edns(fctx, &query->addrinfo->sockaddr); inc_stats(fctx->res, dns_resstatscounter_edns0fail); } else if (rcode == dns_rcode_formerr) { - /* - * The server (or forwarder) doesn't understand us, - * but others might. - */ - rctx->next_server = true; - rctx->broken_server = DNS_R_REMOTEFORMERR; - log_formerr(fctx, "server sent FORMERR"); + if (query->rmessage->cc_echoed) { + /* + * Retry without DNS COOKIE. + */ + query->addrinfo->flags |= FCTX_ADDRINFO_NOCOOKIE; + rctx->resend = true; + log_formerr(fctx, "server sent FORMERR with echoed DNS " + "COOKIE"); + } else { + /* + * The server (or forwarder) doesn't understand us, + * but others might. + */ + rctx->next_server = true; + rctx->broken_server = DNS_R_REMOTEFORMERR; + log_formerr(fctx, "server sent FORMERR"); + } } else if (rcode == dns_rcode_badvers) { unsigned int version; #if DNS_EDNS_VERSION > 0