diff options
Diffstat (limited to 'src/resolve/resolved-dns-transaction.c')
-rw-r--r-- | src/resolve/resolved-dns-transaction.c | 156 |
1 files changed, 61 insertions, 95 deletions
diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c index c60b8215a6..4a2d2ccbde 100644 --- a/src/resolve/resolved-dns-transaction.c +++ b/src/resolve/resolved-dns-transaction.c @@ -11,11 +11,10 @@ #include "resolved-dns-cache.h" #include "resolved-dns-transaction.h" #include "resolved-llmnr.h" -#include "string-table.h" - #if ENABLE_DNS_OVER_TLS -#include <gnutls/socket.h> +#include "resolved-dnstls.h" #endif +#include "string-table.h" #define TRANSACTIONS_MAX 4096 #define TRANSACTION_TCP_TIMEOUT_USEC (10U*USEC_PER_SEC) @@ -503,73 +502,55 @@ static int dns_transaction_on_stream_packet(DnsTransaction *t, DnsPacket *p) { return 0; } -static int on_stream_connection(DnsStream *s) { -#if ENABLE_DNS_OVER_TLS - /* Store TLS Ticket for faster succesive TLS handshakes */ - if (s->tls_session && s->server) { - if (s->server->tls_session_data.data) - gnutls_free(s->server->tls_session_data.data); - - gnutls_session_get_data2(s->tls_session, &s->server->tls_session_data); - } -#endif - - return 0; -} - static int on_stream_complete(DnsStream *s, int error) { - DnsTransaction *t, *n; - int r = 0; - - /* Do not let new transactions use this stream */ - if (s->server && s->server->stream == s) - s->server->stream = dns_stream_unref(s->server->stream); + assert(s); if (ERRNO_IS_DISCONNECT(error) && s->protocol != DNS_PROTOCOL_LLMNR) { - usec_t usec; - log_debug_errno(error, "Connection failure for DNS TCP stream: %m"); if (s->transactions) { + DnsTransaction *t; + t = s->transactions; - 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_feature_level); } } - LIST_FOREACH_SAFE(transactions_by_stream, t, n, s->transactions) - if (error != 0) + if (error != 0) { + DnsTransaction *t, *n; + + LIST_FOREACH_SAFE(transactions_by_stream, t, n, s->transactions) on_transaction_stream_error(t, error); - else if (DNS_PACKET_ID(s->read_packet) == t->id) - /* As each transaction have a unique id the return code is only set once */ - r = dns_transaction_on_stream_packet(t, s->read_packet); + } - return r; + return 0; } -static int dns_stream_on_packet(DnsStream *s) { +static int on_stream_packet(DnsStream *s) { _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL; - int r = 0; DnsTransaction *t; + assert(s); + /* Take ownership of packet to be able to receive new packets */ - p = TAKE_PTR(s->read_packet); - s->n_read = 0; + p = dns_stream_take_read_packet(s); + assert(p); t = hashmap_get(s->manager->dns_transactions, UINT_TO_PTR(DNS_PACKET_ID(p))); + if (t) + return dns_transaction_on_stream_packet(t, p); /* Ignore incorrect transaction id as transaction can have been canceled */ - if (t) - r = dns_transaction_on_stream_packet(t, p); - else { - if (dns_packet_validate_reply(p) <= 0) { - log_debug("Invalid TCP reply packet."); - on_stream_complete(s, 0); - } - return 0; + if (dns_packet_validate_reply(p) <= 0) { + log_debug("Invalid TCP reply packet."); + on_stream_complete(s, 0); } - return r; + return 0; +} + +static uint16_t dns_port_for_feature_level(DnsServerFeatureLevel level) { + return DNS_SERVER_FEATURE_LEVEL_IS_TLS(level) ? 853 : 53; } static int dns_transaction_emit_tcp(DnsTransaction *t) { @@ -577,9 +558,6 @@ static int dns_transaction_emit_tcp(DnsTransaction *t) { _cleanup_(dns_stream_unrefp) DnsStream *s = NULL; union sockaddr_union sa; int r; -#if ENABLE_DNS_OVER_TLS - gnutls_session_t gs; -#endif assert(t); @@ -602,7 +580,7 @@ static int dns_transaction_emit_tcp(DnsTransaction *t) { if (t->server->stream && (DNS_SERVER_FEATURE_LEVEL_IS_TLS(t->current_feature_level) == t->server->stream->encrypted)) s = dns_stream_ref(t->server->stream); else - fd = dns_scope_socket_tcp(t->scope, AF_UNSPEC, NULL, t->server, DNS_SERVER_FEATURE_LEVEL_IS_TLS(t->current_feature_level) ? 853 : 53, &sa); + fd = dns_scope_socket_tcp(t->scope, AF_UNSPEC, NULL, t->server, dns_port_for_feature_level(t->current_feature_level), &sa); break; @@ -645,41 +623,25 @@ static int dns_transaction_emit_tcp(DnsTransaction *t) { fd = -1; - if (t->server) { - dns_stream_unref(t->server->stream); - t->server->stream = dns_stream_ref(s); - s->server = dns_server_ref(t->server); - } - #if ENABLE_DNS_OVER_TLS - if (DNS_SERVER_FEATURE_LEVEL_IS_TLS(t->current_feature_level)) { - r = gnutls_init(&gs, GNUTLS_CLIENT | GNUTLS_ENABLE_FALSE_START | GNUTLS_NONBLOCK); - if (r < 0) - return r; - - /* As DNS-over-TLS is a recent protocol, older TLS versions can be disabled */ - r = gnutls_priority_set_direct(gs, "NORMAL:-VERS-ALL:+VERS-TLS1.2", NULL); - if (r < 0) - return r; - - r = gnutls_credentials_set(gs, GNUTLS_CRD_CERTIFICATE, t->server->tls_cert_cred); - if (r < 0) - return r; - - if (t->server && t->server->tls_session_data.size > 0) - gnutls_session_set_data(gs, t->server->tls_session_data.data, t->server->tls_session_data.size); + if (t->scope->protocol == DNS_PROTOCOL_DNS && + DNS_SERVER_FEATURE_LEVEL_IS_TLS(t->current_feature_level)) { - gnutls_handshake_set_timeout(gs, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT); - - r = dns_stream_connect_tls(s, gs); + assert(t->server); + r = dnstls_stream_connect_tls(s, t->server); if (r < 0) return r; } #endif - s->on_connection = on_stream_connection; + if (t->server) { + dns_server_unref_stream(t->server); + t->server->stream = dns_stream_ref(s); + s->server = dns_server_ref(t->server); + } + s->complete = on_stream_complete; - s->on_packet = dns_stream_on_packet; + s->on_packet = on_stream_packet; /* The interface index is difficult to determine if we are * connecting to the local host, hence fill this in right away @@ -1380,10 +1342,7 @@ static int dns_transaction_prepare(DnsTransaction *t, usec_t ts) { dns_transaction_stop_timeout(t); - r = dns_scope_network_good(t->scope); - if (r < 0) - return r; - if (r == 0) { + if (!dns_scope_network_good(t->scope)) { dns_transaction_complete(t, DNS_TRANSACTION_NETWORK_DOWN); return 0; } @@ -1854,13 +1813,12 @@ static int dns_transaction_add_dnssec_transaction(DnsTransaction *t, DnsResource if (r > 0) { char s[DNS_RESOURCE_KEY_STRING_MAX], saux[DNS_RESOURCE_KEY_STRING_MAX]; - log_debug("Potential cyclic dependency, refusing to add transaction %" PRIu16 " (%s) as dependency for %" PRIu16 " (%s).", - aux->id, - dns_resource_key_to_string(t->key, s, sizeof s), - t->id, - dns_resource_key_to_string(aux->key, saux, sizeof saux)); - - return -ELOOP; + return log_debug_errno(SYNTHETIC_ERRNO(ELOOP), + "Potential cyclic dependency, refusing to add transaction %" PRIu16 " (%s) as dependency for %" PRIu16 " (%s).", + aux->id, + dns_resource_key_to_string(t->key, s, sizeof s), + t->id, + dns_resource_key_to_string(aux->key, saux, sizeof saux)); } } @@ -2184,6 +2142,14 @@ int dns_transaction_request_dnssec_keys(DnsTransaction *t) { if (r > 0) /* positive reply, we won't need the SOA and hence don't need to validate * it. */ continue; + + /* Only bother with this if the SOA/NS RR we are looking at is actually a parent of + * what we are looking for, otherwise there's no value in it for us. */ + r = dns_name_endswith(dns_resource_key_name(t->key), dns_resource_key_name(rr->key)); + if (r < 0) + return r; + if (r == 0) + continue; } r = dnssec_has_rrsig(t->answer, rr->key); @@ -2318,21 +2284,21 @@ int dns_transaction_request_dnssec_keys(DnsTransaction *t) { r = dns_name_parent(&name); if (r > 0) { type = DNS_TYPE_SOA; - log_debug("Requesting parent SOA to validate transaction %" PRIu16 " (%s, unsigned empty DS response).", - t->id, dns_resource_key_name(t->key)); + log_debug("Requesting parent SOA (→ %s) to validate transaction %" PRIu16 " (%s, unsigned empty DS response).", + name, t->id, dns_resource_key_name(t->key)); } else name = NULL; } else if (IN_SET(t->key->type, DNS_TYPE_SOA, DNS_TYPE_NS)) { type = DNS_TYPE_DS; - log_debug("Requesting DS to validate transaction %" PRIu16 " (%s, unsigned empty SOA/NS response).", - t->id, dns_resource_key_name(t->key)); + log_debug("Requesting DS (→ %s) to validate transaction %" PRIu16 " (%s, unsigned empty SOA/NS response).", + name, t->id, name); } else { type = DNS_TYPE_SOA; - log_debug("Requesting SOA to validate transaction %" PRIu16 " (%s, unsigned empty non-SOA/NS/DS response).", - t->id, dns_resource_key_name(t->key)); + log_debug("Requesting SOA (→ %s) to validate transaction %" PRIu16 " (%s, unsigned empty non-SOA/NS/DS response).", + name, t->id, name); } if (name) { @@ -2483,8 +2449,8 @@ static int dns_transaction_requires_rrsig(DnsTransaction *t, DnsResourceRecord * return true; /* A CNAME/DNAME without a parent? That's sooo weird. */ - log_debug("Transaction %" PRIu16 " claims CNAME/DNAME at root. Refusing.", t->id); - return -EBADMSG; + return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG), + "Transaction %" PRIu16 " claims CNAME/DNAME at root. Refusing.", t->id); } } |