summaryrefslogtreecommitdiff
path: root/src/resolve/resolved-dns-transaction.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/resolve/resolved-dns-transaction.c')
-rw-r--r--src/resolve/resolved-dns-transaction.c156
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);
}
}