Skip to content

Commit 2e22a54

Browse files
guilhemyuwata
authored andcommitted
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
1 parent b7aa08c commit 2e22a54

12 files changed

+123
-6
lines changed

man/resolved.conf.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,9 @@
214214
resolver is not capable of authenticating the server, so it is
215215
vulnerable to "man-in-the-middle" attacks.</para>
216216

217+
<para>Server Name Indication (SNI) can be used when opening a TLS connection.
218+
Entries in <varname>DNS=</varname> should be in format <literal>address#server_name</literal>.</para>
219+
217220
<para>In addition to this global DNSOverTLS setting
218221
<citerefentry><refentrytitle>systemd-networkd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
219222
also maintains per-link DNSOverTLS settings. For system DNS

src/resolve/meson.build

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ systemd_resolved_sources = files('''
6464
resolved-etc-hosts.h
6565
resolved-etc-hosts.c
6666
resolved-dnstls.h
67+
resolved-util.c
68+
resolved-util.h
6769
'''.split())
6870

6971
resolvectl_sources = files('''
@@ -228,4 +230,10 @@ tests += [
228230
[],
229231
[],
230232
'ENABLE_RESOLVE', 'manual'],
233+
234+
[['src/resolve/test-resolved-util.c',
235+
'src/resolve/resolved-util.c',
236+
'src/resolve/resolved-util.h'],
237+
[],
238+
[]],
231239
]

src/resolve/resolved-conf.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include "parse-util.h"
99
#include "resolved-conf.h"
1010
#include "resolved-dnssd.h"
11+
#include "resolved-util.h"
1112
#include "specifier.h"
1213
#include "string-table.h"
1314
#include "string-util.h"
@@ -27,11 +28,12 @@ static int manager_add_dns_server_by_string(Manager *m, DnsServerType type, cons
2728
union in_addr_union address;
2829
int family, r, ifindex = 0;
2930
DnsServer *s;
31+
_cleanup_free_ char *server_name = NULL;
3032

3133
assert(m);
3234
assert(word);
3335

34-
r = in_addr_ifindex_from_string_auto(word, &family, &address, &ifindex);
36+
r = in_addr_ifindex_name_from_string_auto(word, &family, &address, &ifindex, &server_name);
3537
if (r < 0)
3638
return r;
3739

@@ -52,7 +54,7 @@ static int manager_add_dns_server_by_string(Manager *m, DnsServerType type, cons
5254
return 0;
5355
}
5456

55-
return dns_server_new(m, NULL, type, NULL, family, &address, ifindex);
57+
return dns_server_new(m, NULL, type, NULL, family, &address, ifindex, server_name);
5658
}
5759

5860
int manager_parse_dns_server_string_and_warn(Manager *m, DnsServerType type, const char *string) {

src/resolve/resolved-dns-server.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,10 @@ int dns_server_new(
2525
Link *l,
2626
int family,
2727
const union in_addr_union *in_addr,
28-
int ifindex) {
28+
int ifindex,
29+
const char *server_name) {
2930

31+
_cleanup_free_ char *name = NULL;
3032
DnsServer *s;
3133

3234
assert(m);
@@ -44,6 +46,12 @@ int dns_server_new(
4446
return -E2BIG;
4547
}
4648

49+
if (server_name) {
50+
name = strdup(server_name);
51+
if (!name)
52+
return -ENOMEM;
53+
}
54+
4755
s = new(DnsServer, 1);
4856
if (!s)
4957
return -ENOMEM;
@@ -55,6 +63,7 @@ int dns_server_new(
5563
.family = family,
5664
.address = *in_addr,
5765
.ifindex = ifindex,
66+
.server_name = TAKE_PTR(name),
5867
};
5968

6069
dns_server_reset_features(s);
@@ -107,6 +116,7 @@ static DnsServer* dns_server_free(DnsServer *s) {
107116
#endif
108117

109118
free(s->server_string);
119+
free(s->server_name);
110120
return mfree(s);
111121
}
112122

src/resolve/resolved-dns-server.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ struct DnsServer {
5353

5454
char *server_string;
5555

56+
char *server_name;
57+
5658
/* The long-lived stream towards this server. */
5759
DnsStream *stream;
5860

@@ -94,7 +96,8 @@ int dns_server_new(
9496
Link *link,
9597
int family,
9698
const union in_addr_union *address,
97-
int ifindex);
99+
int ifindex,
100+
const char *server_string);
98101

99102
DnsServer* dns_server_ref(DnsServer *s);
100103
DnsServer* dns_server_unref(DnsServer *s);

src/resolve/resolved-dnstls-gnutls.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,12 @@ int dnstls_stream_connect_tls(DnsStream *stream, DnsServer *server) {
6767
gnutls_session_set_verify_cert2(gs, &stream->dnstls_data.validation, 1, 0);
6868
}
6969

70+
if (server->server_name) {
71+
r = gnutls_server_name_set(gs, GNUTLS_NAME_DNS, server->server_name, strlen(server->server_name));
72+
if (r < 0)
73+
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to set server name: %s", gnutls_strerror(r));
74+
}
75+
7076
gnutls_handshake_set_timeout(gs, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
7177

7278
gnutls_transport_set_ptr2(gs, (gnutls_transport_ptr_t) (long) stream->fd, stream);

src/resolve/resolved-dnstls-openssl.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,17 @@ int dnstls_stream_connect_tls(DnsStream *stream, DnsServer *server) {
8787
return -ECONNREFUSED;
8888
}
8989

90+
if (server->server_name) {
91+
r = SSL_set_tlsext_host_name(s, server->server_name);
92+
if (r <= 0) {
93+
char errbuf[256];
94+
95+
error = ERR_get_error();
96+
ERR_error_string_n(error, errbuf, sizeof(errbuf));
97+
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to set server name: %s", errbuf);
98+
}
99+
}
100+
90101
ERR_clear_error();
91102
stream->dnstls_data.handshake = SSL_do_handshake(s);
92103
if (stream->dnstls_data.handshake <= 0) {

src/resolve/resolved-link-bus.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,7 @@ int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_
284284
if (s)
285285
dns_server_move_back_and_unmark(s);
286286
else {
287-
r = dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, dns[i].family, &dns[i].address, 0);
287+
r = dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, dns[i].family, &dns[i].address, 0, NULL);
288288
if (r < 0)
289289
goto clear;
290290
}

src/resolve/resolved-link.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ static int link_update_dns_server_one(Link *l, const char *name) {
269269
return 0;
270270
}
271271

272-
return dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, family, &a, 0);
272+
return dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, family, &a, 0, NULL);
273273
}
274274

275275
static int link_update_dns_servers(Link *l) {

src/resolve/resolved-util.c

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/* SPDX-License-Identifier: LGPL-2.1+ */
2+
3+
#include "alloc-util.h"
4+
#include "in-addr-util.h"
5+
#include "macro.h"
6+
#include "resolved-util.h"
7+
8+
int in_addr_ifindex_name_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex, char **server_name) {
9+
_cleanup_free_ char *buf = NULL, *name = NULL;
10+
const char *m;
11+
int r;
12+
13+
assert(s);
14+
15+
m = strchr(s, '#');
16+
if (m) {
17+
name = strdup(m+1);
18+
if (!name)
19+
return -ENOMEM;
20+
21+
buf = strndup(s, m - s);
22+
if (!buf)
23+
return -ENOMEM;
24+
25+
s = buf;
26+
}
27+
28+
r = in_addr_ifindex_from_string_auto(s, family, ret, ifindex);
29+
if (r < 0)
30+
return r;
31+
32+
if (server_name)
33+
*server_name = TAKE_PTR(name);
34+
35+
return r;
36+
}

0 commit comments

Comments
 (0)