aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuilhem Lettron <guilhem@barpilot.io>2019-11-30 03:51:40 +0100
committerYu Watanabe <watanabe.yu+github@gmail.com>2019-12-04 23:24:06 +0900
commit2e22a54f4e085496088b77085f38b66532da59fb (patch)
treec3bc6bb24cafaae584504da112beb38d1b946695
parentMerge pull request #14111 from keszybz/unknown-section-warning (diff)
downloadsystemd-2e22a54f4e085496088b77085f38b66532da59fb.tar.xz
systemd-2e22a54f4e085496088b77085f38b66532da59fb.zip
Implement SNI when using DNS-over-TLS
Some DNS providers need SNI to identify client. This can be used by adding #name to a DNS. Example: [Resolve] DNS=192.168.1.1#example.com
-rw-r--r--man/resolved.conf.xml3
-rw-r--r--src/resolve/meson.build8
-rw-r--r--src/resolve/resolved-conf.c6
-rw-r--r--src/resolve/resolved-dns-server.c12
-rw-r--r--src/resolve/resolved-dns-server.h5
-rw-r--r--src/resolve/resolved-dnstls-gnutls.c6
-rw-r--r--src/resolve/resolved-dnstls-openssl.c11
-rw-r--r--src/resolve/resolved-link-bus.c2
-rw-r--r--src/resolve/resolved-link.c2
-rw-r--r--src/resolve/resolved-util.c36
-rw-r--r--src/resolve/resolved-util.h6
-rw-r--r--src/resolve/test-resolved-util.c32
12 files changed, 123 insertions, 6 deletions
diff --git a/man/resolved.conf.xml b/man/resolved.conf.xml
index 818000145b9..0f70ced5b54 100644
--- a/man/resolved.conf.xml
+++ b/man/resolved.conf.xml
@@ -214,6 +214,9 @@
resolver is not capable of authenticating the server, so it is
vulnerable to "man-in-the-middle" attacks.</para>
+ <para>Server Name Indication (SNI) can be used when opening a TLS connection.
+ Entries in <varname>DNS=</varname> should be in format <literal>address#server_name</literal>.</para>
+
<para>In addition to this global DNSOverTLS setting
<citerefentry><refentrytitle>systemd-networkd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
also maintains per-link DNSOverTLS settings. For system DNS
diff --git a/src/resolve/meson.build b/src/resolve/meson.build
index 92b67b6333d..c4d8d4e5d9a 100644
--- a/src/resolve/meson.build
+++ b/src/resolve/meson.build
@@ -64,6 +64,8 @@ systemd_resolved_sources = files('''
resolved-etc-hosts.h
resolved-etc-hosts.c
resolved-dnstls.h
+ resolved-util.c
+ resolved-util.h
'''.split())
resolvectl_sources = files('''
@@ -228,4 +230,10 @@ tests += [
[],
[],
'ENABLE_RESOLVE', 'manual'],
+
+ [['src/resolve/test-resolved-util.c',
+ 'src/resolve/resolved-util.c',
+ 'src/resolve/resolved-util.h'],
+ [],
+ []],
]
diff --git a/src/resolve/resolved-conf.c b/src/resolve/resolved-conf.c
index a46c45385b5..ca5b8e79183 100644
--- a/src/resolve/resolved-conf.c
+++ b/src/resolve/resolved-conf.c
@@ -8,6 +8,7 @@
#include "parse-util.h"
#include "resolved-conf.h"
#include "resolved-dnssd.h"
+#include "resolved-util.h"
#include "specifier.h"
#include "string-table.h"
#include "string-util.h"
@@ -27,11 +28,12 @@ static int manager_add_dns_server_by_string(Manager *m, DnsServerType type, cons
union in_addr_union address;
int family, r, ifindex = 0;
DnsServer *s;
+ _cleanup_free_ char *server_name = NULL;
assert(m);
assert(word);
- r = in_addr_ifindex_from_string_auto(word, &family, &address, &ifindex);
+ r = in_addr_ifindex_name_from_string_auto(word, &family, &address, &ifindex, &server_name);
if (r < 0)
return r;
@@ -52,7 +54,7 @@ static int manager_add_dns_server_by_string(Manager *m, DnsServerType type, cons
return 0;
}
- return dns_server_new(m, NULL, type, NULL, family, &address, ifindex);
+ return dns_server_new(m, NULL, type, NULL, family, &address, ifindex, server_name);
}
int manager_parse_dns_server_string_and_warn(Manager *m, DnsServerType type, const char *string) {
diff --git a/src/resolve/resolved-dns-server.c b/src/resolve/resolved-dns-server.c
index 9f2c97314fb..4b0599ab9cf 100644
--- a/src/resolve/resolved-dns-server.c
+++ b/src/resolve/resolved-dns-server.c
@@ -25,8 +25,10 @@ int dns_server_new(
Link *l,
int family,
const union in_addr_union *in_addr,
- int ifindex) {
+ int ifindex,
+ const char *server_name) {
+ _cleanup_free_ char *name = NULL;
DnsServer *s;
assert(m);
@@ -44,6 +46,12 @@ int dns_server_new(
return -E2BIG;
}
+ if (server_name) {
+ name = strdup(server_name);
+ if (!name)
+ return -ENOMEM;
+ }
+
s = new(DnsServer, 1);
if (!s)
return -ENOMEM;
@@ -55,6 +63,7 @@ int dns_server_new(
.family = family,
.address = *in_addr,
.ifindex = ifindex,
+ .server_name = TAKE_PTR(name),
};
dns_server_reset_features(s);
@@ -107,6 +116,7 @@ static DnsServer* dns_server_free(DnsServer *s) {
#endif
free(s->server_string);
+ free(s->server_name);
return mfree(s);
}
diff --git a/src/resolve/resolved-dns-server.h b/src/resolve/resolved-dns-server.h
index 54339355aa8..889c80a2054 100644
--- a/src/resolve/resolved-dns-server.h
+++ b/src/resolve/resolved-dns-server.h
@@ -53,6 +53,8 @@ struct DnsServer {
char *server_string;
+ char *server_name;
+
/* The long-lived stream towards this server. */
DnsStream *stream;
@@ -94,7 +96,8 @@ int dns_server_new(
Link *link,
int family,
const union in_addr_union *address,
- int ifindex);
+ int ifindex,
+ const char *server_string);
DnsServer* dns_server_ref(DnsServer *s);
DnsServer* dns_server_unref(DnsServer *s);
diff --git a/src/resolve/resolved-dnstls-gnutls.c b/src/resolve/resolved-dnstls-gnutls.c
index ed0a31e8bf3..aad3bb4481f 100644
--- a/src/resolve/resolved-dnstls-gnutls.c
+++ b/src/resolve/resolved-dnstls-gnutls.c
@@ -67,6 +67,12 @@ int dnstls_stream_connect_tls(DnsStream *stream, DnsServer *server) {
gnutls_session_set_verify_cert2(gs, &stream->dnstls_data.validation, 1, 0);
}
+ if (server->server_name) {
+ r = gnutls_server_name_set(gs, GNUTLS_NAME_DNS, server->server_name, strlen(server->server_name));
+ if (r < 0)
+ return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to set server name: %s", gnutls_strerror(r));
+ }
+
gnutls_handshake_set_timeout(gs, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
gnutls_transport_set_ptr2(gs, (gnutls_transport_ptr_t) (long) stream->fd, stream);
diff --git a/src/resolve/resolved-dnstls-openssl.c b/src/resolve/resolved-dnstls-openssl.c
index 85e202ff741..ce0a4373715 100644
--- a/src/resolve/resolved-dnstls-openssl.c
+++ b/src/resolve/resolved-dnstls-openssl.c
@@ -87,6 +87,17 @@ int dnstls_stream_connect_tls(DnsStream *stream, DnsServer *server) {
return -ECONNREFUSED;
}
+ if (server->server_name) {
+ r = SSL_set_tlsext_host_name(s, server->server_name);
+ if (r <= 0) {
+ char errbuf[256];
+
+ error = ERR_get_error();
+ ERR_error_string_n(error, errbuf, sizeof(errbuf));
+ return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to set server name: %s", errbuf);
+ }
+ }
+
ERR_clear_error();
stream->dnstls_data.handshake = SSL_do_handshake(s);
if (stream->dnstls_data.handshake <= 0) {
diff --git a/src/resolve/resolved-link-bus.c b/src/resolve/resolved-link-bus.c
index 8a2768b1e2c..dae8435b45b 100644
--- a/src/resolve/resolved-link-bus.c
+++ b/src/resolve/resolved-link-bus.c
@@ -284,7 +284,7 @@ int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_
if (s)
dns_server_move_back_and_unmark(s);
else {
- r = dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, dns[i].family, &dns[i].address, 0);
+ r = dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, dns[i].family, &dns[i].address, 0, NULL);
if (r < 0)
goto clear;
}
diff --git a/src/resolve/resolved-link.c b/src/resolve/resolved-link.c
index 96ebb4d23d3..f19fc2f3aa1 100644
--- a/src/resolve/resolved-link.c
+++ b/src/resolve/resolved-link.c
@@ -269,7 +269,7 @@ static int link_update_dns_server_one(Link *l, const char *name) {
return 0;
}
- return dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, family, &a, 0);
+ return dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, family, &a, 0, NULL);
}
static int link_update_dns_servers(Link *l) {
diff --git a/src/resolve/resolved-util.c b/src/resolve/resolved-util.c
new file mode 100644
index 00000000000..2f18f8c19d6
--- /dev/null
+++ b/src/resolve/resolved-util.c
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "alloc-util.h"
+#include "in-addr-util.h"
+#include "macro.h"
+#include "resolved-util.h"
+
+int in_addr_ifindex_name_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex, char **server_name) {
+ _cleanup_free_ char *buf = NULL, *name = NULL;
+ const char *m;
+ int r;
+
+ assert(s);
+
+ m = strchr(s, '#');
+ if (m) {
+ name = strdup(m+1);
+ if (!name)
+ return -ENOMEM;
+
+ buf = strndup(s, m - s);
+ if (!buf)
+ return -ENOMEM;
+
+ s = buf;
+ }
+
+ r = in_addr_ifindex_from_string_auto(s, family, ret, ifindex);
+ if (r < 0)
+ return r;
+
+ if (server_name)
+ *server_name = TAKE_PTR(name);
+
+ return r;
+}
diff --git a/src/resolve/resolved-util.h b/src/resolve/resolved-util.h
new file mode 100644
index 00000000000..10ebbc08743
--- /dev/null
+++ b/src/resolve/resolved-util.h
@@ -0,0 +1,6 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include "in-addr-util.h"
+
+int in_addr_ifindex_name_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex, char **server_name);
diff --git a/src/resolve/test-resolved-util.c b/src/resolve/test-resolved-util.c
new file mode 100644
index 00000000000..35bd73c4f69
--- /dev/null
+++ b/src/resolve/test-resolved-util.c
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "log.h"
+#include "resolved-util.h"
+#include "string-util.h"
+#include "tests.h"
+
+
+static void test_in_addr_ifindex_name_from_string_auto_one(const char *a, const char *expected) {
+ int family, ifindex;
+ union in_addr_union ua;
+ _cleanup_free_ char *server_name = NULL;
+
+ assert_se(in_addr_ifindex_name_from_string_auto(a, &family, &ua, &ifindex, &server_name) >= 0);
+ assert_se(streq_ptr(server_name, expected));
+}
+
+static void test_in_addr_ifindex_name_from_string_auto(void) {
+ log_info("/* %s */", __func__);
+
+ test_in_addr_ifindex_name_from_string_auto_one("192.168.0.1", NULL);
+ test_in_addr_ifindex_name_from_string_auto_one("192.168.0.1#test.com", "test.com");
+ test_in_addr_ifindex_name_from_string_auto_one("fe80::18%19", NULL);
+ test_in_addr_ifindex_name_from_string_auto_one("fe80::18%19#another.test.com", "another.test.com");
+}
+
+int main(int argc, char **argv) {
+ test_setup_logging(LOG_DEBUG);
+
+ test_in_addr_ifindex_name_from_string_auto();
+ return 0;
+}