diff --git a/lib/dns/include/dns/message.h b/lib/dns/include/dns/message.h index 0c7cb4ee44..637675fd9a 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 2564f09de0..3295b55a9a 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -7996,10 +7996,15 @@ rctx_opt(respctx_t *rctx) { } /* Cookie OK */ - query->rmessage->cc_ok = 1; - inc_stats(fctx->res, dns_resstatscounter_cookieok); - dns_adb_setcookie(fctx->adb, query->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); + dns_adb_setcookie(fctx->adb, query->addrinfo, + optvalue, optlen); + } break; default: break; @@ -9663,13 +9668,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