From a1a3f73a57da25dbd158ea71607b7d740b101f49 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 8 Jan 2016 02:33:54 +0100 Subject: resolved: when we get a TCP connection failure, try again Previously, when we couldn't connect to a DNS server via TCP we'd abort the whole transaction using a "connection-failure" state. This change removes that, and counts failed connections as "lost packet" events, so that we switch back to the UDP protocol again. --- src/resolve/resolved-dns-transaction.h | 1 - 1 file changed, 1 deletion(-) (limited to 'src/resolve/resolved-dns-transaction.h') diff --git a/src/resolve/resolved-dns-transaction.h b/src/resolve/resolved-dns-transaction.h index ede33f9547..0df7d01737 100644 --- a/src/resolve/resolved-dns-transaction.h +++ b/src/resolve/resolved-dns-transaction.h @@ -36,7 +36,6 @@ enum DnsTransactionState { DNS_TRANSACTION_ATTEMPTS_MAX_REACHED, DNS_TRANSACTION_INVALID_REPLY, DNS_TRANSACTION_RESOURCES, - DNS_TRANSACTION_CONNECTION_FAILURE, DNS_TRANSACTION_ABORTED, DNS_TRANSACTION_DNSSEC_FAILED, DNS_TRANSACTION_NO_TRUST_ANCHOR, -- cgit v1.2.3-54-g00ecf From 91adc4db33f69606aabd332813a5d7d5751c859f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 8 Jan 2016 17:10:49 +0100 Subject: resolved: don't attempt to send queries for DNSSEC RR types to servers not supporting them If we already degraded the feature level below DO don't bother with sending requests for DS, DNSKEY, RRSIG, NSEC, NSEC3 or NSEC3PARAM RRs. After all, we cannot do DNSSEC validation then anyway, and we better not press a legacy server like this with such modern concepts. This also has the benefit that when we try to validate a response we received using DNSSEC, and we detect a limited server support level while doing so, all further auxiliary DNSSEC queries will fail right-away. --- src/libsystemd/sd-bus/bus-common-errors.h | 1 + src/resolve/dns-type.c | 10 ++++++++++ src/resolve/dns-type.h | 1 + src/resolve/resolved-bus.c | 3 +++ src/resolve/resolved-dns-transaction.c | 20 +++++++++++++++++++- src/resolve/resolved-dns-transaction.h | 1 + 6 files changed, 35 insertions(+), 1 deletion(-) (limited to 'src/resolve/resolved-dns-transaction.h') diff --git a/src/libsystemd/sd-bus/bus-common-errors.h b/src/libsystemd/sd-bus/bus-common-errors.h index 9e49725843..7a5f6cda87 100644 --- a/src/libsystemd/sd-bus/bus-common-errors.h +++ b/src/libsystemd/sd-bus/bus-common-errors.h @@ -76,6 +76,7 @@ #define BUS_ERROR_NO_SUCH_SERVICE "org.freedesktop.resolve1.NoSuchService" #define BUS_ERROR_DNSSEC_FAILED "org.freedesktop.resolve1.DnssecFailed" #define BUS_ERROR_NO_TRUST_ANCHOR "org.freedesktop.resolve1.NoTrustAnchor" +#define BUS_ERROR_RR_TYPE_UNSUPPORTED "org.freedesktop.resolve1.ResourceRecordTypeUnsupported" #define _BUS_ERROR_DNS "org.freedesktop.resolve1.DnsError." #define BUS_ERROR_NO_SUCH_TRANSFER "org.freedesktop.import1.NoSuchTransfer" diff --git a/src/resolve/dns-type.c b/src/resolve/dns-type.c index 0571d65f0b..646d98cd46 100644 --- a/src/resolve/dns-type.c +++ b/src/resolve/dns-type.c @@ -114,6 +114,16 @@ bool dns_type_may_redirect(uint16_t type) { DNS_TYPE_KEY); } +bool dns_type_is_dnssec(uint16_t type) { + return IN_SET(type, + DNS_TYPE_DS, + DNS_TYPE_DNSKEY, + DNS_TYPE_RRSIG, + DNS_TYPE_NSEC, + DNS_TYPE_NSEC3, + DNS_TYPE_NSEC3PARAM); +} + const char *dns_class_to_string(uint16_t class) { switch (class) { diff --git a/src/resolve/dns-type.h b/src/resolve/dns-type.h index c3bb26a5ee..6b3516a76b 100644 --- a/src/resolve/dns-type.h +++ b/src/resolve/dns-type.h @@ -129,6 +129,7 @@ bool dns_type_is_pseudo(uint16_t type); bool dns_type_is_valid_query(uint16_t type); bool dns_type_is_valid_rr(uint16_t type); bool dns_type_may_redirect(uint16_t type); +bool dns_type_is_dnssec(uint16_t type); bool dns_class_is_pseudo(uint16_t class); bool dns_class_is_valid_rr(uint16_t class); diff --git a/src/resolve/resolved-bus.c b/src/resolve/resolved-bus.c index d7295ca39c..39ccf827d6 100644 --- a/src/resolve/resolved-bus.c +++ b/src/resolve/resolved-bus.c @@ -67,6 +67,9 @@ static int reply_query_state(DnsQuery *q) { case DNS_TRANSACTION_NO_TRUST_ANCHOR: return sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_TRUST_ANCHOR, "No suitable trust anchor known"); + case DNS_TRANSACTION_RR_TYPE_UNSUPPORTED: + return sd_bus_reply_method_errorf(q->request, BUS_ERROR_RR_TYPE_UNSUPPORTED, "Server does not support requested resource record type"); + case DNS_TRANSACTION_RCODE_FAILURE: { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c index 998ffb61c5..ce02a3b6d0 100644 --- a/src/resolve/resolved-dns-transaction.c +++ b/src/resolve/resolved-dns-transaction.c @@ -418,6 +418,9 @@ static int dns_transaction_open_tcp(DnsTransaction *t) { if (r < 0) return r; + if (t->current_features < DNS_SERVER_FEATURE_LEVEL_DO && dns_type_is_dnssec(t->key->type)) + return -EOPNOTSUPP; + r = dns_server_adjust_opt(t->server, t->sent, t->current_features); if (r < 0) return r; @@ -696,6 +699,11 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) { dns_transaction_complete(t, DNS_TRANSACTION_NO_SERVERS); return; } + if (r == -EOPNOTSUPP) { + /* Tried to ask for DNSSEC RRs, on a server that doesn't do DNSSEC */ + dns_transaction_complete(t, DNS_TRANSACTION_RR_TYPE_UNSUPPORTED); + return; + } if (r < 0) { /* On LLMNR, if we cannot connect to the host, * we immediately give up */ @@ -832,6 +840,9 @@ static int dns_transaction_emit_udp(DnsTransaction *t) { if (t->current_features < DNS_SERVER_FEATURE_LEVEL_UDP) return -EAGAIN; + if (t->current_features < DNS_SERVER_FEATURE_LEVEL_DO && dns_type_is_dnssec(t->key->type)) + return -EOPNOTSUPP; + if (r > 0 || t->dns_udp_fd < 0) { /* Server changed, or no connection yet. */ int fd; @@ -1277,7 +1288,13 @@ int dns_transaction_go(DnsTransaction *t) { /* No servers to send this to? */ dns_transaction_complete(t, DNS_TRANSACTION_NO_SERVERS); return 0; - } else if (r < 0) { + } + if (r == -EOPNOTSUPP) { + /* Tried to ask for DNSSEC RRs, on a server that doesn't do DNSSEC */ + dns_transaction_complete(t, DNS_TRANSACTION_RR_TYPE_UNSUPPORTED); + return 0; + } + if (r < 0) { if (t->scope->protocol != DNS_PROTOCOL_DNS) { dns_transaction_complete(t, DNS_TRANSACTION_RESOURCES); return 0; @@ -2764,6 +2781,7 @@ static const char* const dns_transaction_state_table[_DNS_TRANSACTION_STATE_MAX] [DNS_TRANSACTION_ABORTED] = "aborted", [DNS_TRANSACTION_DNSSEC_FAILED] = "dnssec-failed", [DNS_TRANSACTION_NO_TRUST_ANCHOR] = "no-trust-anchor", + [DNS_TRANSACTION_RR_TYPE_UNSUPPORTED] = "rr-type-unsupported", }; DEFINE_STRING_TABLE_LOOKUP(dns_transaction_state, DnsTransactionState); diff --git a/src/resolve/resolved-dns-transaction.h b/src/resolve/resolved-dns-transaction.h index 0df7d01737..3d088bfb2b 100644 --- a/src/resolve/resolved-dns-transaction.h +++ b/src/resolve/resolved-dns-transaction.h @@ -39,6 +39,7 @@ enum DnsTransactionState { DNS_TRANSACTION_ABORTED, DNS_TRANSACTION_DNSSEC_FAILED, DNS_TRANSACTION_NO_TRUST_ANCHOR, + DNS_TRANSACTION_RR_TYPE_UNSUPPORTED, _DNS_TRANSACTION_STATE_MAX, _DNS_TRANSACTION_STATE_INVALID = -1 }; -- cgit v1.2.3-54-g00ecf From 274b874830b93e6592f190608866133384066a35 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 11 Jan 2016 19:38:25 +0100 Subject: resolved: rename DnsTransaction's current_features field to current_feature_level This is a follow-up for f4461e5641d53f27d6e76e0607bdaa9c0c58c1f6. --- src/resolve/resolved-dns-transaction.c | 23 ++++++++++++----------- src/resolve/resolved-dns-transaction.h | 2 +- 2 files changed, 13 insertions(+), 12 deletions(-) (limited to 'src/resolve/resolved-dns-transaction.h') diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c index 14a5c0f06a..a6d3a27f8b 100644 --- a/src/resolve/resolved-dns-transaction.c +++ b/src/resolve/resolved-dns-transaction.c @@ -160,6 +160,7 @@ int dns_transaction_new(DnsTransaction **ret, DnsScope *s, DnsResourceKey *key) t->answer_dnssec_result = _DNSSEC_RESULT_INVALID; t->answer_nsec_ttl = (uint32_t) -1; t->key = dns_resource_key_ref(key); + t->current_feature_level = _DNS_SERVER_FEATURE_LEVEL_INVALID; /* Find a fresh, unused transaction id */ do @@ -325,7 +326,7 @@ static int dns_transaction_pick_server(DnsTransaction *t) { if (!server) return -ESRCH; - t->current_features = dns_server_possible_feature_level(server); + t->current_feature_level = dns_server_possible_feature_level(server); if (server == t->server) return 0; @@ -370,7 +371,7 @@ static int on_stream_complete(DnsStream *s, int error) { log_debug_errno(error, "Connection failure for DNS TCP stream: %m"); assert_se(sd_event_now(t->scope->manager->event, clock_boottime_or_monotonic(), &usec) >= 0); - dns_server_packet_lost(t->server, IPPROTO_TCP, t->current_features, usec - t->start_usec); + dns_server_packet_lost(t->server, IPPROTO_TCP, t->current_feature_level, usec - t->start_usec); dns_transaction_retry(t); return 0; @@ -421,7 +422,7 @@ static int dns_transaction_open_tcp(DnsTransaction *t) { if (!dns_server_dnssec_supported(t->server) && dns_type_is_dnssec(t->key->type)) return -EOPNOTSUPP; - r = dns_server_adjust_opt(t->server, t->sent, t->current_features); + r = dns_server_adjust_opt(t->server, t->sent, t->current_feature_level); if (r < 0) return r; @@ -667,13 +668,13 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) { /* Request failed, immediately try again with reduced features */ log_debug("Server returned error: %s", dns_rcode_to_string(DNS_PACKET_RCODE(p))); - dns_server_packet_failed(t->server, t->current_features); + dns_server_packet_failed(t->server, t->current_feature_level); dns_transaction_retry(t); return; } else if (DNS_PACKET_TC(p)) - dns_server_packet_truncated(t->server, t->current_features); + dns_server_packet_truncated(t->server, t->current_feature_level); else - dns_server_packet_received(t->server, p->ipproto, t->current_features, ts - t->start_usec, p->size); + dns_server_packet_received(t->server, p->ipproto, t->current_feature_level, ts - t->start_usec, p->size); break; @@ -799,7 +800,7 @@ static int on_dns_packet(sd_event_source *s, int fd, uint32_t revents, void *use log_debug_errno(r, "Connection failure for DNS UDP packet: %m"); assert_se(sd_event_now(t->scope->manager->event, clock_boottime_or_monotonic(), &usec) >= 0); - dns_server_packet_lost(t->server, IPPROTO_UDP, t->current_features, usec - t->start_usec); + dns_server_packet_lost(t->server, IPPROTO_UDP, t->current_feature_level, usec - t->start_usec); dns_transaction_retry(t); return 0; @@ -839,7 +840,7 @@ static int dns_transaction_emit_udp(DnsTransaction *t) { if (r < 0) return r; - if (t->current_features < DNS_SERVER_FEATURE_LEVEL_UDP) + if (t->current_feature_level < DNS_SERVER_FEATURE_LEVEL_UDP) return -EAGAIN; if (!dns_server_dnssec_supported(t->server) && dns_type_is_dnssec(t->key->type)) @@ -864,7 +865,7 @@ static int dns_transaction_emit_udp(DnsTransaction *t) { t->dns_udp_fd = fd; } - r = dns_server_adjust_opt(t->server, t->sent, t->current_features); + r = dns_server_adjust_opt(t->server, t->sent, t->current_feature_level); if (r < 0) return r; } else @@ -891,7 +892,7 @@ static int on_transaction_timeout(sd_event_source *s, usec_t usec, void *userdat case DNS_PROTOCOL_DNS: assert(t->server); - dns_server_packet_lost(t->server, t->stream ? IPPROTO_TCP : IPPROTO_UDP, t->current_features, usec - t->start_usec); + dns_server_packet_lost(t->server, t->stream ? IPPROTO_TCP : IPPROTO_UDP, t->current_feature_level, usec - t->start_usec); break; case DNS_PROTOCOL_LLMNR: @@ -1569,7 +1570,7 @@ static bool dns_transaction_dnssec_supported(DnsTransaction *t) { if (!t->server) return true; - if (t->current_features < DNS_SERVER_FEATURE_LEVEL_DO) + if (t->current_feature_level < DNS_SERVER_FEATURE_LEVEL_DO) return false; return dns_server_dnssec_supported(t->server); diff --git a/src/resolve/resolved-dns-transaction.h b/src/resolve/resolved-dns-transaction.h index 3d088bfb2b..76cf6e71db 100644 --- a/src/resolve/resolved-dns-transaction.h +++ b/src/resolve/resolved-dns-transaction.h @@ -113,7 +113,7 @@ struct DnsTransaction { DnsServer *server; /* The features of the DNS server at time of transaction start */ - DnsServerFeatureLevel current_features; + DnsServerFeatureLevel current_feature_level; /* Query candidates this transaction is referenced by and that * shall be notified about this specific transaction -- cgit v1.2.3-54-g00ecf