mirror of
https://github.com/systemd/systemd-stable.git
synced 2025-02-08 05:57:26 +03:00
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
This commit is contained in:
parent
b7aa08ca15
commit
2e22a54f4e
@ -214,6 +214,9 @@
|
|||||||
resolver is not capable of authenticating the server, so it is
|
resolver is not capable of authenticating the server, so it is
|
||||||
vulnerable to "man-in-the-middle" attacks.</para>
|
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
|
<para>In addition to this global DNSOverTLS setting
|
||||||
<citerefentry><refentrytitle>systemd-networkd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
<citerefentry><refentrytitle>systemd-networkd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
||||||
also maintains per-link DNSOverTLS settings. For system DNS
|
also maintains per-link DNSOverTLS settings. For system DNS
|
||||||
|
@ -64,6 +64,8 @@ systemd_resolved_sources = files('''
|
|||||||
resolved-etc-hosts.h
|
resolved-etc-hosts.h
|
||||||
resolved-etc-hosts.c
|
resolved-etc-hosts.c
|
||||||
resolved-dnstls.h
|
resolved-dnstls.h
|
||||||
|
resolved-util.c
|
||||||
|
resolved-util.h
|
||||||
'''.split())
|
'''.split())
|
||||||
|
|
||||||
resolvectl_sources = files('''
|
resolvectl_sources = files('''
|
||||||
@ -228,4 +230,10 @@ tests += [
|
|||||||
[],
|
[],
|
||||||
[],
|
[],
|
||||||
'ENABLE_RESOLVE', 'manual'],
|
'ENABLE_RESOLVE', 'manual'],
|
||||||
|
|
||||||
|
[['src/resolve/test-resolved-util.c',
|
||||||
|
'src/resolve/resolved-util.c',
|
||||||
|
'src/resolve/resolved-util.h'],
|
||||||
|
[],
|
||||||
|
[]],
|
||||||
]
|
]
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include "parse-util.h"
|
#include "parse-util.h"
|
||||||
#include "resolved-conf.h"
|
#include "resolved-conf.h"
|
||||||
#include "resolved-dnssd.h"
|
#include "resolved-dnssd.h"
|
||||||
|
#include "resolved-util.h"
|
||||||
#include "specifier.h"
|
#include "specifier.h"
|
||||||
#include "string-table.h"
|
#include "string-table.h"
|
||||||
#include "string-util.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;
|
union in_addr_union address;
|
||||||
int family, r, ifindex = 0;
|
int family, r, ifindex = 0;
|
||||||
DnsServer *s;
|
DnsServer *s;
|
||||||
|
_cleanup_free_ char *server_name = NULL;
|
||||||
|
|
||||||
assert(m);
|
assert(m);
|
||||||
assert(word);
|
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)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
@ -52,7 +54,7 @@ static int manager_add_dns_server_by_string(Manager *m, DnsServerType type, cons
|
|||||||
return 0;
|
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) {
|
int manager_parse_dns_server_string_and_warn(Manager *m, DnsServerType type, const char *string) {
|
||||||
|
@ -25,8 +25,10 @@ int dns_server_new(
|
|||||||
Link *l,
|
Link *l,
|
||||||
int family,
|
int family,
|
||||||
const union in_addr_union *in_addr,
|
const union in_addr_union *in_addr,
|
||||||
int ifindex) {
|
int ifindex,
|
||||||
|
const char *server_name) {
|
||||||
|
|
||||||
|
_cleanup_free_ char *name = NULL;
|
||||||
DnsServer *s;
|
DnsServer *s;
|
||||||
|
|
||||||
assert(m);
|
assert(m);
|
||||||
@ -44,6 +46,12 @@ int dns_server_new(
|
|||||||
return -E2BIG;
|
return -E2BIG;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (server_name) {
|
||||||
|
name = strdup(server_name);
|
||||||
|
if (!name)
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
s = new(DnsServer, 1);
|
s = new(DnsServer, 1);
|
||||||
if (!s)
|
if (!s)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
@ -55,6 +63,7 @@ int dns_server_new(
|
|||||||
.family = family,
|
.family = family,
|
||||||
.address = *in_addr,
|
.address = *in_addr,
|
||||||
.ifindex = ifindex,
|
.ifindex = ifindex,
|
||||||
|
.server_name = TAKE_PTR(name),
|
||||||
};
|
};
|
||||||
|
|
||||||
dns_server_reset_features(s);
|
dns_server_reset_features(s);
|
||||||
@ -107,6 +116,7 @@ static DnsServer* dns_server_free(DnsServer *s) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
free(s->server_string);
|
free(s->server_string);
|
||||||
|
free(s->server_name);
|
||||||
return mfree(s);
|
return mfree(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,6 +53,8 @@ struct DnsServer {
|
|||||||
|
|
||||||
char *server_string;
|
char *server_string;
|
||||||
|
|
||||||
|
char *server_name;
|
||||||
|
|
||||||
/* The long-lived stream towards this server. */
|
/* The long-lived stream towards this server. */
|
||||||
DnsStream *stream;
|
DnsStream *stream;
|
||||||
|
|
||||||
@ -94,7 +96,8 @@ int dns_server_new(
|
|||||||
Link *link,
|
Link *link,
|
||||||
int family,
|
int family,
|
||||||
const union in_addr_union *address,
|
const union in_addr_union *address,
|
||||||
int ifindex);
|
int ifindex,
|
||||||
|
const char *server_string);
|
||||||
|
|
||||||
DnsServer* dns_server_ref(DnsServer *s);
|
DnsServer* dns_server_ref(DnsServer *s);
|
||||||
DnsServer* dns_server_unref(DnsServer *s);
|
DnsServer* dns_server_unref(DnsServer *s);
|
||||||
|
@ -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);
|
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_handshake_set_timeout(gs, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
|
||||||
|
|
||||||
gnutls_transport_set_ptr2(gs, (gnutls_transport_ptr_t) (long) stream->fd, stream);
|
gnutls_transport_set_ptr2(gs, (gnutls_transport_ptr_t) (long) stream->fd, stream);
|
||||||
|
@ -87,6 +87,17 @@ int dnstls_stream_connect_tls(DnsStream *stream, DnsServer *server) {
|
|||||||
return -ECONNREFUSED;
|
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();
|
ERR_clear_error();
|
||||||
stream->dnstls_data.handshake = SSL_do_handshake(s);
|
stream->dnstls_data.handshake = SSL_do_handshake(s);
|
||||||
if (stream->dnstls_data.handshake <= 0) {
|
if (stream->dnstls_data.handshake <= 0) {
|
||||||
|
@ -284,7 +284,7 @@ int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_
|
|||||||
if (s)
|
if (s)
|
||||||
dns_server_move_back_and_unmark(s);
|
dns_server_move_back_and_unmark(s);
|
||||||
else {
|
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)
|
if (r < 0)
|
||||||
goto clear;
|
goto clear;
|
||||||
}
|
}
|
||||||
|
@ -269,7 +269,7 @@ static int link_update_dns_server_one(Link *l, const char *name) {
|
|||||||
return 0;
|
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) {
|
static int link_update_dns_servers(Link *l) {
|
||||||
|
36
src/resolve/resolved-util.c
Normal file
36
src/resolve/resolved-util.c
Normal file
@ -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;
|
||||||
|
}
|
6
src/resolve/resolved-util.h
Normal file
6
src/resolve/resolved-util.h
Normal file
@ -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);
|
32
src/resolve/test-resolved-util.c
Normal file
32
src/resolve/test-resolved-util.c
Normal file
@ -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;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user