]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
resolved: add transaction result for upstream failures 30513/head
authorRonan Pigott <ronan@rjp.ie>
Fri, 22 Dec 2023 04:50:45 +0000 (21:50 -0700)
committerRonan Pigott <ronan@rjp.ie>
Thu, 4 Jan 2024 00:35:02 +0000 (17:35 -0700)
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.

src/resolve/resolved-bus.c
src/resolve/resolved-dns-query.c
src/resolve/resolved-dns-query.h
src/resolve/resolved-dns-transaction.c
src/resolve/resolved-dns-transaction.h

index ef3f5237a9ea131aa2a2aed458db83611048458b..8c9475cd3dee16380b3c720ae6040937b8526129 100644 (file)
@@ -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:
index 7eb6b9736e2465014751414608c63431a5fec5d0..d94fe1da997e4a7428483214a4a60e670459dcbe 100644 (file)
@@ -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));
index 2723299bee5818e514c02afe2ccfc246d1eea148..74ad2c7350061d79afcf831800eb0f35e27401c8 100644 (file)
@@ -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;
index 0f934ef7bb6eafc9e59847e2731f45e47b37c4cc..96b379ee057718c54ea58f3b679c9605a4c9d7b9 100644 (file)
@@ -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 */
 
index 2fd8720e2407170f5fc220740abf8a5c5d9e575d..1188708d8f5f41c4c1f902a41fd649f0ab1fa729 100644 (file)
@@ -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;