diff options
author | Ronan Pigott <ronan@rjp.ie> | 2023-12-21 21:50:45 -0700 |
---|---|---|
committer | Ronan Pigott <ronan@rjp.ie> | 2024-01-03 17:35:02 -0700 |
commit | 9ca133e97a0c8795b1f293ccea4965b4ad1accc4 (patch) | |
tree | 82bc44e03ffd3faaef8159917ae0fa565e26ab15 | |
parent | resolved: support RFC 8914 EDE error codes (diff) | |
download | systemd-9ca133e97a0c8795b1f293ccea4965b4ad1accc4.tar.xz systemd-9ca133e97a0c8795b1f293ccea4965b4ad1accc4.zip |
resolved: add transaction result for upstream failures
This new transaction result is emitted when the upstream server
indicates a fatal error that we will not try to recover from.
Currently, it is emitted when a validating recursive resolver reports an
error validating dnssec records for a domain. The extended error message
should help give context to the admin.
-rw-r--r-- | src/resolve/resolved-bus.c | 5 | ||||
-rw-r--r-- | src/resolve/resolved-dns-query.c | 13 | ||||
-rw-r--r-- | src/resolve/resolved-dns-query.h | 2 | ||||
-rw-r--r-- | src/resolve/resolved-dns-transaction.c | 32 | ||||
-rw-r--r-- | src/resolve/resolved-dns-transaction.h | 3 |
5 files changed, 51 insertions, 4 deletions
diff --git a/src/resolve/resolved-bus.c b/src/resolve/resolved-bus.c index ef3f5237a9e..8c9475cd3de 100644 --- a/src/resolve/resolved-bus.c +++ b/src/resolve/resolved-bus.c @@ -189,6 +189,11 @@ static int reply_query_state(DnsQuery *q) { return sd_bus_reply_method_error(req, &error); } + case DNS_TRANSACTION_UPSTREAM_DNSSEC_FAILURE: + return reply_method_errorf(q, BUS_ERROR_DNSSEC_FAILED, "DNSSEC validation failed upstream: %s%s%s", + dns_ede_rcode_to_string(q->answer_ede_rcode), + isempty(q->answer_ede_msg) ? "" : ": ", q->answer_ede_msg); + case DNS_TRANSACTION_NULL: case DNS_TRANSACTION_PENDING: case DNS_TRANSACTION_VALIDATING: diff --git a/src/resolve/resolved-dns-query.c b/src/resolve/resolved-dns-query.c index 7eb6b9736e2..d94fe1da997 100644 --- a/src/resolve/resolved-dns-query.c +++ b/src/resolve/resolved-dns-query.c @@ -421,6 +421,8 @@ DnsQuery *dns_query_free(DnsQuery *q) { dns_answer_unref(q->reply_authoritative); dns_answer_unref(q->reply_additional); + free(q->answer_ede_msg); + if (q->request_stream) { /* Detach the stream from our query, in case something else keeps a reference to it. */ (void) set_remove(q->request_stream->queries, q); @@ -896,9 +898,20 @@ static void dns_query_accept(DnsQuery *q, DnsQueryCandidate *c) { !FLAGS_SET(t->answer_query_flags, SD_RESOLVED_AUTHENTICATED)) continue; + char *answer_ede_msg = NULL; + if (t->answer_ede_msg) { + answer_ede_msg = strdup(t->answer_ede_msg); + if (!answer_ede_msg) { + log_oom(); + goto fail; + } + } + DNS_ANSWER_REPLACE(q->answer, dns_answer_ref(t->answer)); q->answer_rcode = t->answer_rcode; q->answer_dnssec_result = t->answer_dnssec_result; + q->answer_ede_rcode = t->answer_ede_rcode; + q->answer_ede_msg = answer_ede_msg; q->answer_query_flags = t->answer_query_flags | dns_transaction_source_to_query_flags(t->answer_source); q->answer_errno = t->answer_errno; DNS_PACKET_REPLACE(q->answer_full_packet, dns_packet_ref(t->received)); diff --git a/src/resolve/resolved-dns-query.h b/src/resolve/resolved-dns-query.h index 2723299bee5..74ad2c73500 100644 --- a/src/resolve/resolved-dns-query.h +++ b/src/resolve/resolved-dns-query.h @@ -74,6 +74,8 @@ struct DnsQuery { DnsAnswer *answer; int answer_rcode; DnssecResult answer_dnssec_result; + int answer_ede_rcode; + char *answer_ede_msg; uint64_t answer_query_flags; DnsProtocol answer_protocol; int answer_family; diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c index 0f934ef7bb6..96b379ee057 100644 --- a/src/resolve/resolved-dns-transaction.c +++ b/src/resolve/resolved-dns-transaction.c @@ -162,6 +162,8 @@ DnsTransaction* dns_transaction_free(DnsTransaction *t) { dns_resource_key_unref(t->key); dns_packet_unref(t->bypass); + free(t->answer_ede_msg); + return mfree(t); } @@ -280,6 +282,7 @@ int dns_transaction_new( .dns_udp_fd = -EBADF, .answer_source = _DNS_TRANSACTION_SOURCE_INVALID, .answer_dnssec_result = _DNSSEC_RESULT_INVALID, + .answer_ede_rcode = _DNS_EDE_RCODE_INVALID, .answer_nsec_ttl = UINT32_MAX, .key = dns_resource_key_ref(key), .query_flags = query_flags, @@ -404,6 +407,21 @@ void dns_transaction_complete(DnsTransaction *t, DnsTransactionState state) { "DNS_SERVER_FEATURE_LEVEL=%s", dns_server_feature_level_to_string(t->server->possible_feature_level)); } + if (state == DNS_TRANSACTION_UPSTREAM_DNSSEC_FAILURE) { + dns_resource_key_to_string(dns_transaction_key(t), key_str, sizeof key_str); + + log_struct(LOG_NOTICE, + "MESSAGE_ID=" SD_MESSAGE_DNSSEC_FAILURE_STR, + LOG_MESSAGE("Upstream resolver reported failure for question %s: %s%s%s", + key_str, dns_ede_rcode_to_string(t->answer_ede_rcode), + isempty(t->answer_ede_msg) ? "" : ": ", t->answer_ede_msg), + "DNS_TRANSACTION=%" PRIu16, t->id, + "DNS_QUESTION=%s", key_str, + "DNS_EDE_RCODE=%s", dns_ede_rcode_to_string(t->answer_ede_rcode), + "DNS_SERVER=%s", strna(dns_server_string_full(t->server)), + "DNS_SERVER_FEATURE_LEVEL=%s", dns_server_feature_level_to_string(t->server->possible_feature_level)); + } + /* Note that this call might invalidate the query. Callers * should hence not attempt to access the query or transaction * after calling this function. */ @@ -1209,6 +1227,10 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p, bool encrypt ede_rcode = dns_packet_ede_rcode(p, &ede_msg); if (ede_rcode < 0 && ede_rcode != -EINVAL) log_debug_errno(ede_rcode, "Unable to extract EDE error code from packet, ignoring: %m"); + else { + t->answer_ede_rcode = ede_rcode; + t->answer_ede_msg = TAKE_PTR(ede_msg); + } if (!t->bypass && IN_SET(DNS_PACKET_RCODE(p), DNS_RCODE_FORMERR, DNS_RCODE_SERVFAIL, DNS_RCODE_NOTIMP)) { @@ -1222,8 +1244,9 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p, bool encrypt log_debug("Server returned error: %s (%s%s%s). Lookup failed.", FORMAT_DNS_RCODE(DNS_PACKET_RCODE(p)), FORMAT_DNS_EDE_RCODE(ede_rcode), - isempty(ede_msg) ? "" : ": ", ede_msg); - dns_transaction_complete(t, DNS_TRANSACTION_DNSSEC_FAILED); + isempty(t->answer_ede_msg) ? "" : ": ", + t->answer_ede_msg); + dns_transaction_complete(t, DNS_TRANSACTION_UPSTREAM_DNSSEC_FAILURE); return; } @@ -1232,7 +1255,8 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p, bool encrypt log_debug("Server returned error: %s (%s%s%s), retrying transaction.", FORMAT_DNS_RCODE(DNS_PACKET_RCODE(p)), FORMAT_DNS_EDE_RCODE(ede_rcode), - isempty(ede_msg) ? "" : ": ", ede_msg); + isempty(t->answer_ede_msg) ? "" : ": ", + t->answer_ede_msg); dns_transaction_retry(t, false); return; } @@ -1242,7 +1266,7 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p, bool encrypt log_debug("Server returned error: %s (%s%s%s)", FORMAT_DNS_RCODE(DNS_PACKET_RCODE(p)), FORMAT_DNS_EDE_RCODE(ede_rcode), - isempty(ede_msg) ? "" : ": ", ede_msg); + isempty(t->answer_ede_msg) ? "" : ": ", t->answer_ede_msg); break; } /* No EDE rcode, or EDE rcode we don't understand */ diff --git a/src/resolve/resolved-dns-transaction.h b/src/resolve/resolved-dns-transaction.h index 2fd8720e240..1188708d8f5 100644 --- a/src/resolve/resolved-dns-transaction.h +++ b/src/resolve/resolved-dns-transaction.h @@ -20,6 +20,7 @@ enum DnsTransactionState { DNS_TRANSACTION_PENDING, DNS_TRANSACTION_VALIDATING, DNS_TRANSACTION_RCODE_FAILURE, + DNS_TRANSACTION_UPSTREAM_DNSSEC_FAILURE, DNS_TRANSACTION_SUCCESS, DNS_TRANSACTION_NO_SERVERS, DNS_TRANSACTION_TIMEOUT, @@ -61,6 +62,8 @@ struct DnsTransaction { DnsAnswer *answer; int answer_rcode; + int answer_ede_rcode; + char *answer_ede_msg; DnssecResult answer_dnssec_result; DnsTransactionSource answer_source; uint32_t answer_nsec_ttl; |