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