From cbe194b39e12122b0691cff06d110d369d5e8b44 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 2 Jul 2020 10:25:19 +0900 Subject: [PATCH 01/24] resolve: propagate error in link_load_user() Most error path in link_load_user() are ENOMEM. Hence, it is critical. --- src/resolve/resolved-link.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/resolve/resolved-link.c b/src/resolve/resolved-link.c index 5eb184a10f..2b8df7777c 100644 --- a/src/resolve/resolved-link.c +++ b/src/resolve/resolved-link.c @@ -652,7 +652,9 @@ int link_update(Link *l) { assert(l); link_read_settings(l); - link_load_user(l); + r = link_load_user(l); + if (r < 0) + return r; if (l->llmnr_support != RESOLVE_SUPPORT_NO) { r = manager_llmnr_start(l->manager); From a723fb85dac86fb975e52aeed68dcd62d3f2b3b4 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 13 Jul 2020 06:49:41 +0900 Subject: [PATCH 02/24] util: introduce in_addr_port_ifindex_name_from_string_auto() and in_addr_port_ifindex_name_to_string() --- src/basic/in-addr-util.c | 56 +++++++++++++ src/basic/in-addr-util.h | 1 + src/shared/socket-netlink.c | 154 +++++++++++++++++++++++++----------- src/shared/socket-netlink.h | 15 +++- src/test/test-socket-util.c | 33 ++++++++ 5 files changed, 211 insertions(+), 48 deletions(-) diff --git a/src/basic/in-addr-util.c b/src/basic/in-addr-util.c index 9feee66343..828ea11816 100644 --- a/src/basic/in-addr-util.c +++ b/src/basic/in-addr-util.c @@ -14,6 +14,7 @@ #include "macro.h" #include "parse-util.h" #include "random-util.h" +#include "string-util.h" #include "strxcpyx.h" #include "util.h" @@ -445,6 +446,61 @@ fallback: return in_addr_to_string(family, u, ret); } +int in_addr_port_ifindex_name_to_string(int family, const union in_addr_union *u, uint16_t port, int ifindex, const char *server_name, char **ret) { + _cleanup_free_ char *ip_str = NULL, *x = NULL; + int r; + + assert(IN_SET(family, AF_INET, AF_INET6)); + assert(u); + assert(ret); + + /* Much like in_addr_to_string(), but optionally appends the zone interface index to the address, to properly + * handle IPv6 link-local addresses. */ + + r = in_addr_to_string(family, u, &ip_str); + if (r < 0) + return r; + + if (family == AF_INET6) { + r = in_addr_is_link_local(family, u); + if (r < 0) + return r; + if (r == 0) + ifindex = 0; + } else + ifindex = 0; /* For IPv4 address, ifindex is always ignored. */ + + if (port == 0 && ifindex == 0 && isempty(server_name)) { + *ret = TAKE_PTR(ip_str); + return 0; + } + + const char *separator = isempty(server_name) ? "" : "#"; + server_name = strempty(server_name); + + if (port > 0) { + if (family == AF_INET6) { + if (ifindex > 0) + r = asprintf(&x, "[%s]:%"PRIu16"%%%i%s%s", ip_str, port, ifindex, separator, server_name); + else + r = asprintf(&x, "[%s]:%"PRIu16"%s%s", ip_str, port, separator, server_name); + } else + r = asprintf(&x, "%s:%"PRIu16"%s%s", ip_str, port, separator, server_name); + } else { + if (ifindex > 0) + r = asprintf(&x, "%s%%%i%s%s", ip_str, ifindex, separator, server_name); + else { + x = strjoin(ip_str, separator, server_name); + r = x ? 0 : -ENOMEM; + } + } + if (r < 0) + return -ENOMEM; + + *ret = TAKE_PTR(x); + return 0; +} + int in_addr_from_string(int family, const char *s, union in_addr_union *ret) { union in_addr_union buffer; assert(s); diff --git a/src/basic/in-addr-util.h b/src/basic/in-addr-util.h index 90d79a5ef5..dc3f575bc9 100644 --- a/src/basic/in-addr-util.h +++ b/src/basic/in-addr-util.h @@ -41,6 +41,7 @@ int in_addr_random_prefix(int family, union in_addr_union *u, unsigned prefixlen int in_addr_to_string(int family, const union in_addr_union *u, char **ret); int in_addr_prefix_to_string(int family, const union in_addr_union *u, unsigned prefixlen, char **ret); int in_addr_ifindex_to_string(int family, const union in_addr_union *u, int ifindex, char **ret); +int in_addr_port_ifindex_name_to_string(int family, const union in_addr_union *u, uint16_t port, int ifindex, const char *server_name, char **ret); int in_addr_from_string(int family, const char *s, union in_addr_union *ret); int in_addr_from_string_auto(const char *s, int *ret_family, union in_addr_union *ret); diff --git a/src/shared/socket-netlink.c b/src/shared/socket-netlink.c index 16b0e6a5c3..b95407f10e 100644 --- a/src/shared/socket-netlink.c +++ b/src/shared/socket-netlink.c @@ -327,68 +327,130 @@ int make_socket_fd(int log_level, const char* address, int type, int flags) { return fd; } -int in_addr_ifindex_from_string_auto(const char *s, int *family, union in_addr_union *ret_addr, int *ret_ifindex) { - _cleanup_free_ char *buf = NULL; - const char *suffix; - int r, ifindex = 0; +int in_addr_port_ifindex_name_from_string_auto( + const char *s, + int *ret_family, + union in_addr_union *ret_address, + uint16_t *ret_port, + int *ret_ifindex, + char **ret_server_name) { + + _cleanup_free_ char *buf1 = NULL, *buf2 = NULL, *name = NULL; + int family, ifindex = 0, r; + union in_addr_union a; + uint16_t port = 0; + const char *m; assert(s); - assert(family); - assert(ret_addr); - /* Similar to in_addr_from_string_auto() but also parses an optionally appended IPv6 zone suffix ("scope id") - * if one is found. */ + /* This accepts the following: + * 192.168.0.1:53#example.com + * [2001:4860:4860::8888]:53%eth0#example.com */ + + /* if ret_port is NULL, then strings with port cannot be specified. + * Also, if ret_server_name is NULL, then server_name cannot be specified. */ + + m = strchr(s, '#'); + if (m) { + if (!ret_server_name) + return -EINVAL; + + if (isempty(m + 1)) + return -EINVAL; + + name = strdup(m + 1); + if (!name) + return -ENOMEM; + + s = buf1 = strndup(s, m - s); + if (!buf1) + return -ENOMEM; + } + + m = strchr(s, '%'); + if (m) { + if (isempty(m + 1)) + return -EINVAL; - suffix = strchr(s, '%'); - if (suffix) { if (ret_ifindex) { /* If we shall return the interface index, try to parse it */ - ifindex = resolve_interface(NULL, suffix + 1); + ifindex = resolve_interface(NULL, m + 1); if (ifindex < 0) return ifindex; } - s = buf = strndup(s, suffix - s); - if (!buf) + s = buf2 = strndup(s, m - s); + if (!buf2) return -ENOMEM; } - r = in_addr_from_string_auto(s, family, ret_addr); - if (r < 0) - return r; + m = strrchr(s, ':'); + if (m) { + if (*s == '[') { + _cleanup_free_ char *ip_str = NULL; + if (!ret_port) + return -EINVAL; + + if (*(m - 1) != ']') + return -EINVAL; + + family = AF_INET6; + + r = parse_ip_port(m + 1, &port); + if (r < 0) + return r; + + ip_str = strndup(s + 1, m - s - 2); + if (!ip_str) + return -ENOMEM; + + r = in_addr_from_string(family, ip_str, &a); + if (r < 0) + return r; + } else { + /* First try to parse the string as IPv6 address without port number */ + r = in_addr_from_string(AF_INET6, s, &a); + if (r < 0) { + /* Then the input should be IPv4 address with port number */ + _cleanup_free_ char *ip_str = NULL; + + if (!ret_port) + return -EINVAL; + + family = AF_INET; + + ip_str = strndup(s, m - s); + if (!ip_str) + return -ENOMEM; + + r = in_addr_from_string(family, ip_str, &a); + if (r < 0) + return r; + + r = parse_ip_port(m + 1, &port); + if (r < 0) + return r; + } else + family = AF_INET6; + } + } else { + family = AF_INET; + r = in_addr_from_string(family, s, &a); + if (r < 0) + return r; + } + + if (ret_family) + *ret_family = family; + if (ret_address) + *ret_address = a; + if (ret_port) + *ret_port = port; if (ret_ifindex) *ret_ifindex = ifindex; - - return r; -} - -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); + if (ret_server_name) + *ret_server_name = TAKE_PTR(name); return r; } diff --git a/src/shared/socket-netlink.h b/src/shared/socket-netlink.h index 35c35db52d..01f7745be6 100644 --- a/src/shared/socket-netlink.h +++ b/src/shared/socket-netlink.h @@ -20,5 +20,16 @@ int socket_address_parse_netlink(SocketAddress *a, const char *s); bool socket_address_is(const SocketAddress *a, const char *s, int type); bool socket_address_is_netlink(const SocketAddress *a, const char *s); -int in_addr_ifindex_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex); -int in_addr_ifindex_name_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex, char **server_name); +int in_addr_port_ifindex_name_from_string_auto( + const char *s, + int *ret_family, + union in_addr_union *ret_address, + uint16_t *ret_port, + int *ret_ifindex, + char **ret_server_name); +static inline int in_addr_ifindex_name_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex, char **server_name) { + return in_addr_port_ifindex_name_from_string_auto(s, family, ret, NULL, ifindex, server_name); +} +static inline int in_addr_ifindex_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex) { + return in_addr_ifindex_name_from_string_auto(s, family, ret, ifindex, NULL); +} diff --git a/src/test/test-socket-util.c b/src/test/test-socket-util.c index 024e12a799..b007dd6276 100644 --- a/src/test/test-socket-util.c +++ b/src/test/test-socket-util.c @@ -302,6 +302,38 @@ static void test_in_addr_ifindex_name_from_string_auto(void) { test_in_addr_ifindex_name_from_string_auto_one("fe80::18%19#another.test.com", "another.test.com"); } +static void test_in_addr_port_ifindex_name_from_string_auto_one(const char *str, int family, uint16_t port, int ifindex, const char *server_name) { + _cleanup_free_ char *name = NULL, *x = NULL; + union in_addr_union a; + uint16_t p; + int f, i; + + assert_se(in_addr_port_ifindex_name_from_string_auto(str, &f, &a, &p, &i, &name) >= 0); + assert_se(family == f); + assert_se(port == p); + assert_se(ifindex == i); + assert_se(streq_ptr(server_name, name)); + assert_se(in_addr_port_ifindex_name_to_string(f, &a, p, i, name, &x) >= 0); + assert_se(streq(str, x)); +} + +static void test_in_addr_port_ifindex_name_from_string_auto(void) { + log_info("/* %s */", __func__); + + test_in_addr_port_ifindex_name_from_string_auto_one("192.168.0.1", AF_INET, 0, 0, NULL); + test_in_addr_port_ifindex_name_from_string_auto_one("192.168.0.1#test.com", AF_INET, 0, 0, "test.com"); + test_in_addr_port_ifindex_name_from_string_auto_one("192.168.0.1:53", AF_INET, 53, 0, NULL); + test_in_addr_port_ifindex_name_from_string_auto_one("192.168.0.1:53#example.com", AF_INET, 53, 0, "example.com"); + test_in_addr_port_ifindex_name_from_string_auto_one("fe80::18", AF_INET6, 0, 0, NULL); + test_in_addr_port_ifindex_name_from_string_auto_one("fe80::18#hoge.com", AF_INET6, 0, 0, "hoge.com"); + test_in_addr_port_ifindex_name_from_string_auto_one("fe80::18%19", AF_INET6, 0, 19, NULL); + test_in_addr_port_ifindex_name_from_string_auto_one("[fe80::18]:53", AF_INET6, 53, 0, NULL); + test_in_addr_port_ifindex_name_from_string_auto_one("fe80::18%19#hoge.com", AF_INET6, 0, 19, "hoge.com"); + test_in_addr_port_ifindex_name_from_string_auto_one("[fe80::18]:53#hoge.com", AF_INET6, 53, 0, "hoge.com"); + test_in_addr_port_ifindex_name_from_string_auto_one("[fe80::18]:53%19", AF_INET6, 53, 19, NULL); + test_in_addr_port_ifindex_name_from_string_auto_one("[fe80::18]:53%19#hoge.com", AF_INET6, 53, 19, "hoge.com"); +} + static void test_sockaddr_equal(void) { union sockaddr_union a = { .in.sin_family = AF_INET, @@ -735,6 +767,7 @@ int main(int argc, char *argv[]) { test_in_addr_ifindex_to_string(); test_in_addr_ifindex_from_string_auto(); test_in_addr_ifindex_name_from_string_auto(); + test_in_addr_port_ifindex_name_from_string_auto(); test_sockaddr_equal(); From 408f8fbc0fc3b7b50f7aab6cc57af9bdf2202014 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 13 Jul 2020 07:09:55 +0900 Subject: [PATCH 03/24] util: introduce 'struct in_addr_full' and its helper functions --- src/shared/socket-netlink.c | 67 +++++++++++++++++++++++++++++++++++++ src/shared/socket-netlink.h | 15 +++++++++ 2 files changed, 82 insertions(+) diff --git a/src/shared/socket-netlink.c b/src/shared/socket-netlink.c index b95407f10e..d72a70503a 100644 --- a/src/shared/socket-netlink.c +++ b/src/shared/socket-netlink.c @@ -454,3 +454,70 @@ int in_addr_port_ifindex_name_from_string_auto( return r; } + +struct in_addr_full *in_addr_full_free(struct in_addr_full *a) { + if (!a) + return NULL; + + free(a->server_name); + free(a->cached_server_string); + return mfree(a); +} + +int in_addr_full_new(int family, union in_addr_union *a, uint16_t port, int ifindex, const char *server_name, struct in_addr_full **ret) { + _cleanup_free_ char *name = NULL; + struct in_addr_full *x; + + assert(ret); + + if (!isempty(server_name)) { + name = strdup(server_name); + if (!name) + return -ENOMEM; + } + + x = new(struct in_addr_full, 1); + if (!x) + return -ENOMEM; + + *x = (struct in_addr_full) { + .family = family, + .address = *a, + .port = port, + .ifindex = ifindex, + .server_name = TAKE_PTR(name), + }; + + *ret = x; + return 0; +} + +int in_addr_full_new_from_string(const char *s, struct in_addr_full **ret) { + _cleanup_free_ char *server_name = NULL; + int family, ifindex, r; + union in_addr_union a; + uint16_t port; + + assert(s); + + r = in_addr_port_ifindex_name_from_string_auto(s, &family, &a, &port, &ifindex, &server_name); + if (r < 0) + return r; + + return in_addr_full_new(family, &a, port, ifindex, server_name, ret); +} + +const char *in_addr_full_to_string(struct in_addr_full *a) { + assert(a); + + if (!a->cached_server_string) + (void) in_addr_port_ifindex_name_to_string( + a->family, + &a->address, + a->port, + a->ifindex, + a->server_name, + &a->cached_server_string); + + return a->cached_server_string; +} diff --git a/src/shared/socket-netlink.h b/src/shared/socket-netlink.h index 01f7745be6..9517f6dd6d 100644 --- a/src/shared/socket-netlink.h +++ b/src/shared/socket-netlink.h @@ -33,3 +33,18 @@ static inline int in_addr_ifindex_name_from_string_auto(const char *s, int *fami static inline int in_addr_ifindex_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex) { return in_addr_ifindex_name_from_string_auto(s, family, ret, ifindex, NULL); } + +struct in_addr_full { + int family; + union in_addr_union address; + uint16_t port; + int ifindex; + char *server_name; + char *cached_server_string; /* Should not be handled directly, but through in_addr_full_to_string(). */ +}; + +struct in_addr_full *in_addr_full_free(struct in_addr_full *a); +DEFINE_TRIVIAL_CLEANUP_FUNC(struct in_addr_full*, in_addr_full_free); +int in_addr_full_new(int family, union in_addr_union *a, uint16_t port, int ifindex, const char *server_name, struct in_addr_full **ret); +int in_addr_full_new_from_string(const char *s, struct in_addr_full **ret); +const char *in_addr_full_to_string(struct in_addr_full *a); From 395aa34023c844124d2795b91350152ed17bd5fd Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 13 Jul 2020 08:27:10 +0900 Subject: [PATCH 04/24] resolve: ignore empty server name Just for safety. --- src/resolve/resolved-dns-server.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/resolve/resolved-dns-server.c b/src/resolve/resolved-dns-server.c index 60de1b29e7..ee2ae1ae1b 100644 --- a/src/resolve/resolved-dns-server.c +++ b/src/resolve/resolved-dns-server.c @@ -47,7 +47,7 @@ int dns_server_new( return -E2BIG; } - if (server_name) { + if (!isempty(server_name)) { name = strdup(server_name); if (!name) return -ENOMEM; From da9de7385adc2329bdd75351db9fdbb4a2f90897 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 13 Jul 2020 08:58:02 +0900 Subject: [PATCH 05/24] resolve: support port specifier in DNS= setting --- src/resolve/resolved-conf.c | 12 +++++++++--- src/resolve/resolved-dns-scope.c | 4 ++-- src/resolve/resolved-dns-scope.h | 2 +- src/resolve/resolved-dns-server.c | 11 +++++++++++ src/resolve/resolved-dns-server.h | 6 ++++-- src/resolve/resolved-dns-transaction.c | 10 ++++++---- src/resolve/resolved-link-bus.c | 2 +- src/resolve/resolved-link.c | 2 +- 8 files changed, 35 insertions(+), 14 deletions(-) diff --git a/src/resolve/resolved-conf.c b/src/resolve/resolved-conf.c index 9a6b1e88e1..5df39b1b89 100644 --- a/src/resolve/resolved-conf.c +++ b/src/resolve/resolved-conf.c @@ -28,15 +28,16 @@ static const char* const dns_stub_listener_mode_table[_DNS_STUB_LISTENER_MODE_MA DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(dns_stub_listener_mode, DnsStubListenerMode, DNS_STUB_LISTENER_YES); static int manager_add_dns_server_by_string(Manager *m, DnsServerType type, const char *word) { + _cleanup_free_ char *server_name = NULL; union in_addr_union address; int family, r, ifindex = 0; + uint16_t port; DnsServer *s; - _cleanup_free_ char *server_name = NULL; assert(m); assert(word); - r = in_addr_ifindex_name_from_string_auto(word, &family, &address, &ifindex, &server_name); + r = in_addr_port_ifindex_name_from_string_auto(word, &family, &address, &port, &ifindex, &server_name); if (r < 0) return r; @@ -44,6 +45,11 @@ static int manager_add_dns_server_by_string(Manager *m, DnsServerType type, cons if (!dns_server_address_valid(family, &address)) return 0; + /* By default, the port number is determined with the transaction feature level. + * See dns_transaction_port() and dns_server_port(). */ + if (IN_SET(port, 53, 853)) + port = 0; + /* Filter out duplicates */ s = dns_server_find(manager_get_first_dns_server(m, type), family, &address, ifindex); if (s) { @@ -57,7 +63,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, server_name); + return dns_server_new(m, NULL, type, NULL, family, &address, port, 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-scope.c b/src/resolve/resolved-dns-scope.c index 764ccee0e0..bd4b59ea8e 100644 --- a/src/resolve/resolved-dns-scope.c +++ b/src/resolve/resolved-dns-scope.c @@ -447,8 +447,8 @@ static int dns_scope_socket( return TAKE_FD(fd); } -int dns_scope_socket_udp(DnsScope *s, DnsServer *server, uint16_t port) { - return dns_scope_socket(s, SOCK_DGRAM, AF_UNSPEC, NULL, server, port, NULL); +int dns_scope_socket_udp(DnsScope *s, DnsServer *server) { + return dns_scope_socket(s, SOCK_DGRAM, AF_UNSPEC, NULL, server, dns_server_port(server), NULL); } int dns_scope_socket_tcp(DnsScope *s, int family, const union in_addr_union *address, DnsServer *server, uint16_t port, union sockaddr_union *ret_socket_address) { diff --git a/src/resolve/resolved-dns-scope.h b/src/resolve/resolved-dns-scope.h index b356b92120..8b1a958551 100644 --- a/src/resolve/resolved-dns-scope.h +++ b/src/resolve/resolved-dns-scope.h @@ -75,7 +75,7 @@ void dns_scope_packet_lost(DnsScope *s, usec_t usec); int dns_scope_emit_udp(DnsScope *s, int fd, DnsPacket *p); int dns_scope_socket_tcp(DnsScope *s, int family, const union in_addr_union *address, DnsServer *server, uint16_t port, union sockaddr_union *ret_socket_address); -int dns_scope_socket_udp(DnsScope *s, DnsServer *server, uint16_t port); +int dns_scope_socket_udp(DnsScope *s, DnsServer *server); DnsScopeMatch dns_scope_good_domain(DnsScope *s, int ifindex, uint64_t flags, const char *domain); bool dns_scope_good_key(DnsScope *s, const DnsResourceKey *key); diff --git a/src/resolve/resolved-dns-server.c b/src/resolve/resolved-dns-server.c index ee2ae1ae1b..b4f2a8c97f 100644 --- a/src/resolve/resolved-dns-server.c +++ b/src/resolve/resolved-dns-server.c @@ -26,6 +26,7 @@ int dns_server_new( Link *l, int family, const union in_addr_union *in_addr, + uint16_t port, int ifindex, const char *server_name) { @@ -63,6 +64,7 @@ int dns_server_new( .type = type, .family = family, .address = *in_addr, + .port = port, .ifindex = ifindex, .server_name = TAKE_PTR(name), }; @@ -548,6 +550,15 @@ int dns_server_ifindex(const DnsServer *s) { return 0; } +uint16_t dns_server_port(const DnsServer *s) { + assert(s); + + if (s->port > 0) + return s->port; + + return 53; +} + const char *dns_server_string(DnsServer *server) { assert(server); diff --git a/src/resolve/resolved-dns-server.h b/src/resolve/resolved-dns-server.h index 792f966121..126a52ae6f 100644 --- a/src/resolve/resolved-dns-server.h +++ b/src/resolve/resolved-dns-server.h @@ -56,11 +56,11 @@ struct DnsServer { int family; union in_addr_union address; int ifindex; /* for IPv6 link-local DNS servers */ + uint16_t port; + char *server_name; char *server_string; - char *server_name; - /* The long-lived stream towards this server. */ DnsStream *stream; @@ -102,6 +102,7 @@ int dns_server_new( Link *link, int family, const union in_addr_union *address, + uint16_t port, int ifindex, const char *server_string); @@ -124,6 +125,7 @@ int dns_server_adjust_opt(DnsServer *server, DnsPacket *packet, DnsServerFeature const char *dns_server_string(DnsServer *server); int dns_server_ifindex(const DnsServer *s); +uint16_t dns_server_port(const DnsServer *s); bool dns_server_dnssec_supported(DnsServer *server); diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c index cd5a0e3dd9..b798e03102 100644 --- a/src/resolve/resolved-dns-transaction.c +++ b/src/resolve/resolved-dns-transaction.c @@ -544,8 +544,10 @@ static int on_stream_packet(DnsStream *s) { return 0; } -static uint16_t dns_port_for_feature_level(DnsServerFeatureLevel level) { - return DNS_SERVER_FEATURE_LEVEL_IS_TLS(level) ? 853 : 53; +static uint16_t dns_transaction_port(DnsTransaction *t) { + if (t->server->port > 0) + return t->server->port; + return DNS_SERVER_FEATURE_LEVEL_IS_TLS(t->current_feature_level) ? 853 : 53; } static int dns_transaction_emit_tcp(DnsTransaction *t) { @@ -576,7 +578,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_port_for_feature_level(t->current_feature_level), &sa); + fd = dns_scope_socket_tcp(t->scope, AF_UNSPEC, NULL, t->server, dns_transaction_port(t), &sa); type = DNS_STREAM_LOOKUP; break; @@ -1243,7 +1245,7 @@ static int dns_transaction_emit_udp(DnsTransaction *t) { dns_transaction_close_connection(t); - fd = dns_scope_socket_udp(t->scope, t->server, 53); + fd = dns_scope_socket_udp(t->scope, t->server); if (fd < 0) return fd; diff --git a/src/resolve/resolved-link-bus.c b/src/resolve/resolved-link-bus.c index 0fa62208c3..62afe698c6 100644 --- a/src/resolve/resolved-link-bus.c +++ b/src/resolve/resolved-link-bus.c @@ -285,7 +285,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, NULL); + r = dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, dns[i].family, &dns[i].address, 0, 0, NULL); if (r < 0) goto clear; } diff --git a/src/resolve/resolved-link.c b/src/resolve/resolved-link.c index 2b8df7777c..95f64700b6 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, NULL); + return dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, family, &a, 0, 0, NULL); } static int link_update_dns_servers(Link *l) { From 1b86009298c0c15678abb976e561de64f65decc9 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 13 Jul 2020 09:05:15 +0900 Subject: [PATCH 06/24] resolve: also compare port and SNI in dns_server_find() --- src/resolve/resolved-conf.c | 5 ++++- src/resolve/resolved-dns-server.c | 8 ++++++-- src/resolve/resolved-dns-server.h | 2 +- src/resolve/resolved-link-bus.c | 2 +- src/resolve/resolved-link.c | 2 +- 5 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/resolve/resolved-conf.c b/src/resolve/resolved-conf.c index 5df39b1b89..6b99271245 100644 --- a/src/resolve/resolved-conf.c +++ b/src/resolve/resolved-conf.c @@ -41,6 +41,9 @@ static int manager_add_dns_server_by_string(Manager *m, DnsServerType type, cons if (r < 0) return r; + if (IN_SET(port, 53, 853)) + port = 0; + /* Silently filter out 0.0.0.0 and 127.0.0.53 (our own stub DNS listener) */ if (!dns_server_address_valid(family, &address)) return 0; @@ -51,7 +54,7 @@ static int manager_add_dns_server_by_string(Manager *m, DnsServerType type, cons port = 0; /* Filter out duplicates */ - s = dns_server_find(manager_get_first_dns_server(m, type), family, &address, ifindex); + s = dns_server_find(manager_get_first_dns_server(m, type), family, &address, port, ifindex, server_name); if (s) { /* * Drop the marker. This is used to find the servers diff --git a/src/resolve/resolved-dns-server.c b/src/resolve/resolved-dns-server.c index b4f2a8c97f..1bd9c6fcbd 100644 --- a/src/resolve/resolved-dns-server.c +++ b/src/resolve/resolved-dns-server.c @@ -666,11 +666,15 @@ void dns_server_mark_all(DnsServer *first) { dns_server_mark_all(first->servers_next); } -DnsServer *dns_server_find(DnsServer *first, int family, const union in_addr_union *in_addr, int ifindex) { +DnsServer *dns_server_find(DnsServer *first, int family, const union in_addr_union *in_addr, uint16_t port, int ifindex, const char *name) { DnsServer *s; LIST_FOREACH(servers, s, first) - if (s->family == family && in_addr_equal(family, &s->address, in_addr) > 0 && s->ifindex == ifindex) + if (s->family == family && + in_addr_equal(family, &s->address, in_addr) > 0 && + s->port == port && + s->ifindex == ifindex && + streq_ptr(s->server_name, name)) return s; return NULL; diff --git a/src/resolve/resolved-dns-server.h b/src/resolve/resolved-dns-server.h index 126a52ae6f..4109c29452 100644 --- a/src/resolve/resolved-dns-server.h +++ b/src/resolve/resolved-dns-server.h @@ -131,7 +131,7 @@ bool dns_server_dnssec_supported(DnsServer *server); void dns_server_warn_downgrade(DnsServer *server); -DnsServer *dns_server_find(DnsServer *first, int family, const union in_addr_union *in_addr, int ifindex); +DnsServer *dns_server_find(DnsServer *first, int family, const union in_addr_union *in_addr, uint16_t port, int ifindex, const char *name); void dns_server_unlink_all(DnsServer *first); void dns_server_unlink_marked(DnsServer *first); diff --git a/src/resolve/resolved-link-bus.c b/src/resolve/resolved-link-bus.c index 62afe698c6..1694b1aa5a 100644 --- a/src/resolve/resolved-link-bus.c +++ b/src/resolve/resolved-link-bus.c @@ -281,7 +281,7 @@ int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_ for (i = 0; i < n; i++) { DnsServer *s; - s = dns_server_find(l->dns_servers, dns[i].family, &dns[i].address, 0); + s = dns_server_find(l->dns_servers, dns[i].family, &dns[i].address, 0, 0, NULL); if (s) dns_server_move_back_and_unmark(s); else { diff --git a/src/resolve/resolved-link.c b/src/resolve/resolved-link.c index 95f64700b6..3679ca0703 100644 --- a/src/resolve/resolved-link.c +++ b/src/resolve/resolved-link.c @@ -263,7 +263,7 @@ static int link_update_dns_server_one(Link *l, const char *name) { if (r < 0) return r; - s = dns_server_find(l->dns_servers, family, &a, 0); + s = dns_server_find(l->dns_servers, family, &a, 0, 0, NULL); if (s) { dns_server_move_back_and_unmark(s); return 0; From b6af282475ac950e83d761146d59bc0bffe5e9c6 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 13 Jul 2020 09:11:49 +0900 Subject: [PATCH 07/24] resolve: compare port and SNI in dns_server_hash_ops --- src/resolve/resolved-dns-server.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/resolve/resolved-dns-server.c b/src/resolve/resolved-dns-server.c index 1bd9c6fcbd..0ace7d37f2 100644 --- a/src/resolve/resolved-dns-server.c +++ b/src/resolve/resolved-dns-server.c @@ -609,7 +609,10 @@ static void dns_server_hash_func(const DnsServer *s, struct siphash *state) { siphash24_compress(&s->family, sizeof(s->family), state); siphash24_compress(&s->address, FAMILY_ADDRESS_SIZE(s->family), state); + siphash24_compress(&s->port, sizeof(s->port), state); siphash24_compress(&s->ifindex, sizeof(s->ifindex), state); + if (s->server_name) + siphash24_compress(s->server_name, strlen(s->server_name), state); } static int dns_server_compare_func(const DnsServer *x, const DnsServer *y) { @@ -623,11 +626,15 @@ static int dns_server_compare_func(const DnsServer *x, const DnsServer *y) { if (r != 0) return r; + r = CMP(x->port, y->port); + if (r != 0) + return r; + r = CMP(x->ifindex, y->ifindex); if (r != 0) return r; - return 0; + return streq_ptr(x->server_name, y->server_name); } DEFINE_HASH_OPS(dns_server_hash_ops, DnsServer, dns_server_hash_func, dns_server_compare_func); From 8aa5afd20fecb6ac022cb1e3661de220ea3f03cf Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 13 Jul 2020 09:29:14 +0900 Subject: [PATCH 08/24] resolve: read/save port number and SNI from/into link state file --- src/resolve/resolved-dns-server.c | 34 +++++++++++++++++++------- src/resolve/resolved-dns-server.h | 2 ++ src/resolve/resolved-dns-transaction.c | 4 +-- src/resolve/resolved-link.c | 27 ++++++++++++++------ 4 files changed, 48 insertions(+), 19 deletions(-) diff --git a/src/resolve/resolved-dns-server.c b/src/resolve/resolved-dns-server.c index 0ace7d37f2..c87026f434 100644 --- a/src/resolve/resolved-dns-server.c +++ b/src/resolve/resolved-dns-server.c @@ -119,6 +119,7 @@ static DnsServer* dns_server_free(DnsServer *s) { #endif free(s->server_string); + free(s->server_string_full); free(s->server_name); return mfree(s); } @@ -225,7 +226,7 @@ static void dns_server_verified(DnsServer *s, DnsServerFeatureLevel level) { if (s->verified_feature_level != level) { log_debug("Verified we get a response at feature level %s from DNS server %s.", dns_server_feature_level_to_string(level), - dns_server_string(s)); + strna(dns_server_string_full(s))); s->verified_feature_level = level; } @@ -362,7 +363,7 @@ void dns_server_packet_rcode_downgrade(DnsServer *s, DnsServerFeatureLevel level dns_server_reset_counters(s); } - log_debug("Downgrading transaction feature level fixed an RCODE error, downgrading server %s too.", dns_server_string(s)); + log_debug("Downgrading transaction feature level fixed an RCODE error, downgrading server %s too.", strna(dns_server_string_full(s))); } static bool dns_server_grace_period_expired(DnsServer *s) { @@ -416,7 +417,7 @@ DnsServerFeatureLevel dns_server_possible_feature_level(DnsServer *s) { log_info("Grace period over, resuming full feature set (%s) for DNS server %s.", dns_server_feature_level_to_string(s->possible_feature_level), - dns_server_string(s)); + strna(dns_server_string_full(s))); dns_server_flush_cache(s); @@ -502,7 +503,7 @@ DnsServerFeatureLevel dns_server_possible_feature_level(DnsServer *s) { log_full(log_level, "Using degraded feature set %s instead of %s for DNS server %s.", dns_server_feature_level_to_string(s->possible_feature_level), - dns_server_feature_level_to_string(p), dns_server_string(s)); + dns_server_feature_level_to_string(p), strna(dns_server_string_full(s))); } } @@ -565,7 +566,22 @@ const char *dns_server_string(DnsServer *server) { if (!server->server_string) (void) in_addr_ifindex_to_string(server->family, &server->address, dns_server_ifindex(server), &server->server_string); - return strna(server->server_string); + return server->server_string; +} + +const char *dns_server_string_full(DnsServer *server) { + assert(server); + + if (!server->server_string_full) + (void) in_addr_port_ifindex_name_to_string( + server->family, + &server->address, + server->port, + dns_server_ifindex(server), + server->server_name, + &server->server_string_full); + + return server->server_string_full; } bool dns_server_dnssec_supported(DnsServer *server) { @@ -597,8 +613,8 @@ void dns_server_warn_downgrade(DnsServer *server) { log_struct(LOG_NOTICE, "MESSAGE_ID=" SD_MESSAGE_DNSSEC_DOWNGRADE_STR, - LOG_MESSAGE("Server %s does not support DNSSEC, downgrading to non-DNSSEC mode.", dns_server_string(server)), - "DNS_SERVER=%s", dns_server_string(server), + LOG_MESSAGE("Server %s does not support DNSSEC, downgrading to non-DNSSEC mode.", strna(dns_server_string_full(server))), + "DNS_SERVER=%s", strna(dns_server_string_full(server)), "DNS_SERVER_FEATURE_LEVEL=%s", dns_server_feature_level_to_string(server->possible_feature_level)); server->warned_downgrade = true; @@ -712,7 +728,7 @@ DnsServer *manager_set_dns_server(Manager *m, DnsServer *s) { if (s) log_debug("Switching to %s DNS server %s.", dns_server_type_to_string(s->type), - dns_server_string(s)); + strna(dns_server_string_full(s))); dns_server_unref(m->current_dns_server); m->current_dns_server = dns_server_ref(s); @@ -852,7 +868,7 @@ void dns_server_dump(DnsServer *s, FILE *f) { f = stdout; fputs("[Server ", f); - fputs(dns_server_string(s), f); + fputs(strna(dns_server_string_full(s)), f); fputs(" type=", f); fputs(dns_server_type_to_string(s->type), f); diff --git a/src/resolve/resolved-dns-server.h b/src/resolve/resolved-dns-server.h index 4109c29452..464e8dc251 100644 --- a/src/resolve/resolved-dns-server.h +++ b/src/resolve/resolved-dns-server.h @@ -60,6 +60,7 @@ struct DnsServer { char *server_name; char *server_string; + char *server_string_full; /* The long-lived stream towards this server. */ DnsStream *stream; @@ -124,6 +125,7 @@ DnsServerFeatureLevel dns_server_possible_feature_level(DnsServer *s); int dns_server_adjust_opt(DnsServer *server, DnsPacket *packet, DnsServerFeatureLevel level); const char *dns_server_string(DnsServer *server); +const char *dns_server_string_full(DnsServer *server); int dns_server_ifindex(const DnsServer *s); uint16_t dns_server_port(const DnsServer *s); diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c index b798e03102..e23ea273e7 100644 --- a/src/resolve/resolved-dns-transaction.c +++ b/src/resolve/resolved-dns-transaction.c @@ -314,7 +314,7 @@ void dns_transaction_complete(DnsTransaction *t, DnsTransactionState state) { "DNS_TRANSACTION=%" PRIu16, t->id, "DNS_QUESTION=%s", key_str, "DNSSEC_RESULT=%s", dnssec_result_to_string(t->answer_dnssec_result), - "DNS_SERVER=%s", dns_server_string(t->server), + "DNS_SERVER=%s", strna(dns_server_string_full(t->server)), "DNS_SERVER_FEATURE_LEVEL=%s", dns_server_feature_level_to_string(t->server->possible_feature_level)); } @@ -398,7 +398,7 @@ static int dns_transaction_pick_server(DnsTransaction *t) { t->n_picked_servers ++; - log_debug("Using DNS server %s for transaction %u.", dns_server_string(t->server), t->id); + log_debug("Using DNS server %s for transaction %u.", strna(dns_server_string_full(t->server)), t->id); return 1; } diff --git a/src/resolve/resolved-link.c b/src/resolve/resolved-link.c index 3679ca0703..f52c556bd1 100644 --- a/src/resolve/resolved-link.c +++ b/src/resolve/resolved-link.c @@ -15,6 +15,7 @@ #include "resolved-link.h" #include "resolved-llmnr.h" #include "resolved-mdns.h" +#include "socket-netlink.h" #include "string-util.h" #include "strv.h" #include "tmpfile-util.h" @@ -251,25 +252,35 @@ int link_process_rtnl(Link *l, sd_netlink_message *m) { return 0; } -static int link_update_dns_server_one(Link *l, const char *name) { +static int link_update_dns_server_one(Link *l, const char *str) { + _cleanup_free_ char *name = NULL; + int family, ifindex, r; union in_addr_union a; DnsServer *s; - int family, r; + uint16_t port; assert(l); - assert(name); + assert(str); - r = in_addr_from_string_auto(name, &family, &a); + r = in_addr_port_ifindex_name_from_string_auto(str, &family, &a, &port, &ifindex, &name); if (r < 0) return r; - s = dns_server_find(l->dns_servers, family, &a, 0, 0, NULL); + if (ifindex != 0 && ifindex != l->ifindex) + return -EINVAL; + + /* By default, the port number is determined with the transaction feature level. + * See dns_transaction_port() and dns_server_port(). */ + if (IN_SET(port, 53, 853)) + port = 0; + + s = dns_server_find(l->dns_servers, family, &a, port, 0, name); if (s) { dns_server_move_back_and_unmark(s); return 0; } - return dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, family, &a, 0, 0, NULL); + return dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, family, &a, port, 0, name); } static int link_update_dns_servers(Link *l) { @@ -732,7 +743,7 @@ DnsServer* link_set_dns_server(Link *l, DnsServer *s) { return s; if (s) - log_debug("Switching to DNS server %s for interface %s.", dns_server_string(s), l->ifname); + log_debug("Switching to DNS server %s for interface %s.", strna(dns_server_string_full(s)), l->ifname); dns_server_unref(l->current_dns_server); l->current_dns_server = dns_server_ref(s); @@ -1209,7 +1220,7 @@ int link_save_user(Link *l) { if (server != l->dns_servers) fputc(' ', f); - v = dns_server_string(server); + v = dns_server_string_full(server); if (!v) { r = -ENOMEM; goto fail; From e77bd3fdffe0f5781d48daa5f9f4d12ee81d9cee Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 3 Jul 2020 16:48:29 +0900 Subject: [PATCH 09/24] network: support port number and SNI in [Network] DNS= --- src/network/networkd-dhcp-server.c | 4 +- src/network/networkd-link-bus.c | 64 +++++++++++++++++++++--------- src/network/networkd-link.c | 16 ++++---- src/network/networkd-link.h | 2 +- src/network/networkd-manager.c | 22 +++++----- src/network/networkd-network.c | 22 +++++----- src/network/networkd-network.h | 3 +- src/network/networkd-radv.c | 4 +- 8 files changed, 83 insertions(+), 54 deletions(-) diff --git a/src/network/networkd-dhcp-server.c b/src/network/networkd-dhcp-server.c index 265d9dbc79..5129a2e37e 100644 --- a/src/network/networkd-dhcp-server.c +++ b/src/network/networkd-dhcp-server.c @@ -61,10 +61,10 @@ static int link_push_uplink_to_dhcp_server( struct in_addr ia; /* Only look for IPv4 addresses */ - if (link->network->dns[i].family != AF_INET) + if (link->network->dns[i]->family != AF_INET) continue; - ia = link->network->dns[i].address.in; + ia = link->network->dns[i]->address.in; /* Never propagate obviously borked data */ if (in4_addr_is_null(&ia) || in4_addr_is_localhost(&ia)) diff --git a/src/network/networkd-link-bus.c b/src/network/networkd-link-bus.c index 38b005fb63..dec0d9be46 100644 --- a/src/network/networkd-link-bus.c +++ b/src/network/networkd-link-bus.c @@ -14,6 +14,7 @@ #include "networkd-manager.h" #include "parse-util.h" #include "resolve-util.h" +#include "socket-netlink.h" #include "strv.h" #include "user-util.h" @@ -114,7 +115,7 @@ int bus_link_method_set_ntp_servers(sd_bus_message *message, void *userdata, sd_ } int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_bus_error *error) { - _cleanup_free_ struct in_addr_data *dns = NULL; + struct in_addr_full **dns = NULL; size_t allocated = 0, n = 0; Link *l = userdata; int r; @@ -131,6 +132,7 @@ int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_ return r; for (;;) { + union in_addr_union a; int family; size_t sz; const void *d; @@ -139,50 +141,67 @@ int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_ r = sd_bus_message_enter_container(message, 'r', "iay"); if (r < 0) - return r; + goto finalize; if (r == 0) break; r = sd_bus_message_read(message, "i", &family); if (r < 0) - return r; + goto finalize; - if (!IN_SET(family, AF_INET, AF_INET6)) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family); + if (!IN_SET(family, AF_INET, AF_INET6)) { + r = sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family); + goto finalize; + } r = sd_bus_message_read_array(message, 'y', &d, &sz); if (r < 0) - return r; - if (sz != FAMILY_ADDRESS_SIZE(family)) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid address size"); + goto finalize; + if (sz != FAMILY_ADDRESS_SIZE(family)) { + r = sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid address size"); + goto finalize; + } - if (!dns_server_address_valid(family, d)) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid DNS server address"); + if (!dns_server_address_valid(family, d)) { + r = sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid DNS server address"); + goto finalize; + } r = sd_bus_message_exit_container(message); if (r < 0) - return r; + goto finalize; - if (!GREEDY_REALLOC(dns, allocated, n+1)) - return -ENOMEM; + if (!GREEDY_REALLOC(dns, allocated, n+1)) { + r = -ENOMEM; + goto finalize; + } + + memcpy(&a, d, sz); + r = in_addr_full_new(family, &a, 0, 0, NULL, dns + n); + if (r < 0) + goto finalize; - dns[n].family = family; - memcpy(&dns[n].address, d, sz); n++; } r = sd_bus_message_exit_container(message); if (r < 0) - return r; + goto finalize; r = bus_verify_polkit_async(message, CAP_NET_ADMIN, "org.freedesktop.network1.set-dns-servers", NULL, true, UID_INVALID, &l->manager->polkit_registry, error); if (r < 0) - return r; - if (r == 0) - return 1; /* Polkit will call us back */ + goto finalize; + if (r == 0) { + r = 1; /* Polkit will call us back */ + goto finalize; + } + + if (l->n_dns != (unsigned) -1) + for (unsigned i = 0; i < l->n_dns; i++) + in_addr_full_free(l->dns[i]); free_and_replace(l->dns, dns); l->n_dns = n; @@ -190,6 +209,13 @@ int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_ (void) link_dirty(l); return sd_bus_reply_method_return(message, NULL); + +finalize: + for (size_t i = 0; i < n; i++) + in_addr_full_free(dns[i]); + free(dns); + + return r; } int bus_link_method_set_domains(sd_bus_message *message, void *userdata, sd_bus_error *error) { diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 24de9a7ac8..7e7713519b 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -666,6 +666,9 @@ void link_ntp_settings_clear(Link *link) { } void link_dns_settings_clear(Link *link) { + if (link->n_dns != (unsigned) -1) + for (unsigned i = 0; i < link->n_dns; i++) + in_addr_full_free(link->dns[i]); link->dns = mfree(link->dns); link->n_dns = (unsigned) -1; @@ -4108,20 +4111,17 @@ static void print_link_hashmap(FILE *f, const char *prefix, Hashmap* h) { fputc('\n', f); } -static void link_save_dns(FILE *f, struct in_addr_data *dns, unsigned n_dns, bool *space) { +static void link_save_dns(FILE *f, struct in_addr_full **dns, unsigned n_dns, bool *space) { for (unsigned j = 0; j < n_dns; j++) { - _cleanup_free_ char *b = NULL; - int r; + const char *str; - r = in_addr_to_string(dns[j].family, &dns[j].address, &b); - if (r < 0) { - log_debug_errno(r, "Failed to format address, ignoring: %m"); + str = in_addr_full_to_string(dns[j]); + if (!str) continue; - } if (*space) fputc(' ', f); - fputs(b, f); + fputs(str, f); *space = true; } } diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h index fb12301fe6..e736970503 100644 --- a/src/network/networkd-link.h +++ b/src/network/networkd-link.h @@ -163,7 +163,7 @@ typedef struct Link { bool stats_updated; /* All kinds of DNS configuration the user configured via D-Bus */ - struct in_addr_data *dns; + struct in_addr_full **dns; unsigned n_dns; OrderedSet *search_domains, *route_domains; diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index 4fbb7965be..a87bf25d64 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -1425,33 +1425,33 @@ static int manager_connect_rtnl(Manager *m) { return 0; } -static int ordered_set_put_in_addr_data(OrderedSet *s, const struct in_addr_data *address) { - char *p; +static int ordered_set_put_dns_server(OrderedSet *s, struct in_addr_full *dns) { + const char *p; int r; assert(s); - assert(address); + assert(dns); - r = in_addr_to_string(address->family, &address->address, &p); - if (r < 0) - return r; + p = in_addr_full_to_string(dns); + if (!p) + return 0; - r = ordered_set_consume(s, p); + r = ordered_set_put_strdup(s, p); if (r == -EEXIST) return 0; return r; } -static int ordered_set_put_in_addr_datav(OrderedSet *s, const struct in_addr_data *addresses, unsigned n) { +static int ordered_set_put_dns_servers(OrderedSet *s, struct in_addr_full **dns, unsigned n) { int r, c = 0; unsigned i; assert(s); - assert(addresses || n == 0); + assert(dns || n == 0); for (i = 0; i < n; i++) { - r = ordered_set_put_in_addr_data(s, addresses+i); + r = ordered_set_put_dns_server(s, dns[i]); if (r < 0) return r; @@ -1558,7 +1558,7 @@ static int manager_save(Manager *m) { continue; /* First add the static configured entries */ - r = ordered_set_put_in_addr_datav(dns, link->network->dns, link->network->n_dns); + r = ordered_set_put_dns_servers(dns, link->network->dns, link->network->n_dns); if (r < 0) return r; diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index 6a3920adab..94a1a6100f 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -682,6 +682,8 @@ static Network *network_free(Network *network) { sd_ipv4acd_unref(network->dhcp_acd); strv_free(network->ntp); + for (unsigned i = 0; i < network->n_dns; i++) + in_addr_full_free(network->dns[i]); free(network->dns); ordered_set_free_free(network->search_domains); ordered_set_free_free(network->route_domains); @@ -1194,16 +1196,17 @@ int config_parse_dns( assert(rvalue); if (isempty(rvalue)) { + for (unsigned i = 0; i < n->n_dns; i++) + in_addr_full_free(n->dns[i]); n->dns = mfree(n->dns); n->n_dns = 0; return 0; } for (const char *p = rvalue;;) { + _cleanup_(in_addr_full_freep) struct in_addr_full *dns = NULL; _cleanup_free_ char *w = NULL; - union in_addr_union a; - struct in_addr_data *m; - int family; + struct in_addr_full **m; r = extract_first_word(&p, &w, NULL, 0); if (r == -ENOMEM) @@ -1216,22 +1219,21 @@ int config_parse_dns( if (r == 0) return 0; - r = in_addr_from_string_auto(w, &family, &a); + r = in_addr_full_new_from_string(w, &dns); if (r < 0) { log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse dns server address, ignoring: %s", w); continue; } - m = reallocarray(n->dns, n->n_dns + 1, sizeof(struct in_addr_data)); + if (IN_SET(dns->port, 53, 853)) + dns->port = 0; + + m = reallocarray(n->dns, n->n_dns + 1, sizeof(struct in_addr_full*)); if (!m) return log_oom(); - m[n->n_dns++] = (struct in_addr_data) { - .family = family, - .address = a, - }; - + m[n->n_dns++] = TAKE_PTR(dns); n->dns = m; } } diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index 424298248f..17109d139c 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -32,6 +32,7 @@ #include "networkd-util.h" #include "ordered-set.h" #include "resolve-util.h" +#include "socket-netlink.h" typedef enum IPv6PrivacyExtensions { /* The values map to the kernel's /proc/sys/net/ipv6/conf/xxx/use_tempaddr values */ @@ -316,7 +317,7 @@ struct Network { OrderedHashmap *sr_iov_by_section; /* All kinds of DNS configuration */ - struct in_addr_data *dns; + struct in_addr_full **dns; unsigned n_dns; OrderedSet *search_domains, *route_domains; diff --git a/src/network/networkd-radv.c b/src/network/networkd-radv.c index 8b473836db..088cdf11a3 100644 --- a/src/network/networkd-radv.c +++ b/src/network/networkd-radv.c @@ -463,10 +463,10 @@ static int radv_get_ip6dns(Network *network, struct in6_addr **dns, for (i = 0; i < network->n_dns; i++) { union in_addr_union *addr; - if (network->dns[i].family != AF_INET6) + if (network->dns[i]->family != AF_INET6) continue; - addr = &network->dns[i].address; + addr = &network->dns[i]->address; if (in_addr_is_null(AF_INET6, addr) || in_addr_is_link_local(AF_INET6, addr) || From 64581765148083b26ca38c89add870789fe0e6f7 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 3 Jul 2020 18:29:13 +0900 Subject: [PATCH 10/24] network: do not save DNS= entries not match link ifindex --- src/network/networkd-link.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 7e7713519b..1d73a3c34f 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -4111,10 +4111,13 @@ static void print_link_hashmap(FILE *f, const char *prefix, Hashmap* h) { fputc('\n', f); } -static void link_save_dns(FILE *f, struct in_addr_full **dns, unsigned n_dns, bool *space) { +static void link_save_dns(Link *link, FILE *f, struct in_addr_full **dns, unsigned n_dns, bool *space) { for (unsigned j = 0; j < n_dns; j++) { const char *str; + if (dns[j]->ifindex != 0 && dns[j]->ifindex != link->ifindex) + continue; + str = in_addr_full_to_string(dns[j]); if (!str) continue; @@ -4251,9 +4254,9 @@ int link_save(Link *link) { fputs("DNS=", f); space = false; if (link->n_dns != (unsigned) -1) - link_save_dns(f, link->dns, link->n_dns, &space); + link_save_dns(link, f, link->dns, link->n_dns, &space); else - link_save_dns(f, link->network->dns, link->network->n_dns, &space); + link_save_dns(link, f, link->network->dns, link->network->n_dns, &space); serialize_addresses(f, NULL, &space, NULL, From 87d648977631c55957776812f90d83ba311bc740 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 3 Jul 2020 18:34:37 +0900 Subject: [PATCH 11/24] network: save DNS servers specified by DBus interface Also, filter out DNS servers which do not match link ifindex. --- src/network/networkd-manager.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index a87bf25d64..273c00c36b 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -1425,13 +1425,16 @@ static int manager_connect_rtnl(Manager *m) { return 0; } -static int ordered_set_put_dns_server(OrderedSet *s, struct in_addr_full *dns) { +static int ordered_set_put_dns_server(OrderedSet *s, int ifindex, struct in_addr_full *dns) { const char *p; int r; assert(s); assert(dns); + if (dns->ifindex != 0 && dns->ifindex != ifindex) + return 0; + p = in_addr_full_to_string(dns); if (!p) return 0; @@ -1443,7 +1446,7 @@ static int ordered_set_put_dns_server(OrderedSet *s, struct in_addr_full *dns) { return r; } -static int ordered_set_put_dns_servers(OrderedSet *s, struct in_addr_full **dns, unsigned n) { +static int ordered_set_put_dns_servers(OrderedSet *s, int ifindex, struct in_addr_full **dns, unsigned n) { int r, c = 0; unsigned i; @@ -1451,7 +1454,7 @@ static int ordered_set_put_dns_servers(OrderedSet *s, struct in_addr_full **dns, assert(dns || n == 0); for (i = 0; i < n; i++) { - r = ordered_set_put_dns_server(s, dns[i]); + r = ordered_set_put_dns_server(s, ifindex, dns[i]); if (r < 0) return r; @@ -1558,7 +1561,10 @@ static int manager_save(Manager *m) { continue; /* First add the static configured entries */ - r = ordered_set_put_dns_servers(dns, link->network->dns, link->network->n_dns); + if (link->n_dns != (unsigned) -1) + r = ordered_set_put_dns_servers(dns, link->ifindex, link->dns, link->n_dns); + else + r = ordered_set_put_dns_servers(dns, link->ifindex, link->network->dns, link->network->n_dns); if (r < 0) return r; From 4e11ddfdd3c1f93721b8ca534e33e16ced32ff06 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 3 Jul 2020 20:03:00 +0900 Subject: [PATCH 12/24] network: add DBus method to set DNS server with port number and SNI --- src/network/networkd-link-bus.c | 34 +++++++++++++++++++++++++----- src/network/networkd-link-bus.h | 1 + src/network/networkd-manager-bus.c | 5 +++++ 3 files changed, 35 insertions(+), 5 deletions(-) diff --git a/src/network/networkd-link-bus.c b/src/network/networkd-link-bus.c index dec0d9be46..8b271f9693 100644 --- a/src/network/networkd-link-bus.c +++ b/src/network/networkd-link-bus.c @@ -114,7 +114,7 @@ int bus_link_method_set_ntp_servers(sd_bus_message *message, void *userdata, sd_ return sd_bus_reply_method_return(message, NULL); } -int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_bus_error *error) { +static int bus_link_method_set_dns_servers_internal(sd_bus_message *message, void *userdata, sd_bus_error *error, bool extended) { struct in_addr_full **dns = NULL; size_t allocated = 0, n = 0; Link *l = userdata; @@ -127,19 +127,21 @@ int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_ if (r < 0) return r; - r = sd_bus_message_enter_container(message, 'a', "(iay)"); + r = sd_bus_message_enter_container(message, 'a', extended ? "(iayqs)" : "(iay)"); if (r < 0) return r; for (;;) { + const char *server_name = NULL; union in_addr_union a; + uint16_t port = 0; + const void *d; int family; size_t sz; - const void *d; assert_cc(sizeof(int) == sizeof(int32_t)); - r = sd_bus_message_enter_container(message, 'r', "iay"); + r = sd_bus_message_enter_container(message, 'r', extended ? "iayqs" : "iay"); if (r < 0) goto finalize; if (r == 0) @@ -167,6 +169,19 @@ int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_ goto finalize; } + if (extended) { + r = sd_bus_message_read(message, "q", &port); + if (r < 0) + goto finalize; + + if (IN_SET(port, 53, 853)) + port = 0; + + r = sd_bus_message_read(message, "s", &server_name); + if (r < 0) + goto finalize; + } + r = sd_bus_message_exit_container(message); if (r < 0) goto finalize; @@ -177,7 +192,7 @@ int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_ } memcpy(&a, d, sz); - r = in_addr_full_new(family, &a, 0, 0, NULL, dns + n); + r = in_addr_full_new(family, &a, port, 0, server_name, dns + n); if (r < 0) goto finalize; @@ -218,6 +233,14 @@ finalize: return r; } +int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_bus_error *error) { + return bus_link_method_set_dns_servers_internal(message, userdata, error, false); +} + +int bus_link_method_set_dns_servers_ex(sd_bus_message *message, void *userdata, sd_bus_error *error) { + return bus_link_method_set_dns_servers_internal(message, userdata, error, true); +} + int bus_link_method_set_domains(sd_bus_message *message, void *userdata, sd_bus_error *error) { _cleanup_(ordered_set_freep) OrderedSet *search_domains = NULL, *route_domains = NULL; Link *l = userdata; @@ -696,6 +719,7 @@ const sd_bus_vtable link_vtable[] = { SD_BUS_METHOD("SetNTP", "as", NULL, bus_link_method_set_ntp_servers, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("SetDNS", "a(iay)", NULL, bus_link_method_set_dns_servers, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("SetDNSEx", "a(iayqs)", NULL, bus_link_method_set_dns_servers_ex, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("SetDomains", "a(sb)", NULL, bus_link_method_set_domains, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("SetDefaultRoute", "b", NULL, bus_link_method_set_default_route, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("SetLLMNR", "s", NULL, bus_link_method_set_llmnr, SD_BUS_VTABLE_UNPRIVILEGED), diff --git a/src/network/networkd-link-bus.h b/src/network/networkd-link-bus.h index afe0197dbd..94474f22ff 100644 --- a/src/network/networkd-link-bus.h +++ b/src/network/networkd-link-bus.h @@ -21,6 +21,7 @@ int property_get_address_state(sd_bus *bus, const char *path, const char *interf int bus_link_method_set_ntp_servers(sd_bus_message *message, void *userdata, sd_bus_error *error); int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_bus_error *error); +int bus_link_method_set_dns_servers_ex(sd_bus_message *message, void *userdata, sd_bus_error *error); int bus_link_method_set_domains(sd_bus_message *message, void *userdata, sd_bus_error *error); int bus_link_method_set_default_route(sd_bus_message *message, void *userdata, sd_bus_error *error); int bus_link_method_set_llmnr(sd_bus_message *message, void *userdata, sd_bus_error *error); diff --git a/src/network/networkd-manager-bus.c b/src/network/networkd-manager-bus.c index e956c5ed9a..355a932db2 100644 --- a/src/network/networkd-manager-bus.c +++ b/src/network/networkd-manager-bus.c @@ -151,6 +151,10 @@ static int bus_method_set_link_dns_servers(sd_bus_message *message, void *userda return call_link_method(userdata, message, bus_link_method_set_dns_servers, error); } +static int bus_method_set_link_dns_servers_ex(sd_bus_message *message, void *userdata, sd_bus_error *error) { + return call_link_method(userdata, message, bus_link_method_set_dns_servers_ex, error); +} + static int bus_method_set_link_domains(sd_bus_message *message, void *userdata, sd_bus_error *error) { return call_link_method(userdata, message, bus_link_method_set_domains, error); } @@ -243,6 +247,7 @@ const sd_bus_vtable manager_vtable[] = { SD_BUS_METHOD("GetLinkByIndex", "i", "so", method_get_link_by_index, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("SetLinkNTP", "ias", NULL, bus_method_set_link_ntp_servers, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("SetLinkDNS", "ia(iay)", NULL, bus_method_set_link_dns_servers, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("SetLinkDNSEx", "ia(iayqs)", NULL, bus_method_set_link_dns_servers_ex, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("SetLinkDomains", "ia(sb)", NULL, bus_method_set_link_domains, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("SetLinkDefaultRoute", "ib", NULL, bus_method_set_link_default_route, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("SetLinkLLMNR", "is", NULL, bus_method_set_link_llmnr, SD_BUS_VTABLE_UNPRIVILEGED), From 95ce1ba87bc5fb0a439d91336dc7456d7c61db0b Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 3 Jul 2020 20:31:15 +0900 Subject: [PATCH 13/24] resolve: add DBus method to set DNS server with port number and SNI --- src/resolve/resolved-bus.c | 9 +++ src/resolve/resolved-link-bus.c | 110 ++++++++++++++++++++++---------- src/resolve/resolved-link-bus.h | 1 + 3 files changed, 88 insertions(+), 32 deletions(-) diff --git a/src/resolve/resolved-bus.c b/src/resolve/resolved-bus.c index 45687c8fca..2de86b0f4c 100644 --- a/src/resolve/resolved-bus.c +++ b/src/resolve/resolved-bus.c @@ -1532,6 +1532,10 @@ static int bus_method_set_link_dns_servers(sd_bus_message *message, void *userda return call_link_method(userdata, message, bus_link_method_set_dns_servers, error); } +static int bus_method_set_link_dns_servers_ex(sd_bus_message *message, void *userdata, sd_bus_error *error) { + return call_link_method(userdata, message, bus_link_method_set_dns_servers_ex, error); +} + static int bus_method_set_link_domains(sd_bus_message *message, void *userdata, sd_bus_error *error) { return call_link_method(userdata, message, bus_link_method_set_domains, error); } @@ -1895,6 +1899,11 @@ static const sd_bus_vtable resolve_vtable[] = { SD_BUS_NO_RESULT, bus_method_set_link_dns_servers, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_ARGS("SetLinkDNSEx", + SD_BUS_ARGS("i", ifindex, "a(iayqs)", addresses), + SD_BUS_NO_RESULT, + bus_method_set_link_dns_servers_ex, + SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD_WITH_ARGS("SetLinkDomains", SD_BUS_ARGS("i", ifindex, "a(sb)", domains), SD_BUS_NO_RESULT, diff --git a/src/resolve/resolved-link-bus.c b/src/resolve/resolved-link-bus.c index 1694b1aa5a..53fe180b81 100644 --- a/src/resolve/resolved-link-bus.c +++ b/src/resolve/resolved-link-bus.c @@ -13,6 +13,7 @@ #include "resolved-bus.h" #include "resolved-link-bus.h" #include "resolved-resolv-conf.h" +#include "socket-netlink.h" #include "stdio-util.h" #include "strv.h" #include "user-util.h" @@ -204,11 +205,10 @@ static int verify_unmanaged_link(Link *l, sd_bus_error *error) { return 0; } -int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_bus_error *error) { - _cleanup_free_ struct in_addr_data *dns = NULL; +static int bus_link_method_set_dns_servers_internal(sd_bus_message *message, void *userdata, sd_bus_error *error, bool extended) { + struct in_addr_full **dns = NULL; size_t allocated = 0, n = 0; Link *l = userdata; - unsigned i; int r; assert(message); @@ -218,76 +218,106 @@ int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_ if (r < 0) return r; - r = sd_bus_message_enter_container(message, 'a', "(iay)"); + r = sd_bus_message_enter_container(message, 'a', extended ? "(iayqs)" : "(iay)"); if (r < 0) return r; for (;;) { + const char *server_name = NULL; + union in_addr_union a; + uint16_t port = 0; + const void *d; int family; size_t sz; - const void *d; assert_cc(sizeof(int) == sizeof(int32_t)); - r = sd_bus_message_enter_container(message, 'r', "iay"); + r = sd_bus_message_enter_container(message, 'r', extended ? "iayqs" : "iay"); if (r < 0) - return r; + goto finalize; if (r == 0) break; r = sd_bus_message_read(message, "i", &family); if (r < 0) - return r; + goto finalize; - if (!IN_SET(family, AF_INET, AF_INET6)) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family); + if (!IN_SET(family, AF_INET, AF_INET6)) { + r = sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family); + goto finalize; + } r = sd_bus_message_read_array(message, 'y', &d, &sz); if (r < 0) - return r; - if (sz != FAMILY_ADDRESS_SIZE(family)) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid address size"); + goto finalize; + if (sz != FAMILY_ADDRESS_SIZE(family)) { + r = sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid address size"); + goto finalize; + } - if (!dns_server_address_valid(family, d)) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid DNS server address"); + if (!dns_server_address_valid(family, d)) { + r = sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid DNS server address"); + goto finalize; + } + + if (extended) { + r = sd_bus_message_read(message, "q", &port); + if (r < 0) + goto finalize; + + if (IN_SET(port, 53, 853)) + port = 0; + + r = sd_bus_message_read(message, "s", &server_name); + if (r < 0) + goto finalize; + } r = sd_bus_message_exit_container(message); if (r < 0) - return r; + goto finalize; - if (!GREEDY_REALLOC(dns, allocated, n+1)) - return -ENOMEM; + if (!GREEDY_REALLOC(dns, allocated, n+1)) { + r = -ENOMEM; + goto finalize; + } - dns[n].family = family; - memcpy(&dns[n].address, d, sz); + memcpy(&a, d, sz); + r = in_addr_full_new(family, &a, port, 0, server_name, dns + n); + if (r < 0) + goto finalize; n++; } r = sd_bus_message_exit_container(message); if (r < 0) - return r; + goto finalize; r = bus_verify_polkit_async(message, CAP_NET_ADMIN, "org.freedesktop.resolve1.set-dns-servers", NULL, true, UID_INVALID, &l->manager->polkit_registry, error); if (r < 0) - return r; - if (r == 0) - return 1; /* Polkit will call us back */ + goto finalize; + if (r == 0) { + r = 1; /* Polkit will call us back */ + goto finalize; + } dns_server_mark_all(l->dns_servers); - for (i = 0; i < n; i++) { + for (size_t i = 0; i < n; i++) { DnsServer *s; - s = dns_server_find(l->dns_servers, dns[i].family, &dns[i].address, 0, 0, NULL); + s = dns_server_find(l->dns_servers, dns[i]->family, &dns[i]->address, dns[i]->port, 0, dns[i]->server_name); 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, 0, NULL); - if (r < 0) - goto clear; + r = dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, dns[i]->family, &dns[i]->address, dns[i]->port, 0, dns[i]->server_name); + if (r < 0) { + dns_server_unlink_all(l->dns_servers); + goto finalize; + } } } @@ -299,13 +329,24 @@ int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_ (void) manager_write_resolv_conf(l->manager); (void) manager_send_changed(l->manager, "DNS"); - return sd_bus_reply_method_return(message, NULL); + r = sd_bus_reply_method_return(message, NULL); + +finalize: + for (size_t i = 0; i < n; i++) + in_addr_full_free(dns[i]); + free(dns); -clear: - dns_server_unlink_all(l->dns_servers); return r; } +int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_bus_error *error) { + return bus_link_method_set_dns_servers_internal(message, userdata, error, false); +} + +int bus_link_method_set_dns_servers_ex(sd_bus_message *message, void *userdata, sd_bus_error *error) { + return bus_link_method_set_dns_servers_internal(message, userdata, error, true); +} + int bus_link_method_set_domains(sd_bus_message *message, void *userdata, sd_bus_error *error) { Link *l = userdata; int r; @@ -777,6 +818,11 @@ static const sd_bus_vtable link_vtable[] = { SD_BUS_NO_RESULT, bus_link_method_set_dns_servers, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_ARGS("SetDNSEx", + SD_BUS_ARGS("a(iayqs)", addresses), + SD_BUS_NO_RESULT, + bus_link_method_set_dns_servers_ex, + SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD_WITH_ARGS("SetDomains", SD_BUS_ARGS("a(sb)", domains), SD_BUS_NO_RESULT, diff --git a/src/resolve/resolved-link-bus.h b/src/resolve/resolved-link-bus.h index c249960024..fc85ff855c 100644 --- a/src/resolve/resolved-link-bus.h +++ b/src/resolve/resolved-link-bus.h @@ -11,6 +11,7 @@ extern const BusObjectImplementation link_object; char *link_bus_path(const Link *link); int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_bus_error *error); +int bus_link_method_set_dns_servers_ex(sd_bus_message *message, void *userdata, sd_bus_error *error); int bus_link_method_set_domains(sd_bus_message *message, void *userdata, sd_bus_error *error); int bus_link_method_set_default_route(sd_bus_message *message, void *userdata, sd_bus_error *error); int bus_link_method_set_llmnr(sd_bus_message *message, void *userdata, sd_bus_error *error); From 8e56ea4c88ee77db0322fb0a2233816f6f50eb53 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 3 Jul 2020 21:03:51 +0900 Subject: [PATCH 14/24] resolve: add DBus properties which support DNS SNI and port number --- src/resolve/resolved-bus.c | 173 ++++++++++++++++++++++++-------- src/resolve/resolved-bus.h | 2 +- src/resolve/resolved-link-bus.c | 72 ++++++++++--- 3 files changed, 192 insertions(+), 55 deletions(-) diff --git a/src/resolve/resolved-bus.c b/src/resolve/resolved-bus.c index 2de86b0f4c..7d6e883e8b 100644 --- a/src/resolve/resolved-bus.c +++ b/src/resolve/resolved-bus.c @@ -1218,19 +1218,26 @@ fail: return r; } -int bus_dns_server_append(sd_bus_message *reply, DnsServer *s, bool with_ifindex) { +int bus_dns_server_append(sd_bus_message *reply, DnsServer *s, bool with_ifindex, bool extended) { int r; assert(reply); if (!s) { - if (with_ifindex) - return sd_bus_message_append(reply, "(iiay)", 0, AF_UNSPEC, 0); - else - return sd_bus_message_append(reply, "(iay)", AF_UNSPEC, 0); + if (with_ifindex) { + if (extended) + return sd_bus_message_append(reply, "(iiayqs)", 0, AF_UNSPEC, 0, 0, NULL); + else + return sd_bus_message_append(reply, "(iiay)", 0, AF_UNSPEC, 0); + } else { + if (extended) + return sd_bus_message_append(reply, "(iayqs)", AF_UNSPEC, 0, 0, NULL); + else + return sd_bus_message_append(reply, "(iay)", AF_UNSPEC, 0); + } } - r = sd_bus_message_open_container(reply, 'r', with_ifindex ? "iiay" : "iay"); + r = sd_bus_message_open_container(reply, 'r', with_ifindex ? (extended ? "iiayqs" : "iiay") : (extended ? "iayqs" : "iay")); if (r < 0) return r; @@ -1248,6 +1255,55 @@ int bus_dns_server_append(sd_bus_message *reply, DnsServer *s, bool with_ifindex if (r < 0) return r; + if (extended) { + r = sd_bus_message_append(reply, "q", s->port); + if (r < 0) + return r; + + r = sd_bus_message_append(reply, "s", s->server_name); + if (r < 0) + return r; + } + + return sd_bus_message_close_container(reply); +} + +static int bus_property_get_dns_servers_internal( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error, + bool extended) { + + Manager *m = userdata; + DnsServer *s; + Iterator i; + Link *l; + int r; + + assert(reply); + assert(m); + + r = sd_bus_message_open_container(reply, 'a', extended ? "(iiayqs)" : "(iiay)"); + if (r < 0) + return r; + + LIST_FOREACH(servers, s, m->dns_servers) { + r = bus_dns_server_append(reply, s, true, extended); + if (r < 0) + return r; + } + + HASHMAP_FOREACH(l, m->links, i) + LIST_FOREACH(servers, s, l->dns_servers) { + r = bus_dns_server_append(reply, s, true, extended); + if (r < 0) + return r; + } + return sd_bus_message_close_container(reply); } @@ -1259,33 +1315,46 @@ static int bus_property_get_dns_servers( sd_bus_message *reply, void *userdata, sd_bus_error *error) { + return bus_property_get_dns_servers_internal(bus, path, interface, property, reply, userdata, error, false); +} - Manager *m = userdata; - DnsServer *s; - Iterator i; - Link *l; +static int bus_property_get_dns_servers_ex( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + return bus_property_get_dns_servers_internal(bus, path, interface, property, reply, userdata, error, true); +} + +static int bus_property_get_fallback_dns_servers_internal( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error, + bool extended) { + + DnsServer *s, **f = userdata; int r; assert(reply); - assert(m); + assert(f); - r = sd_bus_message_open_container(reply, 'a', "(iiay)"); + r = sd_bus_message_open_container(reply, 'a', extended ? "(iiayqs)" : "(iiay)"); if (r < 0) return r; - LIST_FOREACH(servers, s, m->dns_servers) { - r = bus_dns_server_append(reply, s, true); + LIST_FOREACH(servers, s, *f) { + r = bus_dns_server_append(reply, s, true, extended); if (r < 0) return r; } - HASHMAP_FOREACH(l, m->links, i) - LIST_FOREACH(servers, s, l->dns_servers) { - r = bus_dns_server_append(reply, s, true); - if (r < 0) - return r; - } - return sd_bus_message_close_container(reply); } @@ -1297,24 +1366,38 @@ static int bus_property_get_fallback_dns_servers( sd_bus_message *reply, void *userdata, sd_bus_error *error) { + return bus_property_get_fallback_dns_servers_internal(bus, path, interface, property, reply, userdata, error, false); +} - DnsServer *s, **f = userdata; - int r; +static int bus_property_get_fallback_dns_servers_ex( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + return bus_property_get_fallback_dns_servers_internal(bus, path, interface, property, reply, userdata, error, true); +} + +static int bus_property_get_current_dns_server_internal( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error, + bool extended) { + + DnsServer *s; assert(reply); - assert(f); + assert(userdata); - r = sd_bus_message_open_container(reply, 'a', "(iiay)"); - if (r < 0) - return r; + s = *(DnsServer **) userdata; - LIST_FOREACH(servers, s, *f) { - r = bus_dns_server_append(reply, s, true); - if (r < 0) - return r; - } - - return sd_bus_message_close_container(reply); + return bus_dns_server_append(reply, s, true, extended); } static int bus_property_get_current_dns_server( @@ -1325,15 +1408,18 @@ static int bus_property_get_current_dns_server( sd_bus_message *reply, void *userdata, sd_bus_error *error) { + return bus_property_get_current_dns_server_internal(bus, path, interface, property, reply, userdata, error, false); +} - DnsServer *s; - - assert(reply); - assert(userdata); - - s = *(DnsServer **) userdata; - - return bus_dns_server_append(reply, s, true); +static int bus_property_get_current_dns_server_ex( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + return bus_property_get_current_dns_server_internal(bus, path, interface, property, reply, userdata, error, true); } static int bus_property_get_domains( @@ -1848,8 +1934,11 @@ static const sd_bus_vtable resolve_vtable[] = { SD_BUS_PROPERTY("MulticastDNS", "s", bus_property_get_resolve_support, offsetof(Manager, mdns_support), 0), SD_BUS_PROPERTY("DNSOverTLS", "s", bus_property_get_dns_over_tls_mode, 0, 0), SD_BUS_PROPERTY("DNS", "a(iiay)", bus_property_get_dns_servers, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("DNSEx", "a(iiayqs)", bus_property_get_dns_servers_ex, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("FallbackDNS", "a(iiay)", bus_property_get_fallback_dns_servers, offsetof(Manager, fallback_dns_servers), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("FallbackDNSEx", "a(iiayqs)", bus_property_get_fallback_dns_servers_ex, offsetof(Manager, fallback_dns_servers), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("CurrentDNSServer", "(iiay)", bus_property_get_current_dns_server, offsetof(Manager, current_dns_server), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("CurrentDNSServerEx", "(iiayqs)", bus_property_get_current_dns_server_ex, offsetof(Manager, current_dns_server), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("Domains", "a(isb)", bus_property_get_domains, 0, 0), SD_BUS_PROPERTY("TransactionStatistics", "(tt)", bus_property_get_transaction_statistics, 0, 0), SD_BUS_PROPERTY("CacheStatistics", "(ttt)", bus_property_get_cache_statistics, 0, 0), diff --git a/src/resolve/resolved-bus.h b/src/resolve/resolved-bus.h index 6d6b095323..28caa64a6b 100644 --- a/src/resolve/resolved-bus.h +++ b/src/resolve/resolved-bus.h @@ -9,7 +9,7 @@ extern const BusObjectImplementation manager_object; int manager_connect_bus(Manager *m); int _manager_send_changed(Manager *manager, const char *property, ...) _sentinel_; #define manager_send_changed(manager, ...) _manager_send_changed(manager, __VA_ARGS__, NULL) -int bus_dns_server_append(sd_bus_message *reply, DnsServer *s, bool with_ifindex); +int bus_dns_server_append(sd_bus_message *reply, DnsServer *s, bool with_ifindex, bool extended); int bus_property_get_resolve_support(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error); diff --git a/src/resolve/resolved-link-bus.c b/src/resolve/resolved-link-bus.c index 53fe180b81..117f8a378a 100644 --- a/src/resolve/resolved-link-bus.c +++ b/src/resolve/resolved-link-bus.c @@ -38,14 +38,15 @@ static int property_get_dns_over_tls_mode( return sd_bus_message_append(reply, "s", dns_over_tls_mode_to_string(link_get_dns_over_tls_mode(l))); } -static int property_get_dns( +static int property_get_dns_internal( sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, - sd_bus_error *error) { + sd_bus_error *error, + bool extended) { Link *l = userdata; DnsServer *s; @@ -54,12 +55,12 @@ static int property_get_dns( assert(reply); assert(l); - r = sd_bus_message_open_container(reply, 'a', "(iay)"); + r = sd_bus_message_open_container(reply, 'a', extended ? "(iayqs)" : "(iay)"); if (r < 0) return r; LIST_FOREACH(servers, s, l->dns_servers) { - r = bus_dns_server_append(reply, s, false); + r = bus_dns_server_append(reply, s, false, extended); if (r < 0) return r; } @@ -67,6 +68,48 @@ static int property_get_dns( return sd_bus_message_close_container(reply); } +static int property_get_dns( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + return property_get_dns_internal(bus, path, interface, property, reply, userdata, error, false); +} + +static int property_get_dns_ex( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + return property_get_dns_internal(bus, path, interface, property, reply, userdata, error, true); +} + +static int property_get_current_dns_server_internal( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error, + bool extended) { + + DnsServer *s; + + assert(reply); + assert(userdata); + + s = *(DnsServer **) userdata; + + return bus_dns_server_append(reply, s, false, extended); +} + static int property_get_current_dns_server( sd_bus *bus, const char *path, @@ -75,15 +118,18 @@ static int property_get_current_dns_server( sd_bus_message *reply, void *userdata, sd_bus_error *error) { + return property_get_current_dns_server_internal(bus, path, interface, property, reply, userdata, error, false); +} - DnsServer *s; - - assert(reply); - assert(userdata); - - s = *(DnsServer **) userdata; - - return bus_dns_server_append(reply, s, false); +static int property_get_current_dns_server_ex( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + return property_get_current_dns_server_internal(bus, path, interface, property, reply, userdata, error, true); } static int property_get_domains( @@ -803,7 +849,9 @@ static const sd_bus_vtable link_vtable[] = { SD_BUS_PROPERTY("ScopesMask", "t", property_get_scopes_mask, 0, 0), SD_BUS_PROPERTY("DNS", "a(iay)", property_get_dns, 0, 0), + SD_BUS_PROPERTY("DNSEx", "a(iayqs)", property_get_dns_ex, 0, 0), SD_BUS_PROPERTY("CurrentDNSServer", "(iay)", property_get_current_dns_server, offsetof(Link, current_dns_server), 0), + SD_BUS_PROPERTY("CurrentDNSServerEx", "(iayqs)", property_get_current_dns_server_ex, offsetof(Link, current_dns_server), 0), SD_BUS_PROPERTY("Domains", "a(sb)", property_get_domains, 0, 0), SD_BUS_PROPERTY("DefaultRoute", "b", property_get_default_route, 0, 0), SD_BUS_PROPERTY("LLMNR", "s", bus_property_get_resolve_support, offsetof(Link, llmnr_support), 0), From b1881e8320ac43a40467117e8cec240e3a5ef57d Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 3 Jul 2020 21:05:15 +0900 Subject: [PATCH 15/24] resolvectl: make DNS servers can be specified with port number and SNI --- src/resolve/resolvectl.c | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/src/resolve/resolvectl.c b/src/resolve/resolvectl.c index c01524b9cc..7c1109cbc9 100644 --- a/src/resolve/resolvectl.c +++ b/src/resolve/resolvectl.c @@ -1867,12 +1867,12 @@ static int verb_status(int argc, char **argv, void *userdata) { return r; } -static int call_dns(sd_bus *bus, char **dns, const BusLocator *locator, sd_bus_error *error) { +static int call_dns(sd_bus *bus, char **dns, const BusLocator *locator, sd_bus_error *error, bool extended) { _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL; char **p; int r; - r = bus_message_new_method_call(bus, &req, locator, "SetLinkDNS"); + r = bus_message_new_method_call(bus, &req, locator, extended ? "SetLinkDNSEx" : "SetLinkDNS"); if (r < 0) return bus_log_create_error(r); @@ -1880,7 +1880,7 @@ static int call_dns(sd_bus *bus, char **dns, const BusLocator *locator, sd_bus_e if (r < 0) return bus_log_create_error(r); - r = sd_bus_message_open_container(req, 'a', "(iay)"); + r = sd_bus_message_open_container(req, 'a', extended ? "(iayqs)" : "(iay)"); if (r < 0) return bus_log_create_error(r); @@ -1888,13 +1888,19 @@ static int call_dns(sd_bus *bus, char **dns, const BusLocator *locator, sd_bus_e * empty list, which will clear the list of domains for an interface. */ if (!strv_equal(dns, STRV_MAKE(""))) STRV_FOREACH(p, dns) { + _cleanup_free_ char *name = NULL; struct in_addr_data data; + uint16_t port; + int ifindex; - r = in_addr_from_string_auto(*p, &data.family, &data.address); + r = in_addr_port_ifindex_name_from_string_auto(*p, &data.family, &data.address, &port, &ifindex, &name); if (r < 0) return log_error_errno(r, "Failed to parse DNS server address: %s", *p); - r = sd_bus_message_open_container(req, 'r', "iay"); + if (ifindex != 0 && ifindex != arg_ifindex) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid ifindex: %i", ifindex); + + r = sd_bus_message_open_container(req, 'r', extended ? "iayqs" : "iay"); if (r < 0) return bus_log_create_error(r); @@ -1906,6 +1912,16 @@ static int call_dns(sd_bus *bus, char **dns, const BusLocator *locator, sd_bus_e if (r < 0) return bus_log_create_error(r); + if (extended) { + r = sd_bus_message_append(req, "q", port); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append(req, "s", name); + if (r < 0) + return bus_log_create_error(r); + } + r = sd_bus_message_close_container(req); if (r < 0) return bus_log_create_error(r); @@ -1915,7 +1931,10 @@ static int call_dns(sd_bus *bus, char **dns, const BusLocator *locator, sd_bus_e if (r < 0) return bus_log_create_error(r); - return sd_bus_call(bus, req, 0, error, NULL); + r = sd_bus_call(bus, req, 0, error, NULL); + if (r < 0 && extended && sd_bus_error_has_name(error, SD_BUS_ERROR_UNKNOWN_METHOD)) + return call_dns(bus, dns, locator, error, false); + return r; } static int verb_dns(int argc, char **argv, void *userdata) { @@ -1937,11 +1956,11 @@ static int verb_dns(int argc, char **argv, void *userdata) { if (argc < 3) return status_ifindex(bus, arg_ifindex, NULL, STATUS_DNS, NULL); - r = call_dns(bus, argv + 2, bus_resolve_mgr, &error); + r = call_dns(bus, argv + 2, bus_resolve_mgr, &error, true); if (r < 0 && sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY)) { sd_bus_error_free(&error); - r = call_dns(bus, argv + 2, bus_network_mgr, &error); + r = call_dns(bus, argv + 2, bus_network_mgr, &error, true); } if (r < 0) { if (arg_ifindex_permissive && From a747e71c5600633db9a8e848f9c7c34793842260 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 3 Jul 2020 21:24:25 +0900 Subject: [PATCH 16/24] resolvectl: show DNS servers with port and SNI --- src/resolve/resolvectl.c | 135 ++++++++++++++++++++++++++++----------- 1 file changed, 96 insertions(+), 39 deletions(-) diff --git a/src/resolve/resolvectl.c b/src/resolve/resolvectl.c index 7c1109cbc9..46079645ca 100644 --- a/src/resolve/resolvectl.c +++ b/src/resolve/resolvectl.c @@ -1120,16 +1120,18 @@ static int reset_server_features(int argc, char **argv, void *userdata) { return 0; } -static int read_dns_server_one(sd_bus_message *m, bool with_ifindex, char **ret) { +static int read_dns_server_one(sd_bus_message *m, bool with_ifindex, bool extended, char **ret) { _cleanup_free_ char *pretty = NULL; int ifindex, family, r; + const char *name = NULL; + uint16_t port = 0; const void *a; size_t sz; assert(m); assert(ret); - r = sd_bus_message_enter_container(m, 'r', with_ifindex ? "iiay" : "iay"); + r = sd_bus_message_enter_container(m, 'r', with_ifindex ? (extended ? "iiayqs" : "iiay") : (extended ? "iayqs" : "iay")); if (r <= 0) return r; @@ -1147,6 +1149,16 @@ static int read_dns_server_one(sd_bus_message *m, bool with_ifindex, char **ret) if (r < 0) return r; + if (extended) { + r = sd_bus_message_read(m, "q", &port); + if (r < 0) + return r; + + r = sd_bus_message_read(m, "s", &name); + if (r < 0) + return r; + } + r = sd_bus_message_exit_container(m); if (r < 0) return r; @@ -1171,7 +1183,7 @@ static int read_dns_server_one(sd_bus_message *m, bool with_ifindex, char **ret) return 1; } - r = in_addr_to_string(family, a, &pretty); + r = in_addr_port_ifindex_name_to_string(family, a, port, ifindex, name, &pretty); if (r < 0) return r; @@ -1180,7 +1192,7 @@ static int read_dns_server_one(sd_bus_message *m, bool with_ifindex, char **ret) return 1; } -static int map_link_dns_servers(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) { +static int map_link_dns_servers_internal(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata, bool extended) { char ***l = userdata; int r; @@ -1189,14 +1201,14 @@ static int map_link_dns_servers(sd_bus *bus, const char *member, sd_bus_message assert(m); assert(l); - r = sd_bus_message_enter_container(m, 'a', "(iay)"); + r = sd_bus_message_enter_container(m, 'a', extended ? "(iayqs)" : "(iay)"); if (r < 0) return r; for (;;) { _cleanup_free_ char *pretty = NULL; - r = read_dns_server_one(m, false, &pretty); + r = read_dns_server_one(m, false, extended, &pretty); if (r < 0) return r; if (r == 0) @@ -1217,11 +1229,26 @@ static int map_link_dns_servers(sd_bus *bus, const char *member, sd_bus_message return 0; } +static int map_link_dns_servers(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) { + return map_link_dns_servers_internal(bus, member, m, error, userdata, false); +} + +static int map_link_dns_servers_ex(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) { + return map_link_dns_servers_internal(bus, member, m, error, userdata, true); +} + static int map_link_current_dns_server(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) { assert(m); assert(userdata); - return read_dns_server_one(m, false, userdata); + return read_dns_server_one(m, false, false, userdata); +} + +static int map_link_current_dns_server_ex(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) { + assert(m); + assert(userdata); + + return read_dns_server_one(m, false, true, userdata); } static int read_domain_one(sd_bus_message *m, bool with_ifindex, char **ret) { @@ -1315,7 +1342,9 @@ struct link_info { const char *dns_over_tls; const char *dnssec; char *current_dns; + char *current_dns_ex; char **dns; + char **dns_ex; char **domains; char **ntas; bool dnssec_supported; @@ -1324,7 +1353,9 @@ struct link_info { static void link_info_clear(struct link_info *p) { free(p->current_dns); + free(p->current_dns_ex); strv_free(p->dns); + strv_free(p->dns_ex); strv_free(p->domains); strv_free(p->ntas); } @@ -1346,17 +1377,19 @@ static int dump_list(Table *table, const char *prefix, char * const *l) { static int status_ifindex(sd_bus *bus, int ifindex, const char *name, StatusMode mode, bool *empty_line) { static const struct bus_properties_map property_map[] = { - { "ScopesMask", "t", NULL, offsetof(struct link_info, scopes_mask) }, - { "DNS", "a(iay)", map_link_dns_servers, offsetof(struct link_info, dns) }, - { "CurrentDNSServer", "(iay)", map_link_current_dns_server, offsetof(struct link_info, current_dns) }, - { "Domains", "a(sb)", map_link_domains, offsetof(struct link_info, domains) }, - { "DefaultRoute", "b", NULL, offsetof(struct link_info, default_route) }, - { "LLMNR", "s", NULL, offsetof(struct link_info, llmnr) }, - { "MulticastDNS", "s", NULL, offsetof(struct link_info, mdns) }, - { "DNSOverTLS", "s", NULL, offsetof(struct link_info, dns_over_tls) }, - { "DNSSEC", "s", NULL, offsetof(struct link_info, dnssec) }, - { "DNSSECNegativeTrustAnchors", "as", NULL, offsetof(struct link_info, ntas) }, - { "DNSSECSupported", "b", NULL, offsetof(struct link_info, dnssec_supported) }, + { "ScopesMask", "t", NULL, offsetof(struct link_info, scopes_mask) }, + { "DNS", "a(iay)", map_link_dns_servers, offsetof(struct link_info, dns) }, + { "DNSEx", "a(iayqs)", map_link_dns_servers_ex, offsetof(struct link_info, dns_ex) }, + { "CurrentDNSServer", "(iay)", map_link_current_dns_server, offsetof(struct link_info, current_dns) }, + { "CurrentDNSServerEx", "(iayqs)", map_link_current_dns_server_ex, offsetof(struct link_info, current_dns_ex) }, + { "Domains", "a(sb)", map_link_domains, offsetof(struct link_info, domains) }, + { "DefaultRoute", "b", NULL, offsetof(struct link_info, default_route) }, + { "LLMNR", "s", NULL, offsetof(struct link_info, llmnr) }, + { "MulticastDNS", "s", NULL, offsetof(struct link_info, mdns) }, + { "DNSOverTLS", "s", NULL, offsetof(struct link_info, dns_over_tls) }, + { "DNSSEC", "s", NULL, offsetof(struct link_info, dnssec) }, + { "DNSSECNegativeTrustAnchors", "as", NULL, offsetof(struct link_info, ntas) }, + { "DNSSECSupported", "b", NULL, offsetof(struct link_info, dnssec_supported) }, {} }; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; @@ -1396,7 +1429,7 @@ static int status_ifindex(sd_bus *bus, int ifindex, const char *name, StatusMode (void) pager_open(arg_pager_flags); if (mode == STATUS_DNS) - return status_print_strv_ifindex(ifindex, name, link_info.dns); + return status_print_strv_ifindex(ifindex, name, link_info.dns_ex ?: link_info.dns); if (mode == STATUS_DOMAIN) return status_print_strv_ifindex(ifindex, name, link_info.domains); @@ -1504,12 +1537,12 @@ static int status_ifindex(sd_bus *bus, int ifindex, const char *name, StatusMode if (link_info.current_dns) { r = table_add_many(table, TABLE_STRING, "Current DNS Server:", - TABLE_STRING, link_info.current_dns); + TABLE_STRING, link_info.current_dns_ex ?: link_info.current_dns); if (r < 0) return table_log_add_error(r); } - r = dump_list(table, "DNS Servers:", link_info.dns); + r = dump_list(table, "DNS Servers:", link_info.dns_ex ?: link_info.dns); if (r < 0) return r; @@ -1527,7 +1560,7 @@ static int status_ifindex(sd_bus *bus, int ifindex, const char *name, StatusMode return 0; } -static int map_global_dns_servers(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) { +static int map_global_dns_servers_internal(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata, bool extended) { char ***l = userdata; int r; @@ -1536,14 +1569,14 @@ static int map_global_dns_servers(sd_bus *bus, const char *member, sd_bus_messag assert(m); assert(l); - r = sd_bus_message_enter_container(m, 'a', "(iiay)"); + r = sd_bus_message_enter_container(m, 'a', extended ? "(iiayqs)" : "(iiay)"); if (r < 0) return r; for (;;) { _cleanup_free_ char *pretty = NULL; - r = read_dns_server_one(m, true, &pretty); + r = read_dns_server_one(m, true, extended, &pretty); if (r < 0) return r; if (r == 0) @@ -1564,11 +1597,26 @@ static int map_global_dns_servers(sd_bus *bus, const char *member, sd_bus_messag return 0; } +static int map_global_dns_servers(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) { + return map_global_dns_servers_internal(bus, member, m, error, userdata, false); +} + +static int map_global_dns_servers_ex(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) { + return map_global_dns_servers_internal(bus, member, m, error, userdata, true); +} + static int map_global_current_dns_server(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) { assert(m); assert(userdata); - return read_dns_server_one(m, true, userdata); + return read_dns_server_one(m, true, false, userdata); +} + +static int map_global_current_dns_server_ex(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) { + assert(m); + assert(userdata); + + return read_dns_server_one(m, true, true, userdata); } static int map_global_domains(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) { @@ -1623,8 +1671,11 @@ static int status_print_strv_global(char **p) { struct global_info { char *current_dns; + char *current_dns_ex; char **dns; + char **dns_ex; char **fallback_dns; + char **fallback_dns_ex; char **domains; char **ntas; const char *llmnr; @@ -1636,24 +1687,30 @@ struct global_info { static void global_info_clear(struct global_info *p) { free(p->current_dns); + free(p->current_dns_ex); strv_free(p->dns); + strv_free(p->dns_ex); strv_free(p->fallback_dns); + strv_free(p->fallback_dns_ex); strv_free(p->domains); strv_free(p->ntas); } static int status_global(sd_bus *bus, StatusMode mode, bool *empty_line) { static const struct bus_properties_map property_map[] = { - { "DNS", "a(iiay)", map_global_dns_servers, offsetof(struct global_info, dns) }, - { "FallbackDNS", "a(iiay)", map_global_dns_servers, offsetof(struct global_info, fallback_dns) }, - { "CurrentDNSServer", "(iiay)", map_global_current_dns_server, offsetof(struct global_info, current_dns) }, - { "Domains", "a(isb)", map_global_domains, offsetof(struct global_info, domains) }, - { "DNSSECNegativeTrustAnchors", "as", NULL, offsetof(struct global_info, ntas) }, - { "LLMNR", "s", NULL, offsetof(struct global_info, llmnr) }, - { "MulticastDNS", "s", NULL, offsetof(struct global_info, mdns) }, - { "DNSOverTLS", "s", NULL, offsetof(struct global_info, dns_over_tls) }, - { "DNSSEC", "s", NULL, offsetof(struct global_info, dnssec) }, - { "DNSSECSupported", "b", NULL, offsetof(struct global_info, dnssec_supported) }, + { "DNS", "a(iiay)", map_global_dns_servers, offsetof(struct global_info, dns) }, + { "DNSEx", "a(iiayqs)", map_global_dns_servers_ex, offsetof(struct global_info, dns_ex) }, + { "FallbackDNS", "a(iiay)", map_global_dns_servers, offsetof(struct global_info, fallback_dns) }, + { "FallbackDNSEx", "a(iiayqs)", map_global_dns_servers_ex, offsetof(struct global_info, fallback_dns_ex) }, + { "CurrentDNSServer", "(iiay)", map_global_current_dns_server, offsetof(struct global_info, current_dns) }, + { "CurrentDNSServerEx", "(iiayqs)", map_global_current_dns_server_ex, offsetof(struct global_info, current_dns_ex) }, + { "Domains", "a(isb)", map_global_domains, offsetof(struct global_info, domains) }, + { "DNSSECNegativeTrustAnchors", "as", NULL, offsetof(struct global_info, ntas) }, + { "LLMNR", "s", NULL, offsetof(struct global_info, llmnr) }, + { "MulticastDNS", "s", NULL, offsetof(struct global_info, mdns) }, + { "DNSOverTLS", "s", NULL, offsetof(struct global_info, dns_over_tls) }, + { "DNSSEC", "s", NULL, offsetof(struct global_info, dnssec) }, + { "DNSSECSupported", "b", NULL, offsetof(struct global_info, dnssec_supported) }, {} }; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; @@ -1679,7 +1736,7 @@ static int status_global(sd_bus *bus, StatusMode mode, bool *empty_line) { (void) pager_open(arg_pager_flags); if (mode == STATUS_DNS) - return status_print_strv_global(global_info.dns); + return status_print_strv_global(global_info.dns_ex ?: global_info.dns); if (mode == STATUS_DOMAIN) return status_print_strv_global(global_info.domains); @@ -1741,16 +1798,16 @@ static int status_global(sd_bus *bus, StatusMode mode, bool *empty_line) { if (global_info.current_dns) { r = table_add_many(table, TABLE_STRING, "Current DNS Server:", - TABLE_STRING, global_info.current_dns); + TABLE_STRING, global_info.current_dns_ex ?: global_info.current_dns); if (r < 0) return table_log_add_error(r); } - r = dump_list(table, "DNS Servers:", global_info.dns); + r = dump_list(table, "DNS Servers:", global_info.dns_ex ?: global_info.dns); if (r < 0) return r; - r = dump_list(table, "Fallback DNS Servers:", global_info.fallback_dns); + r = dump_list(table, "Fallback DNS Servers:", global_info.fallback_dns_ex ?: global_info.fallback_dns); if (r < 0) return r; From 66479677a91d7199d30230974586808b9372f040 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 3 Jul 2020 22:16:55 +0900 Subject: [PATCH 17/24] test-network: add tests for DNS= with port number and SNI --- test/test-network/conf/state-file-tests.network | 2 +- test/test-network/systemd-networkd-tests.py | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/test/test-network/conf/state-file-tests.network b/test/test-network/conf/state-file-tests.network index 468669c6cc..1f7e7d16f0 100644 --- a/test/test-network/conf/state-file-tests.network +++ b/test/test-network/conf/state-file-tests.network @@ -6,7 +6,7 @@ RequiredForOnline=routable [Network] IPv6AcceptRA=no -DNS=10.10.10.10 10.10.10.11 +DNS=10.10.10.10#aaa.com 10.10.10.11:1111#bbb.com [1111:2222::3333]:1234#ccc.com NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org Domains=hogehoge ~foofoo LLMNR=no diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py index 2d7f915850..677e39765e 100755 --- a/test/test-network/systemd-networkd-tests.py +++ b/test/test-network/systemd-networkd-tests.py @@ -2601,7 +2601,7 @@ class NetworkdStateFileTests(unittest.TestCase, Utilities): self.assertRegex(data, r'REQUIRED_FOR_ONLINE=yes') self.assertRegex(data, r'REQUIRED_OPER_STATE_FOR_ONLINE=routable') self.assertRegex(data, r'NETWORK_FILE=/run/systemd/network/state-file-tests.network') - self.assertRegex(data, r'DNS=10.10.10.10 10.10.10.11') + self.assertRegex(data, r'DNS=10.10.10.10#aaa.com 10.10.10.11:1111#bbb.com \[1111:2222::3333\]:1234#ccc.com') self.assertRegex(data, r'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org') self.assertRegex(data, r'DOMAINS=hogehoge') self.assertRegex(data, r'ROUTE_DOMAINS=foofoo') @@ -2610,7 +2610,7 @@ class NetworkdStateFileTests(unittest.TestCase, Utilities): self.assertRegex(data, r'DNSSEC=no') self.assertRegex(data, r'ADDRESSES=192.168.(10.10|12.12)/24 192.168.(12.12|10.10)/24') - check_output(*resolvectl_cmd, 'dns', 'dummy98', '10.10.10.12', '10.10.10.13', env=env) + check_output(*resolvectl_cmd, 'dns', 'dummy98', '10.10.10.12#ccc.com', '10.10.10.13', '1111:2222::3333', env=env) check_output(*resolvectl_cmd, 'domain', 'dummy98', 'hogehogehoge', '~foofoofoo', env=env) check_output(*resolvectl_cmd, 'llmnr', 'dummy98', 'yes', env=env) check_output(*resolvectl_cmd, 'mdns', 'dummy98', 'no', env=env) @@ -2620,7 +2620,7 @@ class NetworkdStateFileTests(unittest.TestCase, Utilities): with open(path) as f: data = f.read() - self.assertRegex(data, r'DNS=10.10.10.12 10.10.10.13') + self.assertRegex(data, r'DNS=10.10.10.12#ccc.com 10.10.10.13 1111:2222::3333') self.assertRegex(data, r'NTP=2.fedora.pool.ntp.org 3.fedora.pool.ntp.org') self.assertRegex(data, r'DOMAINS=hogehogehoge') self.assertRegex(data, r'ROUTE_DOMAINS=foofoofoo') @@ -2633,7 +2633,7 @@ class NetworkdStateFileTests(unittest.TestCase, Utilities): with open(path) as f: data = f.read() - self.assertRegex(data, r'DNS=10.10.10.12 10.10.10.13') + self.assertRegex(data, r'DNS=10.10.10.12#ccc.com 10.10.10.13 1111:2222::3333') self.assertRegex(data, r'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org') self.assertRegex(data, r'DOMAINS=hogehogehoge') self.assertRegex(data, r'ROUTE_DOMAINS=foofoofoo') @@ -2646,7 +2646,7 @@ class NetworkdStateFileTests(unittest.TestCase, Utilities): with open(path) as f: data = f.read() - self.assertRegex(data, r'DNS=10.10.10.10 10.10.10.11') + self.assertRegex(data, r'DNS=10.10.10.10#aaa.com 10.10.10.11:1111#bbb.com \[1111:2222::3333\]:1234#ccc.com') self.assertRegex(data, r'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org') self.assertRegex(data, r'DOMAINS=hogehoge') self.assertRegex(data, r'ROUTE_DOMAINS=foofoo') From e293e755d5db821a8c987b93519d612931c969d7 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 19 Jul 2020 10:43:04 +0900 Subject: [PATCH 18/24] util: drop duplicated inclusion of sd-bus.h --- src/shared/bus-get-properties.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/shared/bus-get-properties.h b/src/shared/bus-get-properties.h index d853b79d8d..81af74309d 100644 --- a/src/shared/bus-get-properties.h +++ b/src/shared/bus-get-properties.h @@ -3,8 +3,6 @@ #include "sd-bus.h" -#include "sd-bus.h" - #include "macro.h" int bus_property_get_bool(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error); From 976009897b2aac52d768e035bc9c2d4862c3956a Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 19 Jul 2020 10:57:04 +0900 Subject: [PATCH 19/24] util: introduce helper functions to read in_addr from bus message --- src/shared/bus-message-util.c | 50 +++++++++++++++++++++++++++++++++++ src/shared/bus-message-util.h | 9 +++++++ src/shared/meson.build | 2 ++ 3 files changed, 61 insertions(+) create mode 100644 src/shared/bus-message-util.c create mode 100644 src/shared/bus-message-util.h diff --git a/src/shared/bus-message-util.c b/src/shared/bus-message-util.c new file mode 100644 index 0000000000..2b13001c32 --- /dev/null +++ b/src/shared/bus-message-util.c @@ -0,0 +1,50 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ + +#include "bus-message-util.h" + +int bus_message_read_family(sd_bus_message *message, sd_bus_error *error, int *ret) { + int family, r; + + assert(message); + assert(ret); + + assert_cc(sizeof(int) == sizeof(int32_t)); + + r = sd_bus_message_read(message, "i", &family); + if (r < 0) + return r; + + if (!IN_SET(family, AF_INET, AF_INET6)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family); + + *ret = family; + return 0; +} + +int bus_message_read_in_addr_auto(sd_bus_message *message, sd_bus_error *error, int *ret_family, union in_addr_union *ret_addr) { + int family, r; + const void *d; + size_t sz; + + assert(message); + + r = sd_bus_message_read(message, "i", &family); + if (r < 0) + return r; + + r = sd_bus_message_read_array(message, 'y', &d, &sz); + if (r < 0) + return r; + + if (!IN_SET(family, AF_INET, AF_INET6)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family); + + if (sz != FAMILY_ADDRESS_SIZE(family)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid address size"); + + if (ret_family) + *ret_family = family; + if (ret_addr) + memcpy(ret_addr, d, sz); + return 0; +} diff --git a/src/shared/bus-message-util.h b/src/shared/bus-message-util.h new file mode 100644 index 0000000000..79bef325e3 --- /dev/null +++ b/src/shared/bus-message-util.h @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ +#pragma once + +#include "sd-bus.h" + +#include "in-addr-util.h" + +int bus_message_read_family(sd_bus_message *message, sd_bus_error *error, int *ret); +int bus_message_read_in_addr_auto(sd_bus_message *message, sd_bus_error *error, int *ret_family, union in_addr_union *ret_addr); diff --git a/src/shared/meson.build b/src/shared/meson.build index 1868e8aede..0da733c3fe 100644 --- a/src/shared/meson.build +++ b/src/shared/meson.build @@ -35,6 +35,8 @@ shared_sources = files(''' bus-log-control-api.h bus-map-properties.c bus-map-properties.h + bus-message-util.c + bus-message-util.h bus-object.c bus-object.h bus-polkit.c From 10d4620467bc9b967d5d6446ecf1bd127e1d81f4 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 19 Jul 2020 11:32:18 +0900 Subject: [PATCH 20/24] util: introduce bus_mesage_read_dns_servers() --- src/network/networkd-link-bus.c | 79 ++-------------------- src/resolve/resolved-link-bus.c | 78 ++-------------------- src/shared/bus-message-util.c | 112 ++++++++++++++++++++++++++++++++ src/shared/bus-message-util.h | 8 +++ 4 files changed, 128 insertions(+), 149 deletions(-) diff --git a/src/network/networkd-link-bus.c b/src/network/networkd-link-bus.c index 8b271f9693..be19671505 100644 --- a/src/network/networkd-link-bus.c +++ b/src/network/networkd-link-bus.c @@ -7,6 +7,7 @@ #include "alloc-util.h" #include "bus-common-errors.h" #include "bus-get-properties.h" +#include "bus-message-util.h" #include "bus-polkit.h" #include "dns-domain.h" #include "networkd-link-bus.h" @@ -115,9 +116,9 @@ int bus_link_method_set_ntp_servers(sd_bus_message *message, void *userdata, sd_ } static int bus_link_method_set_dns_servers_internal(sd_bus_message *message, void *userdata, sd_bus_error *error, bool extended) { - struct in_addr_full **dns = NULL; - size_t allocated = 0, n = 0; + struct in_addr_full **dns; Link *l = userdata; + size_t n; int r; assert(message); @@ -127,82 +128,10 @@ static int bus_link_method_set_dns_servers_internal(sd_bus_message *message, voi if (r < 0) return r; - r = sd_bus_message_enter_container(message, 'a', extended ? "(iayqs)" : "(iay)"); + r = bus_message_read_dns_servers(message, error, extended, &dns, &n); if (r < 0) return r; - for (;;) { - const char *server_name = NULL; - union in_addr_union a; - uint16_t port = 0; - const void *d; - int family; - size_t sz; - - assert_cc(sizeof(int) == sizeof(int32_t)); - - r = sd_bus_message_enter_container(message, 'r', extended ? "iayqs" : "iay"); - if (r < 0) - goto finalize; - if (r == 0) - break; - - r = sd_bus_message_read(message, "i", &family); - if (r < 0) - goto finalize; - - if (!IN_SET(family, AF_INET, AF_INET6)) { - r = sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family); - goto finalize; - } - - r = sd_bus_message_read_array(message, 'y', &d, &sz); - if (r < 0) - goto finalize; - if (sz != FAMILY_ADDRESS_SIZE(family)) { - r = sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid address size"); - goto finalize; - } - - if (!dns_server_address_valid(family, d)) { - r = sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid DNS server address"); - goto finalize; - } - - if (extended) { - r = sd_bus_message_read(message, "q", &port); - if (r < 0) - goto finalize; - - if (IN_SET(port, 53, 853)) - port = 0; - - r = sd_bus_message_read(message, "s", &server_name); - if (r < 0) - goto finalize; - } - - r = sd_bus_message_exit_container(message); - if (r < 0) - goto finalize; - - if (!GREEDY_REALLOC(dns, allocated, n+1)) { - r = -ENOMEM; - goto finalize; - } - - memcpy(&a, d, sz); - r = in_addr_full_new(family, &a, port, 0, server_name, dns + n); - if (r < 0) - goto finalize; - - n++; - } - - r = sd_bus_message_exit_container(message); - if (r < 0) - goto finalize; - r = bus_verify_polkit_async(message, CAP_NET_ADMIN, "org.freedesktop.network1.set-dns-servers", NULL, true, UID_INVALID, diff --git a/src/resolve/resolved-link-bus.c b/src/resolve/resolved-link-bus.c index 117f8a378a..42d4ae7aaf 100644 --- a/src/resolve/resolved-link-bus.c +++ b/src/resolve/resolved-link-bus.c @@ -7,6 +7,7 @@ #include "alloc-util.h" #include "bus-common-errors.h" #include "bus-get-properties.h" +#include "bus-message-util.h" #include "bus-polkit.h" #include "parse-util.h" #include "resolve-util.h" @@ -252,9 +253,9 @@ static int verify_unmanaged_link(Link *l, sd_bus_error *error) { } static int bus_link_method_set_dns_servers_internal(sd_bus_message *message, void *userdata, sd_bus_error *error, bool extended) { - struct in_addr_full **dns = NULL; - size_t allocated = 0, n = 0; + struct in_addr_full **dns; Link *l = userdata; + size_t n; int r; assert(message); @@ -264,81 +265,10 @@ static int bus_link_method_set_dns_servers_internal(sd_bus_message *message, voi if (r < 0) return r; - r = sd_bus_message_enter_container(message, 'a', extended ? "(iayqs)" : "(iay)"); + r = bus_message_read_dns_servers(message, error, extended, &dns, &n); if (r < 0) return r; - for (;;) { - const char *server_name = NULL; - union in_addr_union a; - uint16_t port = 0; - const void *d; - int family; - size_t sz; - - assert_cc(sizeof(int) == sizeof(int32_t)); - - r = sd_bus_message_enter_container(message, 'r', extended ? "iayqs" : "iay"); - if (r < 0) - goto finalize; - if (r == 0) - break; - - r = sd_bus_message_read(message, "i", &family); - if (r < 0) - goto finalize; - - if (!IN_SET(family, AF_INET, AF_INET6)) { - r = sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family); - goto finalize; - } - - r = sd_bus_message_read_array(message, 'y', &d, &sz); - if (r < 0) - goto finalize; - if (sz != FAMILY_ADDRESS_SIZE(family)) { - r = sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid address size"); - goto finalize; - } - - if (!dns_server_address_valid(family, d)) { - r = sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid DNS server address"); - goto finalize; - } - - if (extended) { - r = sd_bus_message_read(message, "q", &port); - if (r < 0) - goto finalize; - - if (IN_SET(port, 53, 853)) - port = 0; - - r = sd_bus_message_read(message, "s", &server_name); - if (r < 0) - goto finalize; - } - - r = sd_bus_message_exit_container(message); - if (r < 0) - goto finalize; - - if (!GREEDY_REALLOC(dns, allocated, n+1)) { - r = -ENOMEM; - goto finalize; - } - - memcpy(&a, d, sz); - r = in_addr_full_new(family, &a, port, 0, server_name, dns + n); - if (r < 0) - goto finalize; - n++; - } - - r = sd_bus_message_exit_container(message); - if (r < 0) - goto finalize; - r = bus_verify_polkit_async(message, CAP_NET_ADMIN, "org.freedesktop.resolve1.set-dns-servers", NULL, true, UID_INVALID, diff --git a/src/shared/bus-message-util.c b/src/shared/bus-message-util.c index 2b13001c32..4151b91aec 100644 --- a/src/shared/bus-message-util.c +++ b/src/shared/bus-message-util.c @@ -2,6 +2,8 @@ #include "bus-message-util.h" +#include "resolve-util.h" + int bus_message_read_family(sd_bus_message *message, sd_bus_error *error, int *ret) { int family, r; @@ -48,3 +50,113 @@ int bus_message_read_in_addr_auto(sd_bus_message *message, sd_bus_error *error, memcpy(ret_addr, d, sz); return 0; } + +static int bus_message_read_dns_one( + sd_bus_message *message, + sd_bus_error *error, + bool extended, + int *ret_family, + union in_addr_union *ret_address, + uint16_t *ret_port, + const char **ret_server_name) { + const char *server_name = NULL; + union in_addr_union a; + uint16_t port = 0; + int family, r; + + assert(message); + assert(ret_family); + assert(ret_address); + assert(ret_port); + assert(ret_server_name); + + r = sd_bus_message_enter_container(message, 'r', extended ? "iayqs" : "iay"); + if (r <= 0) + return r; + + r = bus_message_read_in_addr_auto(message, error, &family, &a); + if (r < 0) + return r; + + if (!dns_server_address_valid(family, &a)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid DNS server address"); + + if (extended) { + r = sd_bus_message_read(message, "q", &port); + if (r < 0) + return r; + + if (IN_SET(port, 53, 853)) + port = 0; + + r = sd_bus_message_read(message, "s", &server_name); + if (r < 0) + return r; + } + + r = sd_bus_message_exit_container(message); + if (r < 0) + return r; + + *ret_family = family; + *ret_address = a; + *ret_port = port; + *ret_server_name = server_name; + + return 1; +} + +int bus_message_read_dns_servers( + sd_bus_message *message, + sd_bus_error *error, + bool extended, + struct in_addr_full ***ret_dns, + size_t *ret_n_dns) { + + struct in_addr_full **dns = NULL; + size_t n = 0, allocated = 0; + int r; + + assert(message); + assert(ret_dns); + assert(ret_n_dns); + + r = sd_bus_message_enter_container(message, 'a', extended ? "(iayqs)" : "(iay)"); + if (r < 0) + return r; + + for (;;) { + const char *server_name; + union in_addr_union a; + uint16_t port; + int family; + + r = bus_message_read_dns_one(message, error, extended, &family, &a, &port, &server_name); + if (r < 0) + goto clear; + if (r == 0) + break; + + if (!GREEDY_REALLOC(dns, allocated, n+1)) { + r = -ENOMEM; + goto clear; + } + + r = in_addr_full_new(family, &a, port, 0, server_name, dns + n); + if (r < 0) + goto clear; + + n++; + } + + *ret_dns = TAKE_PTR(dns); + *ret_n_dns = n; + return 0; + +clear: + for (size_t i = 0; i < n; i++) + in_addr_full_free(dns[i]); + free(dns); + + return r; +} diff --git a/src/shared/bus-message-util.h b/src/shared/bus-message-util.h index 79bef325e3..90b78f415f 100644 --- a/src/shared/bus-message-util.h +++ b/src/shared/bus-message-util.h @@ -4,6 +4,14 @@ #include "sd-bus.h" #include "in-addr-util.h" +#include "socket-netlink.h" int bus_message_read_family(sd_bus_message *message, sd_bus_error *error, int *ret); int bus_message_read_in_addr_auto(sd_bus_message *message, sd_bus_error *error, int *ret_family, union in_addr_union *ret_addr); + +int bus_message_read_dns_servers( + sd_bus_message *message, + sd_bus_error *error, + bool extended, + struct in_addr_full ***ret_dns, + size_t *ret_n_dns); From 3dd95ab6c5366bd44f9a146afcab86d0d2a54102 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 19 Jul 2020 12:07:27 +0900 Subject: [PATCH 21/24] util: introduce bus_message_read_ifindex() --- src/shared/bus-message-util.c | 20 ++++++++++++++++++++ src/shared/bus-message-util.h | 1 + 2 files changed, 21 insertions(+) diff --git a/src/shared/bus-message-util.c b/src/shared/bus-message-util.c index 4151b91aec..85e1e98e19 100644 --- a/src/shared/bus-message-util.c +++ b/src/shared/bus-message-util.c @@ -4,6 +4,26 @@ #include "resolve-util.h" +int bus_message_read_ifindex(sd_bus_message *message, sd_bus_error *error, int *ret) { + int ifindex, r; + + assert(message); + assert(ret); + + assert_cc(sizeof(int) == sizeof(int32_t)); + + r = sd_bus_message_read(message, "i", &ifindex); + if (r < 0) + return r; + + if (ifindex <= 0) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface index"); + + *ret = ifindex; + + return 0; +} + int bus_message_read_family(sd_bus_message *message, sd_bus_error *error, int *ret) { int family, r; diff --git a/src/shared/bus-message-util.h b/src/shared/bus-message-util.h index 90b78f415f..98ad035ee4 100644 --- a/src/shared/bus-message-util.h +++ b/src/shared/bus-message-util.h @@ -6,6 +6,7 @@ #include "in-addr-util.h" #include "socket-netlink.h" +int bus_message_read_ifindex(sd_bus_message *message, sd_bus_error *error, int *ret); int bus_message_read_family(sd_bus_message *message, sd_bus_error *error, int *ret); int bus_message_read_in_addr_auto(sd_bus_message *message, sd_bus_error *error, int *ret_family, union in_addr_union *ret_addr); From 7695e2cbbeaa2c931a8cb8c4a752bb959105608e Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 19 Jul 2020 12:32:21 +0900 Subject: [PATCH 22/24] network, resolve: use bus_message_read_ifindex() or friends --- src/network/networkd-manager-bus.c | 16 ++++++---------- src/resolve/resolved-bus.c | 27 ++++++++------------------- 2 files changed, 14 insertions(+), 29 deletions(-) diff --git a/src/network/networkd-manager-bus.c b/src/network/networkd-manager-bus.c index 355a932db2..9db59d93f8 100644 --- a/src/network/networkd-manager-bus.c +++ b/src/network/networkd-manager-bus.c @@ -6,6 +6,7 @@ #include "alloc-util.h" #include "bus-common-errors.h" +#include "bus-message-util.h" #include "bus-polkit.h" #include "networkd-link-bus.h" #include "networkd-link.h" @@ -93,17 +94,16 @@ static int method_get_link_by_index(sd_bus_message *message, void *userdata, sd_ _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; _cleanup_free_ char *path = NULL; Manager *manager = userdata; - int32_t index; + int ifindex, r; Link *link; - int r; - r = sd_bus_message_read(message, "i", &index); + r = bus_message_read_ifindex(message, error, &ifindex); if (r < 0) return r; - link = hashmap_get(manager->links, INT_TO_PTR((int) index)); + link = hashmap_get(manager->links, INT_TO_PTR(ifindex)); if (!link) - return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_LINK, "Link %" PRIi32 " not known", index); + return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_LINK, "Link %i not known", ifindex); r = sd_bus_message_new_method_return(message, &reply); if (r < 0) @@ -128,14 +128,10 @@ static int call_link_method(Manager *m, sd_bus_message *message, sd_bus_message_ assert(message); assert(handler); - assert_cc(sizeof(int) == sizeof(int32_t)); - r = sd_bus_message_read(message, "i", &ifindex); + r = bus_message_read_ifindex(message, error, &ifindex); if (r < 0) return r; - if (ifindex <= 0) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface index"); - l = hashmap_get(m->links, INT_TO_PTR(ifindex)); if (!l) return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_LINK, "Link %i not known", ifindex); diff --git a/src/resolve/resolved-bus.c b/src/resolve/resolved-bus.c index 7d6e883e8b..dba1639a11 100644 --- a/src/resolve/resolved-bus.c +++ b/src/resolve/resolved-bus.c @@ -4,6 +4,7 @@ #include "bus-common-errors.h" #include "bus-get-properties.h" #include "bus-log-control-api.h" +#include "bus-message-util.h" #include "bus-polkit.h" #include "dns-domain.h" #include "memory-util.h" @@ -454,11 +455,10 @@ finish: static int bus_method_resolve_address(sd_bus_message *message, void *userdata, sd_bus_error *error) { _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL; Manager *m = userdata; + union in_addr_union a; int family, ifindex; uint64_t flags; - const void *d; DnsQuery *q; - size_t sz; int r; assert(message); @@ -466,20 +466,14 @@ static int bus_method_resolve_address(sd_bus_message *message, void *userdata, s assert_cc(sizeof(int) == sizeof(int32_t)); - r = sd_bus_message_read(message, "ii", &ifindex, &family); + r = sd_bus_message_read(message, "i", &ifindex); if (r < 0) return r; - if (!IN_SET(family, AF_INET, AF_INET6)) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family); - - r = sd_bus_message_read_array(message, 'y', &d, &sz); + r = bus_message_read_in_addr_auto(message, error, &family, &a); if (r < 0) return r; - if (sz != FAMILY_ADDRESS_SIZE(family)) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid address size"); - r = sd_bus_message_read(message, "t", &flags); if (r < 0) return r; @@ -488,7 +482,7 @@ static int bus_method_resolve_address(sd_bus_message *message, void *userdata, s if (r < 0) return r; - r = dns_question_new_reverse(&question, family, d); + r = dns_question_new_reverse(&question, family, &a); if (r < 0) return r; @@ -498,7 +492,7 @@ static int bus_method_resolve_address(sd_bus_message *message, void *userdata, s q->request = sd_bus_message_ref(message); q->request_family = family; - memcpy(&q->request_address, d, sz); + q->request_address = a; q->complete = bus_method_resolve_address_complete; r = dns_query_bus_track(q, message); @@ -1583,9 +1577,6 @@ static int get_any_link(Manager *m, int ifindex, Link **ret, sd_bus_error *error assert(m); assert(ret); - if (ifindex <= 0) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface index"); - l = hashmap_get(m->links, INT_TO_PTR(ifindex)); if (!l) return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_LINK, "Link %i not known", ifindex); @@ -1602,8 +1593,7 @@ static int call_link_method(Manager *m, sd_bus_message *message, sd_bus_message_ assert(message); assert(handler); - assert_cc(sizeof(int) == sizeof(int32_t)); - r = sd_bus_message_read(message, "i", &ifindex); + r = bus_message_read_ifindex(message, error, &ifindex); if (r < 0) return r; @@ -1663,8 +1653,7 @@ static int bus_method_get_link(sd_bus_message *message, void *userdata, sd_bus_e assert(message); assert(m); - assert_cc(sizeof(int) == sizeof(int32_t)); - r = sd_bus_message_read(message, "i", &ifindex); + r = bus_message_read_ifindex(message, error, &ifindex); if (r < 0) return r; From a574b7d15287e5fee08fc04d788632feefbe8387 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 19 Jul 2020 12:43:39 +0900 Subject: [PATCH 23/24] resolvectl: use bus_message_read_in_addr_auto() --- src/resolve/resolvectl.c | 84 +++++++++++++++------------------------- 1 file changed, 32 insertions(+), 52 deletions(-) diff --git a/src/resolve/resolvectl.c b/src/resolve/resolvectl.c index 46079645ca..476c5e4a3c 100644 --- a/src/resolve/resolvectl.c +++ b/src/resolve/resolvectl.c @@ -13,6 +13,7 @@ #include "bus-error.h" #include "bus-locator.h" #include "bus-map-properties.h" +#include "bus-message-util.h" #include "dns-domain.h" #include "escape.h" #include "format-table.h" @@ -209,34 +210,29 @@ static int resolve_host(sd_bus *bus, const char *name) { while ((r = sd_bus_message_enter_container(reply, 'r', "iiay")) > 0) { _cleanup_free_ char *pretty = NULL; int ifindex, family, k; - const void *a; - size_t sz; + union in_addr_union a; assert_cc(sizeof(int) == sizeof(int32_t)); - r = sd_bus_message_read(reply, "ii", &ifindex, &family); + r = sd_bus_message_read(reply, "i", &ifindex); if (r < 0) return bus_log_parse_error(r); - r = sd_bus_message_read_array(reply, 'y', &a, &sz); - if (r < 0) - return bus_log_parse_error(r); + sd_bus_error_free(&error); + r = bus_message_read_in_addr_auto(reply, &error, &family, &a); + if (r < 0 && !sd_bus_error_has_name(&error, SD_BUS_ERROR_INVALID_ARGS)) + return log_error_errno(r, "%s: systemd-resolved returned invalid result: %s", name, bus_error_message(&error, r)); r = sd_bus_message_exit_container(reply); if (r < 0) return bus_log_parse_error(r); - if (!IN_SET(family, AF_INET, AF_INET6)) { - log_debug("%s: skipping entry with family %d (%s)", name, family, af_to_name(family) ?: "unknown"); + if (sd_bus_error_has_name(&error, SD_BUS_ERROR_INVALID_ARGS)) { + log_debug_errno(r, "%s: systemd-resolved returned invalid result, ignoring: %s", name, bus_error_message(&error, r)); continue; } - if (sz != FAMILY_ADDRESS_SIZE(family)) { - log_error("%s: systemd-resolved returned address of invalid size %zu for family %s", name, sz, af_to_name(family) ?: "unknown"); - return -EINVAL; - } - - r = in_addr_ifindex_to_string(family, a, ifindex, &pretty); + r = in_addr_ifindex_to_string(family, &a, ifindex, &pretty); if (r < 0) return log_error_errno(r, "Failed to print address for %s: %m", name); @@ -740,33 +736,29 @@ static int resolve_service(sd_bus *bus, const char *name, const char *type, cons while ((r = sd_bus_message_enter_container(reply, 'r', "iiay")) > 0) { _cleanup_free_ char *pretty = NULL; int ifindex, family, k; - const void *a; + union in_addr_union a;; assert_cc(sizeof(int) == sizeof(int32_t)); - r = sd_bus_message_read(reply, "ii", &ifindex, &family); + r = sd_bus_message_read(reply, "i", &ifindex); if (r < 0) return bus_log_parse_error(r); - r = sd_bus_message_read_array(reply, 'y', &a, &sz); - if (r < 0) - return bus_log_parse_error(r); + sd_bus_error_free(&error); + r = bus_message_read_in_addr_auto(reply, &error, &family, &a); + if (r < 0 && !sd_bus_error_has_name(&error, SD_BUS_ERROR_INVALID_ARGS)) + return log_error_errno(r, "%s: systemd-resolved returned invalid result: %s", name, bus_error_message(&error, r)); r = sd_bus_message_exit_container(reply); if (r < 0) return bus_log_parse_error(r); - if (!IN_SET(family, AF_INET, AF_INET6)) { - log_debug("%s: skipping entry with family %d (%s)", name, family, af_to_name(family) ?: "unknown"); + if (sd_bus_error_has_name(&error, SD_BUS_ERROR_INVALID_ARGS)) { + log_debug_errno(r, "%s: systemd-resolved returned invalid result, ignoring: %s", name, bus_error_message(&error, r)); continue; } - if (sz != FAMILY_ADDRESS_SIZE(family)) { - log_error("%s: systemd-resolved returned address of invalid size %zu for family %s", name, sz, af_to_name(family) ?: "unknown"); - return -EINVAL; - } - - r = in_addr_ifindex_to_string(family, a, ifindex, &pretty); + r = in_addr_ifindex_to_string(family, &a, ifindex, &pretty); if (r < 0) return log_error_errno(r, "Failed to print address for %s: %m", name); @@ -1121,12 +1113,12 @@ static int reset_server_features(int argc, char **argv, void *userdata) { } static int read_dns_server_one(sd_bus_message *m, bool with_ifindex, bool extended, char **ret) { + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_free_ char *pretty = NULL; - int ifindex, family, r; + int ifindex, family, r, k; + union in_addr_union a; const char *name = NULL; uint16_t port = 0; - const void *a; - size_t sz; assert(m); assert(ret); @@ -1141,13 +1133,9 @@ static int read_dns_server_one(sd_bus_message *m, bool with_ifindex, bool extend return r; } - r = sd_bus_message_read(m, "i", &family); - if (r < 0) - return r; - - r = sd_bus_message_read_array(m, 'y', &a, &sz); - if (r < 0) - return r; + k = bus_message_read_in_addr_auto(m, &error, &family, &a); + if (k < 0 && !sd_bus_error_has_name(&error, SD_BUS_ERROR_INVALID_ARGS)) + return k; if (extended) { r = sd_bus_message_read(m, "q", &port); @@ -1163,27 +1151,19 @@ static int read_dns_server_one(sd_bus_message *m, bool with_ifindex, bool extend if (r < 0) return r; + if (k < 0) { + log_debug("Invalid DNS server, ignoring: %s", bus_error_message(&error, k)); + *ret = NULL; + return 1; + } + if (with_ifindex && ifindex != 0) { /* only show the global ones here */ *ret = NULL; return 1; } - if (!IN_SET(family, AF_INET, AF_INET6)) { - log_debug("Unexpected family, ignoring: %i", family); - - *ret = NULL; - return 1; - } - - if (sz != FAMILY_ADDRESS_SIZE(family)) { - log_debug("Address size mismatch, ignoring."); - - *ret = NULL; - return 1; - } - - r = in_addr_port_ifindex_name_to_string(family, a, port, ifindex, name, &pretty); + r = in_addr_port_ifindex_name_to_string(family, &a, port, ifindex, name, &pretty); if (r < 0) return r; From 711dd5db9e1935a20158727f4a27d12a64ba48e7 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 19 Jul 2020 13:57:51 +0900 Subject: [PATCH 24/24] man: update explanation about the format to specify DNS servers --- man/resolvectl.xml | 23 ++++++++++++++--------- man/resolved.conf.xml | 13 +++++++++---- man/systemd.network.xml | 10 +++++++++- 3 files changed, 32 insertions(+), 14 deletions(-) diff --git a/man/resolvectl.xml b/man/resolvectl.xml index 0ae70dc34b..a4bd8f52d7 100644 --- a/man/resolvectl.xml +++ b/man/resolvectl.xml @@ -145,15 +145,20 @@ settings for network interfaces. These commands may be used to inform systemd-resolved or systemd-networkd about per-interface DNS configuration determined through external means. The dns command expects IPv4 or - IPv6 address specifications of DNS servers to use. The domain command expects - valid DNS domains, possibly prefixed with ~, and configures a per-interface - search or route-only domain. The default-route command expects a boolean - parameter, and configures whether the link may be used as default route for DNS lookups, i.e. if it - is suitable for lookups on domains no other link explicitly is configured for. The - llmnr, mdns, dnssec and - dnsovertls commands may be used to configure the per-interface LLMNR, - MulticastDNS, DNSSEC and DNSOverTLS settings. Finally, nta command may be used - to configure additional per-interface DNSSEC NTA domains. + IPv6 address specifications of DNS servers to use. Each address can optionally take a port number + separated with :, a network interface name or index separated with + %, and a Server Name Indication (SNI) separated with #. When + IPv6 address is specified with a port number, then the address must be in the square brackets. That + is, the acceptable full formats are 111.222.333.444:9953%ifname#example.com for + IPv4 and [1111:2222::3333]:9953%ifname#example.com for IPv6. The + domain command expects valid DNS domains, possibly prefixed with + ~, and configures a per-interface search or route-only domain. The + default-route command expects a boolean parameter, and configures whether the + link may be used as default route for DNS lookups, i.e. if it is suitable for lookups on domains no + other link explicitly is configured for. The llmnr, mdns, + dnssec and dnsovertls commands may be used to configure the + per-interface LLMNR, MulticastDNS, DNSSEC and DNSOverTLS settings. Finally, nta + command may be used to configure additional per-interface DNSSEC NTA domains. Commands dns, domain and nta can take a single empty string argument to clear their respective value lists. diff --git a/man/resolved.conf.xml b/man/resolved.conf.xml index 0e7a9f4bc6..535a23f500 100644 --- a/man/resolved.conf.xml +++ b/man/resolved.conf.xml @@ -47,8 +47,13 @@ DNS= - A space-separated list of IPv4 and IPv6 addresses to use as system DNS servers. DNS requests - are sent to one of the listed DNS servers in parallel to suitable per-link DNS servers acquired from + A space-separated list of IPv4 and IPv6 addresses to use as system DNS servers. Each address can + optionally take a port number separated with :, a network interface name or index separated with + %, and a Server Name Indication (SNI) separated with #. When IPv6 address is + specified with a port number, then the address must be in the square brackets. That is, the acceptable full formats + are 111.222.333.444:9953%ifname#example.com for IPv4 and + [1111:2222::3333]:9953%ifname#example.com for IPv6. DNS requests are sent to one of the listed + DNS servers in parallel to suitable per-link DNS servers acquired from systemd-networkd.service8 or set at runtime by external applications. For compatibility reasons, if this setting is not specified, the DNS servers listed in /etc/resolv.conf are used instead, if that file exists and any servers @@ -57,8 +62,8 @@ FallbackDNS= - A space-separated list of IPv4 and IPv6 addresses to use as the fallback DNS servers. Any - per-link DNS servers obtained from + A space-separated list of IPv4 and IPv6 addresses to use as the fallback DNS servers. Please see + DNS= for acceptable format of adddresses. Any per-link DNS servers obtained from systemd-networkd.service8 take precedence over this setting, as do any servers set via DNS= above or /etc/resolv.conf. This setting is hence only used if no other DNS server information is diff --git a/man/systemd.network.xml b/man/systemd.network.xml index 58d1f2c717..0b0c751e91 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -606,7 +606,15 @@ A DNS server address, which must be in the format described in inet_pton3. - This option may be specified more than once. This setting is read by + This option may be specified more than once. Each address can optionally take a port number + separated with :, a network interface name or index separated with + %, and a Server Name Indication (SNI) separated with #. + When IPv6 address is specified with a port number, then the address must be in the square + brackets. That is, the acceptable full formats are + 111.222.333.444:9953%ifname#example.com for IPv4 and + [1111:2222::3333]:9953%ifname#example.com for IPv6. This setting can be + specified multiple times. If an empty string is assigned, then the all previous assignments + are cleared. This setting is read by systemd-resolved.service8.