diff --git a/src/resolve/resolved-dns-server.c b/src/resolve/resolved-dns-server.c index 04a8e92d73..9bb716e2c1 100644 --- a/src/resolve/resolved-dns-server.c +++ b/src/resolve/resolved-dns-server.c @@ -362,9 +362,8 @@ void dns_server_packet_rcode_downgrade(DnsServer *s, DnsServerFeatureLevel level if (s->possible_feature_level > level) { s->possible_feature_level = level; dns_server_reset_counters(s); + log_debug("Downgrading transaction feature level fixed an RCODE error, downgrading server %s too.", strna(dns_server_string_full(s))); } - - log_debug("Downgrading transaction feature level fixed an RCODE error, downgrading server %s too.", strna(dns_server_string_full(s))); } void dns_server_packet_invalid(DnsServer *s, DnsServerFeatureLevel level) { diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c index c2ca181ab7..594ce5e27b 100644 --- a/src/resolve/resolved-dns-transaction.c +++ b/src/resolve/resolved-dns-transaction.c @@ -1142,22 +1142,35 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p, bool encrypt break; } - /* Reduce this feature level by one and try again. */ - switch (t->current_feature_level) { - case DNS_SERVER_FEATURE_LEVEL_TLS_DO: - t->clamp_feature_level_servfail = DNS_SERVER_FEATURE_LEVEL_TLS_PLAIN; - break; - case DNS_SERVER_FEATURE_LEVEL_TLS_PLAIN + 1: - /* Skip plain TLS when TLS is not supported */ - t->clamp_feature_level_servfail = DNS_SERVER_FEATURE_LEVEL_TLS_PLAIN - 1; - break; - default: - t->clamp_feature_level_servfail = t->current_feature_level - 1; - } + /* SERVFAIL can happen for many reasons and may be transient. + * To avoid unnecessary downgrades retry once with the initial level. + * Check for clamp_feature_level_servfail having an invalid value as a sign that this is the + * first attempt to downgrade. If so, clamp to the current value so that the transaction + * is retried without actually downgrading. If the next try also fails we will downgrade by + * hitting the else branch below. */ + if (DNS_PACKET_RCODE(p) == DNS_RCODE_SERVFAIL && + t->clamp_feature_level_servfail < 0) { + t->clamp_feature_level_servfail = t->current_feature_level; + log_debug("Server returned error %s, retrying transaction.", + dns_rcode_to_string(DNS_PACKET_RCODE(p))); + } else { + /* Reduce this feature level by one and try again. */ + switch (t->current_feature_level) { + case DNS_SERVER_FEATURE_LEVEL_TLS_DO: + t->clamp_feature_level_servfail = DNS_SERVER_FEATURE_LEVEL_TLS_PLAIN; + break; + case DNS_SERVER_FEATURE_LEVEL_TLS_PLAIN + 1: + /* Skip plain TLS when TLS is not supported */ + t->clamp_feature_level_servfail = DNS_SERVER_FEATURE_LEVEL_TLS_PLAIN - 1; + break; + default: + t->clamp_feature_level_servfail = t->current_feature_level - 1; + } - log_debug("Server returned error %s, retrying transaction with reduced feature level %s.", - dns_rcode_to_string(DNS_PACKET_RCODE(p)), - dns_server_feature_level_to_string(t->clamp_feature_level_servfail)); + log_debug("Server returned error %s, retrying transaction with reduced feature level %s.", + dns_rcode_to_string(DNS_PACKET_RCODE(p)), + dns_server_feature_level_to_string(t->clamp_feature_level_servfail)); + } dns_transaction_retry(t, false /* use the same server */); return;