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', "(sb)");
82 LIST_FOREACH(domains
, d
, l
->search_domains
) {
83 r
= sd_bus_message_append(reply
, "(sb)", d
->name
, d
->route_only
);
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 static int property_get_dnssec_supported(
148 const char *interface
,
149 const char *property
,
150 sd_bus_message
*reply
,
152 sd_bus_error
*error
) {
159 return sd_bus_message_append(reply
, "b", link_dnssec_supported(l
));
162 int bus_link_method_set_dns_servers(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
163 _cleanup_free_
struct in_addr_data
*dns
= NULL
;
164 size_t allocated
= 0, n
= 0;
172 r
= sd_bus_message_enter_container(message
, 'a', "(iay)");
181 assert_cc(sizeof(int) == sizeof(int32_t));
183 r
= sd_bus_message_enter_container(message
, 'r', "iay");
189 r
= sd_bus_message_read(message
, "i", &family
);
193 if (!IN_SET(family
, AF_INET
, AF_INET6
))
194 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Unknown address family %i", family
);
196 r
= sd_bus_message_read_array(message
, 'y', &d
, &sz
);
199 if (sz
!= FAMILY_ADDRESS_SIZE(family
))
200 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid address size");
202 r
= sd_bus_message_exit_container(message
);
206 if (!GREEDY_REALLOC(dns
, allocated
, n
+1))
209 dns
[n
].family
= family
;
210 memcpy(&dns
[n
].address
, d
, sz
);
214 r
= sd_bus_message_exit_container(message
);
218 dns_server_mark_all(l
->dns_servers
);
220 for (i
= 0; i
< n
; i
++) {
223 s
= dns_server_find(l
->dns_servers
, dns
[i
].family
, &dns
[i
].address
);
225 dns_server_move_back_and_unmark(s
);
227 r
= dns_server_new(l
->manager
, NULL
, DNS_SERVER_LINK
, l
, dns
[i
].family
, &dns
[i
].address
);
234 dns_server_unlink_marked(l
->dns_servers
);
235 link_allocate_scopes(l
);
237 return sd_bus_reply_method_return(message
, NULL
);
240 dns_server_unlink_all(l
->dns_servers
);
244 int bus_link_method_set_search_domains(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
251 r
= sd_bus_message_enter_container(message
, 'a', "(sb)");
259 r
= sd_bus_message_read(message
, "(sb)", &name
, &route_only
);
265 r
= dns_name_is_valid(name
);
269 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid search domain %s", name
);
270 if (!route_only
&& dns_name_is_root(name
))
271 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Root domain is not suitable as search domain");
274 dns_search_domain_mark_all(l
->search_domains
);
276 r
= sd_bus_message_rewind(message
, false);
285 r
= sd_bus_message_read(message
, "(sb)", &name
, &route_only
);
291 r
= dns_search_domain_find(l
->search_domains
, name
, &d
);
296 dns_search_domain_move_back_and_unmark(d
);
298 r
= dns_search_domain_new(l
->manager
, &d
, DNS_SEARCH_DOMAIN_LINK
, l
, name
);
303 d
->route_only
= route_only
;
306 r
= sd_bus_message_exit_container(message
);
310 dns_search_domain_unlink_marked(l
->search_domains
);
311 return sd_bus_reply_method_return(message
, NULL
);
314 dns_search_domain_unlink_all(l
->search_domains
);
318 int bus_link_method_set_llmnr(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
327 r
= sd_bus_message_read(message
, "s", &llmnr
);
332 mode
= RESOLVE_SUPPORT_YES
;
334 mode
= resolve_support_from_string(llmnr
);
336 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid LLMNR setting: %s", llmnr
);
339 l
->llmnr_support
= mode
;
340 link_allocate_scopes(l
);
341 link_add_rrs(l
, false);
343 return sd_bus_reply_method_return(message
, NULL
);
346 int bus_link_method_set_mdns(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
355 r
= sd_bus_message_read(message
, "s", &mdns
);
360 mode
= RESOLVE_SUPPORT_NO
;
362 mode
= resolve_support_from_string(mdns
);
364 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid MulticastDNS setting: %s", mdns
);
367 l
->mdns_support
= mode
;
368 link_allocate_scopes(l
);
369 link_add_rrs(l
, false);
371 return sd_bus_reply_method_return(message
, NULL
);
374 int bus_link_method_set_dnssec(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
383 r
= sd_bus_message_read(message
, "s", &dnssec
);
388 mode
= _DNSSEC_MODE_INVALID
;
390 mode
= dnssec_mode_from_string(dnssec
);
392 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid DNSSEC setting: %s", dnssec
);
395 link_set_dnssec_mode(l
, mode
);
397 return sd_bus_reply_method_return(message
, NULL
);
400 int bus_link_method_set_dnssec_negative_trust_anchors(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
401 _cleanup_set_free_free_ Set
*ns
= NULL
;
402 _cleanup_free_
char **ntas
= NULL
;
410 r
= sd_bus_message_read_strv(message
, &ntas
);
414 STRV_FOREACH(i
, ntas
) {
415 r
= dns_name_is_valid(*i
);
419 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid negative trust anchor domain: %s", *i
);
422 ns
= set_new(&dns_name_hash_ops
);
426 STRV_FOREACH(i
, ntas
) {
427 r
= set_put_strdup(ns
, *i
);
432 set_free_free(l
->dnssec_negative_trust_anchors
);
433 l
->dnssec_negative_trust_anchors
= ns
;
436 return sd_bus_reply_method_return(message
, NULL
);
439 int bus_link_method_revert(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
445 link_flush_settings(l
);
446 link_allocate_scopes(l
);
447 link_add_rrs(l
, false);
449 return sd_bus_reply_method_return(message
, NULL
);
452 const sd_bus_vtable link_vtable
[] = {
453 SD_BUS_VTABLE_START(0),
455 SD_BUS_PROPERTY("ScopesMask", "t", property_get_scopes_mask
, 0, 0),
456 SD_BUS_PROPERTY("DNS", "a(iay)", property_get_dns
, 0, 0),
457 SD_BUS_PROPERTY("Domains", "a(sb)", property_get_domains
, 0, 0),
458 SD_BUS_PROPERTY("LLMNR", "s", property_get_resolve_support
, offsetof(Link
, llmnr_support
), 0),
459 SD_BUS_PROPERTY("MulticastDNS", "s", property_get_resolve_support
, offsetof(Link
, mdns_support
), 0),
460 SD_BUS_PROPERTY("DNSSEC", "s", property_get_dnssec_mode
, offsetof(Link
, dnssec_mode
), 0),
461 SD_BUS_PROPERTY("DNSSECNegativeTrustAnchors", "as", property_get_ntas
, 0, 0),
462 SD_BUS_PROPERTY("DNSSECSupport", "b", property_get_dnssec_supported
, 0, 0),
464 SD_BUS_METHOD("SetDNS", "a(iay)", NULL
, bus_link_method_set_dns_servers
, 0),
465 SD_BUS_METHOD("SetDomains", "a(sb)", NULL
, bus_link_method_set_search_domains
, 0),
466 SD_BUS_METHOD("SetLLMNR", "s", NULL
, bus_link_method_set_llmnr
, 0),
467 SD_BUS_METHOD("SetMulticastDNS", "s", NULL
, bus_link_method_set_mdns
, 0),
468 SD_BUS_METHOD("SetDNSSEC", "s", NULL
, bus_link_method_set_dnssec
, 0),
469 SD_BUS_METHOD("SetDNSSECNegativeTrustAnchors", "as", NULL
, bus_link_method_set_dnssec_negative_trust_anchors
, 0),
470 SD_BUS_METHOD("Revert", NULL
, NULL
, bus_link_method_revert
, 0),
475 int link_object_find(sd_bus
*bus
, const char *path
, const char *interface
, void *userdata
, void **found
, sd_bus_error
*error
) {
476 _cleanup_free_
char *e
= NULL
;
477 Manager
*m
= userdata
;
488 r
= sd_bus_path_decode(path
, "/org/freedesktop/resolve1/link", &e
);
492 r
= parse_ifindex(e
, &ifindex
);
496 link
= hashmap_get(m
->links
, INT_TO_PTR(ifindex
));
504 char *link_bus_path(Link
*link
) {
505 _cleanup_free_
char *ifindex
= NULL
;
511 if (asprintf(&ifindex
, "%i", link
->ifindex
) < 0)
514 r
= sd_bus_path_encode("/org/freedesktop/resolve1/link", ifindex
, &p
);
521 int link_node_enumerator(sd_bus
*bus
, const char *path
, void *userdata
, char ***nodes
, sd_bus_error
*error
) {
522 _cleanup_strv_free_
char **l
= NULL
;
523 Manager
*m
= userdata
;
533 l
= new0(char*, hashmap_size(m
->links
) + 1);
537 HASHMAP_FOREACH(link
, m
->links
, i
) {
540 p
= link_bus_path(link
);