1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2016 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 #include "alloc-util.h"
24 #include "parse-util.h"
25 #include "resolve-util.h"
26 #include "resolved-bus.h"
27 #include "resolved-link-bus.h"
30 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_resolve_support
, resolve_support
, ResolveSupport
);
31 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_dnssec_mode
, dnssec_mode
, DnssecMode
);
33 static int property_get_dns(
36 const char *interface
,
38 sd_bus_message
*reply
,
40 sd_bus_error
*error
) {
49 r
= sd_bus_message_open_container(reply
, 'a', "(iay)");
53 LIST_FOREACH(servers
, s
, l
->dns_servers
) {
54 r
= bus_dns_server_append(reply
, s
, false);
59 return sd_bus_message_close_container(reply
);
62 static int property_get_domains(
65 const char *interface
,
67 sd_bus_message
*reply
,
69 sd_bus_error
*error
) {
78 r
= sd_bus_message_open_container(reply
, 'a', "s");
82 LIST_FOREACH(domains
, d
, l
->search_domains
) {
83 r
= sd_bus_message_append(reply
, "s", d
->name
);
88 return sd_bus_message_close_container(reply
);
91 static int property_get_scopes_mask(
94 const char *interface
,
96 sd_bus_message
*reply
,
98 sd_bus_error
*error
) {
106 mask
= (l
->unicast_scope
? SD_RESOLVED_DNS
: 0) |
107 (l
->llmnr_ipv4_scope
? SD_RESOLVED_LLMNR_IPV4
: 0) |
108 (l
->llmnr_ipv6_scope
? SD_RESOLVED_LLMNR_IPV6
: 0) |
109 (l
->mdns_ipv4_scope
? SD_RESOLVED_MDNS_IPV4
: 0) |
110 (l
->mdns_ipv6_scope
? SD_RESOLVED_MDNS_IPV6
: 0);
112 return sd_bus_message_append(reply
, "t", mask
);
115 static int property_get_ntas(
118 const char *interface
,
119 const char *property
,
120 sd_bus_message
*reply
,
122 sd_bus_error
*error
) {
132 r
= sd_bus_message_open_container(reply
, 'a', "s");
136 SET_FOREACH(name
, l
->dnssec_negative_trust_anchors
, i
) {
137 r
= sd_bus_message_append(reply
, "s", name
);
142 return sd_bus_message_close_container(reply
);
145 int bus_link_method_set_dns_servers(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
146 _cleanup_free_
struct in_addr_data
*dns
= NULL
;
147 size_t allocated
= 0, n
= 0;
155 r
= sd_bus_message_enter_container(message
, 'a', "(iay)");
164 assert_cc(sizeof(int) == sizeof(int32_t));
166 r
= sd_bus_message_enter_container(message
, 'r', "iay");
172 r
= sd_bus_message_read(message
, "i", &family
);
176 if (!IN_SET(family
, AF_INET
, AF_INET6
))
177 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Unknown address family %i", family
);
179 r
= sd_bus_message_read_array(message
, 'y', &d
, &sz
);
182 if (sz
!= FAMILY_ADDRESS_SIZE(family
))
183 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid address size");
185 r
= sd_bus_message_exit_container(message
);
189 if (!GREEDY_REALLOC(dns
, allocated
, n
+1))
192 dns
[n
].family
= family
;
193 memcpy(&dns
[n
].address
, d
, sz
);
197 r
= sd_bus_message_exit_container(message
);
201 dns_server_mark_all(l
->dns_servers
);
203 for (i
= 0; i
< n
; i
++) {
206 s
= dns_server_find(l
->dns_servers
, dns
[i
].family
, &dns
[i
].address
);
208 dns_server_move_back_and_unmark(s
);
210 r
= dns_server_new(l
->manager
, NULL
, DNS_SERVER_LINK
, l
, dns
[i
].family
, &dns
[i
].address
);
217 dns_server_unlink_marked(l
->dns_servers
);
218 link_allocate_scopes(l
);
220 return sd_bus_reply_method_return(message
, NULL
);
223 dns_server_unlink_all(l
->dns_servers
);
227 int bus_link_method_set_search_domains(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
228 _cleanup_free_
char **domains
= NULL
;
236 r
= sd_bus_message_read_strv(message
, &domains
);
240 STRV_FOREACH(i
, domains
) {
242 r
= dns_name_is_valid(*i
);
246 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid search domain %s", *i
);
247 if (dns_name_is_root(*i
))
248 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Root domain is not suitable as search domain");
251 dns_search_domain_mark_all(l
->search_domains
);
253 STRV_FOREACH(i
, domains
) {
256 r
= dns_search_domain_find(l
->search_domains
, *i
, &d
);
261 dns_search_domain_move_back_and_unmark(d
);
263 r
= dns_search_domain_new(l
->manager
, NULL
, DNS_SEARCH_DOMAIN_LINK
, l
, *i
);
269 dns_search_domain_unlink_marked(l
->search_domains
);
270 return sd_bus_reply_method_return(message
, NULL
);
273 dns_search_domain_unlink_all(l
->search_domains
);
277 int bus_link_method_set_llmnr(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
286 r
= sd_bus_message_read(message
, "s", &llmnr
);
291 mode
= RESOLVE_SUPPORT_YES
;
293 mode
= resolve_support_from_string(llmnr
);
295 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid LLMNR setting: %s", llmnr
);
298 l
->llmnr_support
= mode
;
299 link_allocate_scopes(l
);
300 link_add_rrs(l
, false);
302 return sd_bus_reply_method_return(message
, NULL
);
305 int bus_link_method_set_mdns(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
314 r
= sd_bus_message_read(message
, "s", &mdns
);
319 mode
= RESOLVE_SUPPORT_NO
;
321 mode
= resolve_support_from_string(mdns
);
323 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid MulticastDNS setting: %s", mdns
);
326 l
->mdns_support
= mode
;
327 link_allocate_scopes(l
);
328 link_add_rrs(l
, false);
330 return sd_bus_reply_method_return(message
, NULL
);
333 int bus_link_method_set_dnssec(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
342 r
= sd_bus_message_read(message
, "s", &dnssec
);
347 mode
= _DNSSEC_MODE_INVALID
;
349 mode
= dnssec_mode_from_string(dnssec
);
351 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid DNSSEC setting: %s", dnssec
);
354 link_set_dnssec_mode(l
, mode
);
356 return sd_bus_reply_method_return(message
, NULL
);
359 int bus_link_method_set_dnssec_negative_trust_anchors(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
360 _cleanup_set_free_free_ Set
*ns
= NULL
;
361 _cleanup_free_
char **ntas
= NULL
;
369 r
= sd_bus_message_read_strv(message
, &ntas
);
373 STRV_FOREACH(i
, ntas
) {
374 r
= dns_name_is_valid(*i
);
378 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid search negative trust anchor domain: %s", *i
);
381 ns
= set_new(&dns_name_hash_ops
);
385 STRV_FOREACH(i
, ntas
) {
386 r
= set_put_strdup(ns
, *i
);
391 set_free_free(l
->dnssec_negative_trust_anchors
);
392 l
->dnssec_negative_trust_anchors
= ns
;
395 return sd_bus_reply_method_return(message
, NULL
);
398 int bus_link_method_revert(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
404 link_flush_settings(l
);
405 link_allocate_scopes(l
);
406 link_add_rrs(l
, false);
408 return sd_bus_reply_method_return(message
, NULL
);
411 const sd_bus_vtable link_vtable
[] = {
412 SD_BUS_VTABLE_START(0),
414 SD_BUS_PROPERTY("ScopesMask", "t", property_get_scopes_mask
, 0, 0),
415 SD_BUS_PROPERTY("DNS", "a(iay)", property_get_dns
, 0, 0),
416 SD_BUS_PROPERTY("Domains", "as", property_get_domains
, 0, 0),
417 SD_BUS_PROPERTY("LLMNR", "s", property_get_resolve_support
, offsetof(Link
, llmnr_support
), 0),
418 SD_BUS_PROPERTY("MulticastDNS", "s", property_get_resolve_support
, offsetof(Link
, mdns_support
), 0),
419 SD_BUS_PROPERTY("DNSSEC", "s", property_get_dnssec_mode
, offsetof(Link
, dnssec_mode
), 0),
420 SD_BUS_PROPERTY("DNSSECNegativeTrustAnchors", "as", property_get_ntas
, 0, 0),
422 SD_BUS_METHOD("SetDNS", "a(iay)", NULL
, bus_link_method_set_dns_servers
, 0),
423 SD_BUS_METHOD("SetDomains", "as", NULL
, bus_link_method_set_search_domains
, 0),
424 SD_BUS_METHOD("SetLLMNR", "s", NULL
, bus_link_method_set_llmnr
, 0),
425 SD_BUS_METHOD("SetMulticastDNS", "s", NULL
, bus_link_method_set_mdns
, 0),
426 SD_BUS_METHOD("SetDNSSEC", "s", NULL
, bus_link_method_set_dnssec
, 0),
427 SD_BUS_METHOD("SetDNSSECNegativeTrustAnchors", "as", NULL
, bus_link_method_set_dnssec_negative_trust_anchors
, 0),
428 SD_BUS_METHOD("Revert", NULL
, NULL
, bus_link_method_revert
, 0),
433 int link_object_find(sd_bus
*bus
, const char *path
, const char *interface
, void *userdata
, void **found
, sd_bus_error
*error
) {
434 _cleanup_free_
char *e
= NULL
;
435 Manager
*m
= userdata
;
446 r
= sd_bus_path_decode(path
, "/org/freedesktop/resolve1/link", &e
);
450 r
= parse_ifindex(e
, &ifindex
);
454 link
= hashmap_get(m
->links
, INT_TO_PTR(ifindex
));
462 char *link_bus_path(Link
*link
) {
463 _cleanup_free_
char *ifindex
= NULL
;
469 if (asprintf(&ifindex
, "%i", link
->ifindex
) < 0)
472 r
= sd_bus_path_encode("/org/freedesktop/resolve1/link", ifindex
, &p
);
479 int link_node_enumerator(sd_bus
*bus
, const char *path
, void *userdata
, char ***nodes
, sd_bus_error
*error
) {
480 _cleanup_strv_free_
char **l
= NULL
;
481 Manager
*m
= userdata
;
491 l
= new0(char*, hashmap_size(m
->links
) + 1);
495 HASHMAP_FOREACH(link
, m
->links
, i
) {
498 p
= link_bus_path(link
);