1
1
mirror of https://github.com/systemd/systemd-stable.git synced 2025-03-08 20:58:20 +03:00

Merge pull request #18640 from poettering/resolved-dnssec-retry-harder

resolved: two dnssec retry/downgrade tweaks
This commit is contained in:
Lennart Poettering 2021-02-17 19:50:58 +01:00 committed by GitHub
commit 6283e71ba8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 50 additions and 3 deletions

View File

@ -378,6 +378,17 @@ void dns_server_packet_invalid(DnsServer *s, DnsServerFeatureLevel level) {
s->packet_invalid = true;
}
void dns_server_packet_do_off(DnsServer *s, DnsServerFeatureLevel level) {
assert(s);
/* Invoked whenever the DO flag was not copied from our request to the response. */
if (s->possible_feature_level != level)
return;
s->packet_do_off = true;
}
static bool dns_server_grace_period_expired(DnsServer *s) {
usec_t ts;
@ -494,6 +505,17 @@ DnsServerFeatureLevel dns_server_possible_feature_level(DnsServer *s) {
* when we can't use EDNS because the DNS server doesn't support it. */
log_level = LOG_NOTICE;
} else if (s->packet_do_off &&
DNS_SERVER_FEATURE_LEVEL_IS_DNSSEC(s->possible_feature_level) &&
dns_server_get_dnssec_mode(s) != DNSSEC_YES) {
/* The server didn't copy the DO bit from request to response, thus DNSSEC is not
* correctly implemented, let's downgrade if that's allowed. */
log_debug("Detected server didn't copy DO flag from request to response, downgrading feature level...");
s->possible_feature_level = DNS_SERVER_FEATURE_LEVEL_IS_TLS(s->possible_feature_level) ? DNS_SERVER_FEATURE_LEVEL_TLS_PLAIN :
DNS_SERVER_FEATURE_LEVEL_EDNS0;
} else if (s->packet_rrsig_missing &&
DNS_SERVER_FEATURE_LEVEL_IS_DNSSEC(s->possible_feature_level) &&
dns_server_get_dnssec_mode(s) != DNSSEC_YES) {
@ -653,6 +675,9 @@ bool dns_server_dnssec_supported(DnsServer *server) {
if (server->packet_rrsig_missing)
return false;
if (server->packet_do_off)
return false;
/* DNSSEC servers need to support TCP properly (see RFC5966), if they don't, we assume DNSSEC is borked too */
if (server->n_failed_tcp >= DNS_SERVER_FEATURE_RETRY_ATTEMPTS)
return false;
@ -898,6 +923,7 @@ void dns_server_reset_features(DnsServer *s) {
s->packet_bad_opt = false;
s->packet_rrsig_missing = false;
s->packet_do_off = false;
s->features_grace_period_usec = DNS_SERVER_FEATURE_GRACE_PERIOD_MIN_USEC;
@ -959,14 +985,16 @@ void dns_server_dump(DnsServer *s, FILE *f) {
"\tSeen truncated packet: %s\n"
"\tSeen OPT RR getting lost: %s\n"
"\tSeen RRSIG RR missing: %s\n"
"\tSeen invalid packet: %s\n",
"\tSeen invalid packet: %s\n"
"\tServer dropped DO flag: %s\n",
s->received_udp_packet_max,
s->n_failed_udp,
s->n_failed_tcp,
yes_no(s->packet_truncated),
yes_no(s->packet_bad_opt),
yes_no(s->packet_rrsig_missing),
yes_no(s->packet_invalid));
yes_no(s->packet_invalid),
yes_no(s->packet_do_off));
}
void dns_server_unref_stream(DnsServer *s) {

View File

@ -85,6 +85,7 @@ struct DnsServer {
bool packet_bad_opt:1; /* Set when OPT was missing or otherwise bad on reply */
bool packet_rrsig_missing:1; /* Set when RRSIG was missing */
bool packet_invalid:1; /* Set when we failed to parse a reply */
bool packet_do_off:1; /* Set when the server didn't copy DNSSEC DO flag from request to response */
usec_t verified_usec;
usec_t features_grace_period_usec;
@ -124,6 +125,7 @@ void dns_server_packet_rrsig_missing(DnsServer *s, DnsServerFeatureLevel level);
void dns_server_packet_bad_opt(DnsServer *s, DnsServerFeatureLevel level);
void dns_server_packet_rcode_downgrade(DnsServer *s, DnsServerFeatureLevel level);
void dns_server_packet_invalid(DnsServer *s, DnsServerFeatureLevel level);
void dns_server_packet_do_off(DnsServer *s, DnsServerFeatureLevel level);
DnsServerFeatureLevel dns_server_possible_feature_level(DnsServer *s);

View File

@ -844,6 +844,7 @@ static bool dns_transaction_dnssec_is_live(DnsTransaction *t) {
static int dns_transaction_dnssec_ready(DnsTransaction *t) {
DnsTransaction *dt;
int r;
assert(t);
@ -877,7 +878,7 @@ static int dns_transaction_dnssec_ready(DnsTransaction *t) {
case DNS_TRANSACTION_DNSSEC_FAILED:
/* We handle DNSSEC failures different from other errors, as we care about the DNSSEC
* validationr result */
* validation result */
log_debug("Auxiliary DNSSEC RR query failed validation: %s", dnssec_result_to_string(dt->answer_dnssec_result));
t->answer_dnssec_result = dt->answer_dnssec_result; /* Copy error code over */
@ -894,6 +895,18 @@ static int dns_transaction_dnssec_ready(DnsTransaction *t) {
return 1;
fail:
/* Some auxiliary DNSSEC transaction failed for some reason. Maybe we learned something about the
* server due to this failure, and the feature level is now different? Let's see and restart the
* transaction if so. If not, let's propagate the auxiliary failure.
*
* This is particularly relevant if an auxiliary request figured out that DNSSEC doesn't work, and we
* are in permissive DNSSEC mode, and thus should restart things without DNSSEC magic. */
r = dns_transaction_maybe_restart(t);
if (r < 0)
return r;
if (r > 0)
return 0; /* don't validate just yet, we restarted things */
t->answer_dnssec_result = DNSSEC_FAILED_AUXILIARY;
dns_transaction_complete(t, DNS_TRANSACTION_DNSSEC_FAILED);
return 0;
@ -1279,6 +1292,10 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p, bool encrypt
if (!p->opt)
dns_server_packet_bad_opt(t->server, t->current_feature_level);
/* Report that the server didn't copy our query DO bit from request to response */
if (DNS_PACKET_DO(t->sent) && !DNS_PACKET_DO(t->received))
dns_server_packet_do_off(t->server, t->current_feature_level);
/* Report that we successfully received a packet */
dns_server_packet_received(t->server, p->ipproto, t->current_feature_level, p->size);
}