1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2016 Lennart Poettering
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
21 #include "alloc-util.h"
22 #include "bus-common-errors.h"
24 #include "parse-util.h"
25 #include "resolve-util.h"
26 #include "resolved-bus.h"
27 #include "resolved-link-bus.h"
28 #include "resolved-resolv-conf.h"
31 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_resolve_support
, resolve_support
, ResolveSupport
);
33 static int property_get_dnssec_mode(
36 const char *interface
,
38 sd_bus_message
*reply
,
40 sd_bus_error
*error
) {
47 return sd_bus_message_append(reply
, "s", dnssec_mode_to_string(link_get_dnssec_mode(l
)));
50 static int property_get_dns(
53 const char *interface
,
55 sd_bus_message
*reply
,
57 sd_bus_error
*error
) {
66 r
= sd_bus_message_open_container(reply
, 'a', "(iay)");
70 LIST_FOREACH(servers
, s
, l
->dns_servers
) {
71 r
= bus_dns_server_append(reply
, s
, false);
76 return sd_bus_message_close_container(reply
);
79 static int property_get_domains(
82 const char *interface
,
84 sd_bus_message
*reply
,
86 sd_bus_error
*error
) {
95 r
= sd_bus_message_open_container(reply
, 'a', "(sb)");
99 LIST_FOREACH(domains
, d
, l
->search_domains
) {
100 r
= sd_bus_message_append(reply
, "(sb)", d
->name
, d
->route_only
);
105 return sd_bus_message_close_container(reply
);
108 static int property_get_scopes_mask(
111 const char *interface
,
112 const char *property
,
113 sd_bus_message
*reply
,
115 sd_bus_error
*error
) {
123 mask
= (l
->unicast_scope
? SD_RESOLVED_DNS
: 0) |
124 (l
->llmnr_ipv4_scope
? SD_RESOLVED_LLMNR_IPV4
: 0) |
125 (l
->llmnr_ipv6_scope
? SD_RESOLVED_LLMNR_IPV6
: 0) |
126 (l
->mdns_ipv4_scope
? SD_RESOLVED_MDNS_IPV4
: 0) |
127 (l
->mdns_ipv6_scope
? SD_RESOLVED_MDNS_IPV6
: 0);
129 return sd_bus_message_append(reply
, "t", mask
);
132 static int property_get_ntas(
135 const char *interface
,
136 const char *property
,
137 sd_bus_message
*reply
,
139 sd_bus_error
*error
) {
149 r
= sd_bus_message_open_container(reply
, 'a', "s");
153 SET_FOREACH(name
, l
->dnssec_negative_trust_anchors
, i
) {
154 r
= sd_bus_message_append(reply
, "s", name
);
159 return sd_bus_message_close_container(reply
);
162 static int property_get_dnssec_supported(
165 const char *interface
,
166 const char *property
,
167 sd_bus_message
*reply
,
169 sd_bus_error
*error
) {
176 return sd_bus_message_append(reply
, "b", link_dnssec_supported(l
));
179 static int verify_unmanaged_link(Link
*l
, sd_bus_error
*error
) {
182 if (l
->flags
& IFF_LOOPBACK
)
183 return sd_bus_error_setf(error
, BUS_ERROR_LINK_BUSY
, "Link %s is loopback device.", l
->name
);
185 return sd_bus_error_setf(error
, BUS_ERROR_LINK_BUSY
, "Link %s is managed.", l
->name
);
190 int bus_link_method_set_dns_servers(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
191 _cleanup_free_
struct in_addr_data
*dns
= NULL
;
192 size_t allocated
= 0, n
= 0;
200 r
= verify_unmanaged_link(l
, error
);
204 r
= sd_bus_message_enter_container(message
, 'a', "(iay)");
213 assert_cc(sizeof(int) == sizeof(int32_t));
215 r
= sd_bus_message_enter_container(message
, 'r', "iay");
221 r
= sd_bus_message_read(message
, "i", &family
);
225 if (!IN_SET(family
, AF_INET
, AF_INET6
))
226 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Unknown address family %i", family
);
228 r
= sd_bus_message_read_array(message
, 'y', &d
, &sz
);
231 if (sz
!= FAMILY_ADDRESS_SIZE(family
))
232 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid address size");
234 if (!dns_server_address_valid(family
, d
))
235 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid DNS server address");
237 r
= sd_bus_message_exit_container(message
);
241 if (!GREEDY_REALLOC(dns
, allocated
, n
+1))
244 dns
[n
].family
= family
;
245 memcpy(&dns
[n
].address
, d
, sz
);
249 r
= sd_bus_message_exit_container(message
);
253 dns_server_mark_all(l
->dns_servers
);
255 for (i
= 0; i
< n
; i
++) {
258 s
= dns_server_find(l
->dns_servers
, dns
[i
].family
, &dns
[i
].address
, 0);
260 dns_server_move_back_and_unmark(s
);
262 r
= dns_server_new(l
->manager
, NULL
, DNS_SERVER_LINK
, l
, dns
[i
].family
, &dns
[i
].address
, 0);
269 dns_server_unlink_marked(l
->dns_servers
);
270 link_allocate_scopes(l
);
272 (void) link_save_user(l
);
273 (void) manager_write_resolv_conf(l
->manager
);
275 return sd_bus_reply_method_return(message
, NULL
);
278 dns_server_unlink_all(l
->dns_servers
);
282 int bus_link_method_set_domains(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
289 r
= verify_unmanaged_link(l
, error
);
293 r
= sd_bus_message_enter_container(message
, 'a', "(sb)");
301 r
= sd_bus_message_read(message
, "(sb)", &name
, &route_only
);
307 r
= dns_name_is_valid(name
);
311 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid search domain %s", name
);
312 if (!route_only
&& dns_name_is_root(name
))
313 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Root domain is not suitable as search domain");
316 dns_search_domain_mark_all(l
->search_domains
);
318 r
= sd_bus_message_rewind(message
, false);
327 r
= sd_bus_message_read(message
, "(sb)", &name
, &route_only
);
333 r
= dns_search_domain_find(l
->search_domains
, name
, &d
);
338 dns_search_domain_move_back_and_unmark(d
);
340 r
= dns_search_domain_new(l
->manager
, &d
, DNS_SEARCH_DOMAIN_LINK
, l
, name
);
345 d
->route_only
= route_only
;
348 r
= sd_bus_message_exit_container(message
);
352 dns_search_domain_unlink_marked(l
->search_domains
);
354 (void) link_save_user(l
);
355 (void) manager_write_resolv_conf(l
->manager
);
357 return sd_bus_reply_method_return(message
, NULL
);
360 dns_search_domain_unlink_all(l
->search_domains
);
364 int bus_link_method_set_llmnr(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
373 r
= verify_unmanaged_link(l
, error
);
377 r
= sd_bus_message_read(message
, "s", &llmnr
);
382 mode
= RESOLVE_SUPPORT_YES
;
384 mode
= resolve_support_from_string(llmnr
);
386 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid LLMNR setting: %s", llmnr
);
389 l
->llmnr_support
= mode
;
390 link_allocate_scopes(l
);
391 link_add_rrs(l
, false);
393 (void) link_save_user(l
);
395 return sd_bus_reply_method_return(message
, NULL
);
398 int bus_link_method_set_mdns(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
407 r
= verify_unmanaged_link(l
, error
);
411 r
= sd_bus_message_read(message
, "s", &mdns
);
416 mode
= RESOLVE_SUPPORT_NO
;
418 mode
= resolve_support_from_string(mdns
);
420 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid MulticastDNS setting: %s", mdns
);
423 l
->mdns_support
= mode
;
424 link_allocate_scopes(l
);
425 link_add_rrs(l
, false);
427 (void) link_save_user(l
);
429 return sd_bus_reply_method_return(message
, NULL
);
432 int bus_link_method_set_dnssec(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
441 r
= verify_unmanaged_link(l
, error
);
445 r
= sd_bus_message_read(message
, "s", &dnssec
);
450 mode
= _DNSSEC_MODE_INVALID
;
452 mode
= dnssec_mode_from_string(dnssec
);
454 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid DNSSEC setting: %s", dnssec
);
457 link_set_dnssec_mode(l
, mode
);
459 (void) link_save_user(l
);
461 return sd_bus_reply_method_return(message
, NULL
);
464 int bus_link_method_set_dnssec_negative_trust_anchors(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
465 _cleanup_set_free_free_ Set
*ns
= NULL
;
466 _cleanup_strv_free_
char **ntas
= NULL
;
474 r
= verify_unmanaged_link(l
, error
);
478 r
= sd_bus_message_read_strv(message
, &ntas
);
482 STRV_FOREACH(i
, ntas
) {
483 r
= dns_name_is_valid(*i
);
487 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid negative trust anchor domain: %s", *i
);
490 ns
= set_new(&dns_name_hash_ops
);
494 STRV_FOREACH(i
, ntas
) {
495 r
= set_put_strdup(ns
, *i
);
500 set_free_free(l
->dnssec_negative_trust_anchors
);
501 l
->dnssec_negative_trust_anchors
= ns
;
504 (void) link_save_user(l
);
506 return sd_bus_reply_method_return(message
, NULL
);
509 int bus_link_method_revert(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
516 r
= verify_unmanaged_link(l
, error
);
520 link_flush_settings(l
);
521 link_allocate_scopes(l
);
522 link_add_rrs(l
, false);
524 (void) link_save_user(l
);
525 (void) manager_write_resolv_conf(l
->manager
);
527 return sd_bus_reply_method_return(message
, NULL
);
530 const sd_bus_vtable link_vtable
[] = {
531 SD_BUS_VTABLE_START(0),
533 SD_BUS_PROPERTY("ScopesMask", "t", property_get_scopes_mask
, 0, 0),
534 SD_BUS_PROPERTY("DNS", "a(iay)", property_get_dns
, 0, 0),
535 SD_BUS_PROPERTY("Domains", "a(sb)", property_get_domains
, 0, 0),
536 SD_BUS_PROPERTY("LLMNR", "s", property_get_resolve_support
, offsetof(Link
, llmnr_support
), 0),
537 SD_BUS_PROPERTY("MulticastDNS", "s", property_get_resolve_support
, offsetof(Link
, mdns_support
), 0),
538 SD_BUS_PROPERTY("DNSSEC", "s", property_get_dnssec_mode
, 0, 0),
539 SD_BUS_PROPERTY("DNSSECNegativeTrustAnchors", "as", property_get_ntas
, 0, 0),
540 SD_BUS_PROPERTY("DNSSECSupported", "b", property_get_dnssec_supported
, 0, 0),
542 SD_BUS_METHOD("SetDNS", "a(iay)", NULL
, bus_link_method_set_dns_servers
, 0),
543 SD_BUS_METHOD("SetDomains", "a(sb)", NULL
, bus_link_method_set_domains
, 0),
544 SD_BUS_METHOD("SetLLMNR", "s", NULL
, bus_link_method_set_llmnr
, 0),
545 SD_BUS_METHOD("SetMulticastDNS", "s", NULL
, bus_link_method_set_mdns
, 0),
546 SD_BUS_METHOD("SetDNSSEC", "s", NULL
, bus_link_method_set_dnssec
, 0),
547 SD_BUS_METHOD("SetDNSSECNegativeTrustAnchors", "as", NULL
, bus_link_method_set_dnssec_negative_trust_anchors
, 0),
548 SD_BUS_METHOD("Revert", NULL
, NULL
, bus_link_method_revert
, 0),
553 int link_object_find(sd_bus
*bus
, const char *path
, const char *interface
, void *userdata
, void **found
, sd_bus_error
*error
) {
554 _cleanup_free_
char *e
= NULL
;
555 Manager
*m
= userdata
;
566 r
= sd_bus_path_decode(path
, "/org/freedesktop/resolve1/link", &e
);
570 r
= parse_ifindex(e
, &ifindex
);
574 link
= hashmap_get(m
->links
, INT_TO_PTR(ifindex
));
582 char *link_bus_path(Link
*link
) {
583 _cleanup_free_
char *ifindex
= NULL
;
589 if (asprintf(&ifindex
, "%i", link
->ifindex
) < 0)
592 r
= sd_bus_path_encode("/org/freedesktop/resolve1/link", ifindex
, &p
);
599 int link_node_enumerator(sd_bus
*bus
, const char *path
, void *userdata
, char ***nodes
, sd_bus_error
*error
) {
600 _cleanup_strv_free_
char **l
= NULL
;
601 Manager
*m
= userdata
;
611 l
= new0(char*, hashmap_size(m
->links
) + 1);
615 HASHMAP_FOREACH(link
, m
->links
, i
) {
618 p
= link_bus_path(link
);