From 7cc6ed7ba6c667caef9a92ba4d59e1ecdc3af8ff Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 22 Jan 2016 17:22:23 +0100 Subject: [PATCH] resolved: replace DNS_TRANSACTION_RESOURCES by DNS_TRANSACTION_ERRNO Whenever we encounter an OS error we did not expect, we so far put the transaction into DNS_TRANSACTION_RESOURCES state. Rename this state to DNS_TRANSACTION_ERRNO, and save + propagate the actual system error to the caller. This should make error messages triggered by system errors much more readable by the user. --- src/resolve/resolved-bus.c | 4 +- src/resolve/resolved-dns-query.c | 31 +++++++--- src/resolve/resolved-dns-query.h | 1 + src/resolve/resolved-dns-transaction.c | 83 ++++++++++++++------------ src/resolve/resolved-dns-transaction.h | 3 +- 5 files changed, 73 insertions(+), 49 deletions(-) diff --git a/src/resolve/resolved-bus.c b/src/resolve/resolved-bus.c index 3a21773dae..d8e8638327 100644 --- a/src/resolve/resolved-bus.c +++ b/src/resolve/resolved-bus.c @@ -43,8 +43,8 @@ static int reply_query_state(DnsQuery *q) { case DNS_TRANSACTION_INVALID_REPLY: return sd_bus_reply_method_errorf(q->request, BUS_ERROR_INVALID_REPLY, "Received invalid reply"); - case DNS_TRANSACTION_RESOURCES: - return sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_RESOURCES, "Not enough resources"); + case DNS_TRANSACTION_ERRNO: + return sd_bus_reply_method_errnof(q->request, q->answer_errno, "Lookup failed due to system error: %m"); case DNS_TRANSACTION_ABORTED: return sd_bus_reply_method_errorf(q->request, BUS_ERROR_ABORTED, "Query aborted"); diff --git a/src/resolve/resolved-dns-query.c b/src/resolve/resolved-dns-query.c index 1fe37a6813..1d706f8a43 100644 --- a/src/resolve/resolved-dns-query.c +++ b/src/resolve/resolved-dns-query.c @@ -182,7 +182,7 @@ static DnsTransactionState dns_query_candidate_state(DnsQueryCandidate *c) { assert(c); if (c->error_code != 0) - return DNS_TRANSACTION_RESOURCES; + return DNS_TRANSACTION_ERRNO; SET_FOREACH(t, c->transactions, i) { @@ -324,6 +324,7 @@ static void dns_query_reset_answer(DnsQuery *q) { q->answer = dns_answer_unref(q->answer); q->answer_rcode = 0; q->answer_dnssec_result = _DNSSEC_RESULT_INVALID; + q->answer_errno = 0; q->answer_authenticated = false; q->answer_protocol = _DNS_PROTOCOL_INVALID; q->answer_family = AF_UNSPEC; @@ -670,7 +671,10 @@ int dns_query_go(DnsQuery *q) { if (found == DNS_SCOPE_NO) { DnsTransactionState state = DNS_TRANSACTION_NO_SERVERS; - dns_query_synthesize_reply(q, &state); + r = dns_query_synthesize_reply(q, &state); + if (r < 0) + return r; + dns_query_complete(q, state); return 1; } @@ -748,7 +752,10 @@ static void dns_query_accept(DnsQuery *q, DnsQueryCandidate *c) { assert(q); if (!c) { - dns_query_synthesize_reply(q, &state); + r = dns_query_synthesize_reply(q, &state); + if (r < 0) + goto fail; + dns_query_complete(q, state); return; } @@ -760,12 +767,11 @@ static void dns_query_accept(DnsQuery *q, DnsQueryCandidate *c) { case DNS_TRANSACTION_SUCCESS: { /* We found a successfuly reply, merge it into the answer */ r = dns_answer_extend(&q->answer, t->answer); - if (r < 0) { - dns_query_complete(q, DNS_TRANSACTION_RESOURCES); - return; - } + if (r < 0) + goto fail; q->answer_rcode = t->answer_rcode; + q->answer_errno = 0; if (t->answer_authenticated) { has_authenticated = true; @@ -796,6 +802,7 @@ static void dns_query_accept(DnsQuery *q, DnsQueryCandidate *c) { q->answer = dns_answer_unref(q->answer); q->answer_rcode = t->answer_rcode; q->answer_dnssec_result = t->answer_dnssec_result; + q->answer_errno = t->answer_errno; state = t->state; break; @@ -813,8 +820,16 @@ static void dns_query_accept(DnsQuery *q, DnsQueryCandidate *c) { dns_search_domain_unref(q->answer_search_domain); q->answer_search_domain = dns_search_domain_ref(c->search_domain); - dns_query_synthesize_reply(q, &state); + r = dns_query_synthesize_reply(q, &state); + if (r < 0) + goto fail; + dns_query_complete(q, state); + return; + +fail: + q->answer_errno = -r; + dns_query_complete(q, DNS_TRANSACTION_ERRNO); } void dns_query_ready(DnsQuery *q) { diff --git a/src/resolve/resolved-dns-query.h b/src/resolve/resolved-dns-query.h index 9f618d6f6b..c7e4ce9a00 100644 --- a/src/resolve/resolved-dns-query.h +++ b/src/resolve/resolved-dns-query.h @@ -83,6 +83,7 @@ struct DnsQuery { DnsProtocol answer_protocol; int answer_family; DnsSearchDomain *answer_search_domain; + int answer_errno; /* if state is DNS_TRANSACTION_ERRNO */ /* Bus client information */ sd_bus_message *request; diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c index 02269498c9..0aeb3b0f4a 100644 --- a/src/resolve/resolved-dns-transaction.c +++ b/src/resolve/resolved-dns-transaction.c @@ -24,6 +24,7 @@ #include "af-list.h" #include "alloc-util.h" #include "dns-domain.h" +#include "errno-list.h" #include "fd-util.h" #include "random-util.h" #include "resolved-dns-cache.h" @@ -43,6 +44,7 @@ static void dns_transaction_reset_answer(DnsTransaction *t) { t->answer_source = _DNS_TRANSACTION_SOURCE_INVALID; t->answer_authenticated = false; t->answer_nsec_ttl = (uint32_t) -1; + t->answer_errno = 0; } static void dns_transaction_flush_dnssec_transactions(DnsTransaction *t) { @@ -285,6 +287,7 @@ void dns_transaction_complete(DnsTransaction *t, DnsTransactionState state) { DnsZoneItem *z; DnsTransaction *d; Iterator i; + const char *st; assert(t); assert(!DNS_TRANSACTION_IS_LIVE(state)); @@ -304,13 +307,18 @@ void dns_transaction_complete(DnsTransaction *t, DnsTransactionState state) { * should hence not attempt to access the query or transaction * after calling this function. */ + if (state == DNS_TRANSACTION_ERRNO) + st = errno_to_name(t->answer_errno); + else + st = dns_transaction_state_to_string(state); + log_debug("Transaction %" PRIu16 " for <%s> on scope %s on %s/%s now complete with <%s> from %s (%s).", t->id, dns_transaction_key_string(t), dns_protocol_to_string(t->scope->protocol), t->scope->link ? t->scope->link->name : "*", t->scope->family == AF_UNSPEC ? "*" : af_to_name(t->scope->family), - dns_transaction_state_to_string(state), + st, t->answer_source < 0 ? "none" : dns_transaction_source_to_string(t->answer_source), t->answer_authenticated ? "authenticated" : "unsigned"); @@ -393,8 +401,10 @@ static void dns_transaction_retry(DnsTransaction *t) { dns_scope_next_dns_server(t->scope); r = dns_transaction_go(t); - if (r < 0) - dns_transaction_complete(t, DNS_TRANSACTION_RESOURCES); + if (r < 0) { + t->answer_errno = -r; + dns_transaction_complete(t, DNS_TRANSACTION_ERRNO); + } } static int dns_transaction_maybe_restart(DnsTransaction *t) { @@ -449,7 +459,8 @@ static int on_stream_complete(DnsStream *s, int error) { return 0; } if (error != 0) { - dns_transaction_complete(t, DNS_TRANSACTION_RESOURCES); + t->answer_errno = error; + dns_transaction_complete(t, DNS_TRANSACTION_ERRNO); return 0; } @@ -664,20 +675,16 @@ static void dns_transaction_process_dnssec(DnsTransaction *t) { /* Are there ongoing DNSSEC transactions? If so, let's wait for them. */ r = dns_transaction_dnssec_ready(t); - if (r < 0) { - dns_transaction_complete(t, DNS_TRANSACTION_RESOURCES); - return; - } + if (r < 0) + goto fail; if (r == 0) /* We aren't ready yet (or one of our auxiliary transactions failed, and we shouldn't validate now */ return; /* See if we learnt things from the additional DNSSEC transactions, that we didn't know before, and better * restart the lookup immediately. */ r = dns_transaction_maybe_restart(t); - if (r < 0) { - dns_transaction_complete(t, DNS_TRANSACTION_RESOURCES); - return; - } + if (r < 0) + goto fail; if (r > 0) /* Transaction got restarted... */ return; @@ -688,10 +695,8 @@ static void dns_transaction_process_dnssec(DnsTransaction *t) { dns_transaction_complete(t, DNS_TRANSACTION_INVALID_REPLY); return; } - if (r < 0) { - dns_transaction_complete(t, DNS_TRANSACTION_RESOURCES); - return; - } + if (r < 0) + goto fail; if (t->answer_dnssec_result == DNSSEC_INCOMPATIBLE_SERVER && t->scope->dnssec_mode == DNSSEC_YES) { @@ -719,6 +724,12 @@ static void dns_transaction_process_dnssec(DnsTransaction *t) { dns_transaction_complete(t, DNS_TRANSACTION_SUCCESS); else dns_transaction_complete(t, DNS_TRANSACTION_RCODE_FAILURE); + + return; + +fail: + t->answer_errno = -r; + dns_transaction_complete(t, DNS_TRANSACTION_ERRNO); } void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) { @@ -862,10 +873,8 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) { if (r < 0) { /* On LLMNR, if we cannot connect to the host, * we immediately give up */ - if (t->scope->protocol != DNS_PROTOCOL_DNS) { - dns_transaction_complete(t, DNS_TRANSACTION_RESOURCES); - return; - } + if (t->scope->protocol != DNS_PROTOCOL_DNS) + goto fail; /* On DNS, couldn't send? Try immediately again, with a new server */ dns_transaction_retry(t); @@ -891,10 +900,8 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) { /* See if we know things we didn't know before that indicate we better restart the lookup immediately. */ r = dns_transaction_maybe_restart(t); - if (r < 0) { - dns_transaction_complete(t, DNS_TRANSACTION_RESOURCES); - return; - } + if (r < 0) + goto fail; if (r > 0) /* Transaction got restarted... */ return; @@ -902,10 +909,8 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) { /* Only consider responses with equivalent query section to the request */ r = dns_packet_is_reply_for(p, t->key); - if (r < 0) { - dns_transaction_complete(t, DNS_TRANSACTION_RESOURCES); - return; - } + if (r < 0) + goto fail; if (r == 0) { dns_transaction_complete(t, DNS_TRANSACTION_INVALID_REPLY); return; @@ -934,10 +939,8 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) { * quickly. */ if (t->state != DNS_TRANSACTION_PENDING) return; - if (r < 0) { - dns_transaction_complete(t, DNS_TRANSACTION_RESOURCES); - return; - } + if (r < 0) + goto fail; if (r > 0) { /* There are DNSSEC transactions pending now. Update the state accordingly. */ t->state = DNS_TRANSACTION_VALIDATING; @@ -948,6 +951,11 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) { } dns_transaction_process_dnssec(t); + return; + +fail: + t->answer_errno = -r; + dns_transaction_complete(t, DNS_TRANSACTION_ERRNO); } static int on_dns_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata) { @@ -973,7 +981,8 @@ static int on_dns_packet(sd_event_source *s, int fd, uint32_t revents, void *use return 0; } if (r < 0) { - dns_transaction_complete(t, DNS_TRANSACTION_RESOURCES); + dns_transaction_complete(t, DNS_TRANSACTION_ERRNO); + t->answer_errno = -r; return 0; } @@ -1482,10 +1491,8 @@ int dns_transaction_go(DnsTransaction *t) { return 0; } if (r < 0) { - if (t->scope->protocol != DNS_PROTOCOL_DNS) { - dns_transaction_complete(t, DNS_TRANSACTION_RESOURCES); - return 0; - } + if (t->scope->protocol != DNS_PROTOCOL_DNS) + return r; /* Couldn't send? Try immediately again, with a new server */ dns_scope_next_dns_server(t->scope); @@ -3001,7 +3008,7 @@ static const char* const dns_transaction_state_table[_DNS_TRANSACTION_STATE_MAX] [DNS_TRANSACTION_TIMEOUT] = "timeout", [DNS_TRANSACTION_ATTEMPTS_MAX_REACHED] = "attempts-max-reached", [DNS_TRANSACTION_INVALID_REPLY] = "invalid-reply", - [DNS_TRANSACTION_RESOURCES] = "resources", + [DNS_TRANSACTION_ERRNO] = "errno", [DNS_TRANSACTION_ABORTED] = "aborted", [DNS_TRANSACTION_DNSSEC_FAILED] = "dnssec-failed", [DNS_TRANSACTION_NO_TRUST_ANCHOR] = "no-trust-anchor", diff --git a/src/resolve/resolved-dns-transaction.h b/src/resolve/resolved-dns-transaction.h index ab5717c4d1..b6c5b2861c 100644 --- a/src/resolve/resolved-dns-transaction.h +++ b/src/resolve/resolved-dns-transaction.h @@ -35,7 +35,7 @@ enum DnsTransactionState { DNS_TRANSACTION_TIMEOUT, DNS_TRANSACTION_ATTEMPTS_MAX_REACHED, DNS_TRANSACTION_INVALID_REPLY, - DNS_TRANSACTION_RESOURCES, + DNS_TRANSACTION_ERRNO, DNS_TRANSACTION_ABORTED, DNS_TRANSACTION_DNSSEC_FAILED, DNS_TRANSACTION_NO_TRUST_ANCHOR, @@ -84,6 +84,7 @@ struct DnsTransaction { DnssecResult answer_dnssec_result; DnsTransactionSource answer_source; uint32_t answer_nsec_ttl; + int answer_errno; /* if state is DNS_TRANSACTION_ERRNO */ /* Indicates whether the primary answer is authenticated, * i.e. whether the RRs from answer which directly match the