1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
7 #include "alloc-util.h"
8 #include "bus-common-errors.h"
9 #include "bus-get-properties.h"
10 #include "bus-message-util.h"
11 #include "bus-object.h"
12 #include "bus-polkit.h"
13 #include "dns-domain.h"
15 #include "parse-util.h"
16 #include "resolve-util.h"
17 #include "resolved-bus.h"
18 #include "resolved-def.h"
19 #include "resolved-dns-search-domain.h"
20 #include "resolved-dns-server.h"
21 #include "resolved-link.h"
22 #include "resolved-link-bus.h"
23 #include "resolved-llmnr.h"
24 #include "resolved-manager.h"
25 #include "resolved-mdns.h"
26 #include "resolved-resolv-conf.h"
28 #include "socket-netlink.h"
29 #include "stdio-util.h"
30 #include "string-util.h"
33 static BUS_DEFINE_PROPERTY_GET(property_get_dnssec_supported
, "b", Link
, link_dnssec_supported
);
34 static BUS_DEFINE_PROPERTY_GET2(property_get_dnssec_mode
, "s", Link
, link_get_dnssec_mode
, dnssec_mode_to_string
);
35 static BUS_DEFINE_PROPERTY_GET2(property_get_llmnr_support
, "s", Link
, link_get_llmnr_support
, resolve_support_to_string
);
36 static BUS_DEFINE_PROPERTY_GET2(property_get_mdns_support
, "s", Link
, link_get_mdns_support
, resolve_support_to_string
);
37 static BUS_DEFINE_PROPERTY_GET(property_get_default_route
, "b", Link
, link_get_default_route
);
39 static int property_get_dns_over_tls_mode(
42 const char *interface
,
44 sd_bus_message
*reply
,
46 sd_bus_error
*error
) {
48 Link
*l
= ASSERT_PTR(userdata
);
52 return sd_bus_message_append(reply
, "s", dns_over_tls_mode_to_string(link_get_dns_over_tls_mode(l
)));
55 static int property_get_dns_internal(
58 const char *interface
,
60 sd_bus_message
*reply
,
65 Link
*l
= ASSERT_PTR(userdata
);
70 r
= sd_bus_message_open_container(reply
, 'a', extended
? "(iayqs)" : "(iay)");
74 LIST_FOREACH(servers
, s
, l
->dns_servers
) {
75 r
= bus_dns_server_append(reply
, s
, false, extended
);
80 return sd_bus_message_close_container(reply
);
83 static int property_get_dns(
86 const char *interface
,
88 sd_bus_message
*reply
,
90 sd_bus_error
*error
) {
91 return property_get_dns_internal(bus
, path
, interface
, property
, reply
, userdata
, error
, false);
94 static int property_get_dns_ex(
97 const char *interface
,
99 sd_bus_message
*reply
,
101 sd_bus_error
*error
) {
102 return property_get_dns_internal(bus
, path
, interface
, property
, reply
, userdata
, error
, true);
105 static int property_get_current_dns_server_internal(
108 const char *interface
,
109 const char *property
,
110 sd_bus_message
*reply
,
120 s
= *(DnsServer
**) userdata
;
122 return bus_dns_server_append(reply
, s
, false, extended
);
125 static int property_get_current_dns_server(
128 const char *interface
,
129 const char *property
,
130 sd_bus_message
*reply
,
132 sd_bus_error
*error
) {
133 return property_get_current_dns_server_internal(bus
, path
, interface
, property
, reply
, userdata
, error
, false);
136 static int property_get_current_dns_server_ex(
139 const char *interface
,
140 const char *property
,
141 sd_bus_message
*reply
,
143 sd_bus_error
*error
) {
144 return property_get_current_dns_server_internal(bus
, path
, interface
, property
, reply
, userdata
, error
, true);
147 static int property_get_domains(
150 const char *interface
,
151 const char *property
,
152 sd_bus_message
*reply
,
154 sd_bus_error
*error
) {
156 Link
*l
= ASSERT_PTR(userdata
);
161 r
= sd_bus_message_open_container(reply
, 'a', "(sb)");
165 LIST_FOREACH(domains
, d
, l
->search_domains
) {
166 r
= sd_bus_message_append(reply
, "(sb)", d
->name
, d
->route_only
);
171 return sd_bus_message_close_container(reply
);
174 static int property_get_scopes_mask(
177 const char *interface
,
178 const char *property
,
179 sd_bus_message
*reply
,
181 sd_bus_error
*error
) {
183 Link
*l
= ASSERT_PTR(userdata
);
188 mask
= (l
->unicast_scope
? SD_RESOLVED_DNS
: 0) |
189 (l
->llmnr_ipv4_scope
? SD_RESOLVED_LLMNR_IPV4
: 0) |
190 (l
->llmnr_ipv6_scope
? SD_RESOLVED_LLMNR_IPV6
: 0) |
191 (l
->mdns_ipv4_scope
? SD_RESOLVED_MDNS_IPV4
: 0) |
192 (l
->mdns_ipv6_scope
? SD_RESOLVED_MDNS_IPV6
: 0);
194 return sd_bus_message_append(reply
, "t", mask
);
197 static int verify_unmanaged_link(Link
*l
, sd_bus_error
*error
) {
200 if (l
->flags
& IFF_LOOPBACK
)
201 return sd_bus_error_setf(error
, BUS_ERROR_LINK_BUSY
, "Link %s is loopback device.", l
->ifname
);
203 return sd_bus_error_setf(error
, BUS_ERROR_LINK_BUSY
, "Link %s is managed.", l
->ifname
);
208 static int bus_link_method_set_dns_servers_internal(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
, bool extended
) {
209 _cleanup_free_
char *j
= NULL
;
210 struct in_addr_full
**dns
;
211 bool changed
= false;
212 Link
*l
= ASSERT_PTR(userdata
);
218 r
= verify_unmanaged_link(l
, error
);
222 r
= bus_message_read_dns_servers(message
, error
, extended
, &dns
, &n
);
226 r
= bus_verify_polkit_async(
228 "org.freedesktop.resolve1.set-dns-servers",
229 (const char**) STRV_MAKE("interface", l
->ifname
),
230 &l
->manager
->polkit_registry
, error
);
234 r
= 1; /* Polkit will call us back */
238 for (size_t i
= 0; i
< n
; i
++) {
241 s
= in_addr_full_to_string(dns
[i
]);
247 if (!strextend_with_separator(&j
, ", ", s
)) {
253 bus_client_log(message
, "DNS server change");
255 dns_server_mark_all(l
->dns_servers
);
257 for (size_t i
= 0; i
< n
; i
++) {
260 s
= dns_server_find(l
->dns_servers
, dns
[i
]->family
, &dns
[i
]->address
, dns
[i
]->port
, 0, dns
[i
]->server_name
);
262 dns_server_move_back_and_unmark(s
);
264 r
= dns_server_new(l
->manager
, NULL
, DNS_SERVER_LINK
, l
, /* delegate= */ NULL
, dns
[i
]->family
, &dns
[i
]->address
, dns
[i
]->port
, 0, dns
[i
]->server_name
, RESOLVE_CONFIG_SOURCE_DBUS
);
266 dns_server_unlink_all(l
->dns_servers
);
274 changed
= dns_server_unlink_marked(l
->dns_servers
) || changed
;
277 link_allocate_scopes(l
);
279 (void) link_save_user(l
);
280 (void) manager_write_resolv_conf(l
->manager
);
281 (void) manager_send_changed(l
->manager
, "DNS");
282 (void) manager_send_dns_configuration_changed(l
->manager
, l
, /* reset= */ true);
285 log_link_info(l
, "Bus client set DNS server list to: %s", j
);
287 log_link_info(l
, "Bus client reset DNS server list.");
290 r
= sd_bus_reply_method_return(message
, NULL
);
293 for (size_t i
= 0; i
< n
; i
++)
294 in_addr_full_free(dns
[i
]);
300 int bus_link_method_set_dns_servers(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
301 return bus_link_method_set_dns_servers_internal(message
, userdata
, error
, false);
304 int bus_link_method_set_dns_servers_ex(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
305 return bus_link_method_set_dns_servers_internal(message
, userdata
, error
, true);
308 int bus_link_method_set_domains(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
309 _cleanup_free_
char *j
= NULL
;
310 Link
*l
= ASSERT_PTR(userdata
);
311 bool changed
= false;
316 r
= verify_unmanaged_link(l
, error
);
320 r
= sd_bus_message_enter_container(message
, 'a', "(sb)");
325 _cleanup_free_
char *prefixed
= NULL
;
329 r
= sd_bus_message_read(message
, "(sb)", &name
, &route_only
);
335 r
= dns_name_is_valid(name
);
339 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid search domain %s", name
);
340 if (!route_only
&& dns_name_is_root(name
))
341 return sd_bus_error_set(error
, SD_BUS_ERROR_INVALID_ARGS
, "Root domain is not suitable as search domain");
344 prefixed
= strjoin("~", name
);
351 if (!strextend_with_separator(&j
, ", ", name
))
355 r
= sd_bus_message_rewind(message
, false);
359 r
= bus_verify_polkit_async(
361 "org.freedesktop.resolve1.set-domains",
362 (const char**) STRV_MAKE("interface", l
->ifname
),
363 &l
->manager
->polkit_registry
,
368 return 1; /* Polkit will call us back */
370 bus_client_log(message
, "dns domains change");
372 dns_search_domain_mark_all(l
->search_domains
);
379 r
= sd_bus_message_read(message
, "(sb)", &name
, &route_only
);
385 r
= dns_search_domain_find(l
->search_domains
, name
, &d
);
390 dns_search_domain_move_back_and_unmark(d
);
392 r
= dns_search_domain_new(l
->manager
, &d
, DNS_SEARCH_DOMAIN_LINK
, l
, /* delegate= */ NULL
, name
);
399 d
->route_only
= route_only
;
402 r
= sd_bus_message_exit_container(message
);
406 changed
= dns_search_domain_unlink_marked(l
->search_domains
) || changed
;
409 (void) link_save_user(l
);
410 (void) manager_write_resolv_conf(l
->manager
);
413 log_link_info(l
, "Bus client set search domain list to: %s", j
);
415 log_link_info(l
, "Bus client reset search domain list.");
418 return sd_bus_reply_method_return(message
, NULL
);
421 dns_search_domain_unlink_all(l
->search_domains
);
425 int bus_link_method_set_default_route(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
426 Link
*l
= ASSERT_PTR(userdata
);
431 r
= verify_unmanaged_link(l
, error
);
435 r
= sd_bus_message_read(message
, "b", &b
);
439 r
= bus_verify_polkit_async(
441 "org.freedesktop.resolve1.set-default-route",
442 (const char**) STRV_MAKE("interface", l
->ifname
),
443 &l
->manager
->polkit_registry
,
448 return 1; /* Polkit will call us back */
450 bus_client_log(message
, "dns default route change");
452 if (l
->default_route
!= b
) {
453 link_set_default_route(l
, b
);
454 (void) link_save_user(l
);
455 (void) manager_write_resolv_conf(l
->manager
);
457 log_link_info(l
, "Bus client set default route setting: %s", yes_no(b
));
460 return sd_bus_reply_method_return(message
, NULL
);
463 int bus_link_method_set_llmnr(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
464 Link
*l
= ASSERT_PTR(userdata
);
471 r
= verify_unmanaged_link(l
, error
);
475 r
= sd_bus_message_read(message
, "s", &llmnr
);
480 mode
= RESOLVE_SUPPORT_YES
;
482 mode
= resolve_support_from_string(llmnr
);
484 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid LLMNR setting: %s", llmnr
);
487 r
= bus_verify_polkit_async(
489 "org.freedesktop.resolve1.set-llmnr",
490 (const char**) STRV_MAKE("interface", l
->ifname
),
491 &l
->manager
->polkit_registry
,
496 return 1; /* Polkit will call us back */
498 bus_client_log(message
, "LLMNR change");
500 if (l
->llmnr_support
!= mode
) {
501 l
->llmnr_support
= mode
;
502 link_allocate_scopes(l
);
503 link_add_rrs(l
, false);
505 (void) link_save_user(l
);
507 manager_llmnr_maybe_stop(l
->manager
);
509 log_link_info(l
, "Bus client set LLMNR setting: %s", resolve_support_to_string(mode
));
512 return sd_bus_reply_method_return(message
, NULL
);
515 int bus_link_method_set_mdns(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
516 Link
*l
= ASSERT_PTR(userdata
);
523 r
= verify_unmanaged_link(l
, error
);
527 r
= sd_bus_message_read(message
, "s", &mdns
);
532 mode
= RESOLVE_SUPPORT_YES
;
534 mode
= resolve_support_from_string(mdns
);
536 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid MulticastDNS setting: %s", mdns
);
539 r
= bus_verify_polkit_async(
541 "org.freedesktop.resolve1.set-mdns",
542 (const char**) STRV_MAKE("interface", l
->ifname
),
543 &l
->manager
->polkit_registry
,
548 return 1; /* Polkit will call us back */
550 bus_client_log(message
, "mDNS change");
552 if (l
->mdns_support
!= mode
) {
553 l
->mdns_support
= mode
;
554 link_allocate_scopes(l
);
555 link_add_rrs(l
, false);
557 (void) link_save_user(l
);
559 manager_mdns_maybe_stop(l
->manager
);
561 log_link_info(l
, "Bus client set MulticastDNS setting: %s", resolve_support_to_string(mode
));
564 return sd_bus_reply_method_return(message
, NULL
);
567 int bus_link_method_set_dns_over_tls(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
568 Link
*l
= ASSERT_PTR(userdata
);
569 const char *dns_over_tls
;
575 r
= verify_unmanaged_link(l
, error
);
579 r
= sd_bus_message_read(message
, "s", &dns_over_tls
);
583 if (isempty(dns_over_tls
))
584 mode
= _DNS_OVER_TLS_MODE_INVALID
;
586 mode
= dns_over_tls_mode_from_string(dns_over_tls
);
588 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid DNSOverTLS setting: %s", dns_over_tls
);
591 r
= bus_verify_polkit_async(
593 "org.freedesktop.resolve1.set-dns-over-tls",
594 (const char**) STRV_MAKE("interface", l
->ifname
),
595 &l
->manager
->polkit_registry
,
600 return 1; /* Polkit will call us back */
602 bus_client_log(message
, "D-o-T change");
604 if (l
->dns_over_tls_mode
!= mode
) {
605 link_set_dns_over_tls_mode(l
, mode
);
606 link_allocate_scopes(l
);
608 (void) link_save_user(l
);
610 log_link_info(l
, "Bus client set DNSOverTLS setting: %s",
611 mode
< 0 ? "default" : dns_over_tls_mode_to_string(mode
));
614 return sd_bus_reply_method_return(message
, NULL
);
617 int bus_link_method_set_dnssec(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
618 Link
*l
= ASSERT_PTR(userdata
);
625 r
= verify_unmanaged_link(l
, error
);
629 r
= sd_bus_message_read(message
, "s", &dnssec
);
634 mode
= _DNSSEC_MODE_INVALID
;
636 mode
= dnssec_mode_from_string(dnssec
);
638 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid DNSSEC setting: %s", dnssec
);
641 r
= bus_verify_polkit_async(
643 "org.freedesktop.resolve1.set-dnssec",
644 (const char**) STRV_MAKE("interface", l
->ifname
),
645 &l
->manager
->polkit_registry
,
650 return 1; /* Polkit will call us back */
652 bus_client_log(message
, "DNSSEC change");
654 if (l
->dnssec_mode
!= mode
) {
655 link_set_dnssec_mode(l
, mode
);
656 link_allocate_scopes(l
);
658 (void) link_save_user(l
);
660 log_link_info(l
, "Bus client set DNSSEC setting: %s",
661 mode
< 0 ? "default" : dnssec_mode_to_string(mode
));
664 return sd_bus_reply_method_return(message
, NULL
);
667 int bus_link_method_set_dnssec_negative_trust_anchors(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
668 _cleanup_set_free_ Set
*ns
= NULL
;
669 _cleanup_strv_free_
char **ntas
= NULL
;
670 _cleanup_free_
char *j
= NULL
;
671 Link
*l
= ASSERT_PTR(userdata
);
676 r
= verify_unmanaged_link(l
, error
);
680 r
= sd_bus_message_read_strv(message
, &ntas
);
684 STRV_FOREACH(i
, ntas
) {
685 r
= dns_name_is_valid(*i
);
689 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
,
690 "Invalid negative trust anchor domain: %s", *i
);
692 r
= set_put_strdup_full(&ns
, &dns_name_hash_ops_free
, *i
);
696 if (!strextend_with_separator(&j
, ", ", *i
))
700 r
= bus_verify_polkit_async(
702 "org.freedesktop.resolve1.set-dnssec-negative-trust-anchors",
703 (const char**) STRV_MAKE("interface", l
->ifname
),
704 &l
->manager
->polkit_registry
,
709 return 1; /* Polkit will call us back */
711 bus_client_log(message
, "DNSSEC NTA change");
713 if (!set_equal(ns
, l
->dnssec_negative_trust_anchors
)) {
714 set_free_and_replace(l
->dnssec_negative_trust_anchors
, ns
);
716 (void) link_save_user(l
);
719 log_link_info(l
, "Bus client set NTA list to: %s", j
);
721 log_link_info(l
, "Bus client reset NTA list.");
724 return sd_bus_reply_method_return(message
, NULL
);
727 int bus_link_method_revert(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
728 Link
*l
= ASSERT_PTR(userdata
);
733 r
= verify_unmanaged_link(l
, error
);
737 r
= bus_verify_polkit_async(
739 "org.freedesktop.resolve1.revert",
740 (const char**) STRV_MAKE("interface", l
->ifname
),
741 &l
->manager
->polkit_registry
,
746 return 1; /* Polkit will call us back */
748 bus_client_log(message
, "revert");
750 link_flush_settings(l
);
751 link_allocate_scopes(l
);
752 link_add_rrs(l
, false);
754 (void) link_save_user(l
);
755 (void) manager_write_resolv_conf(l
->manager
);
756 (void) manager_send_changed(l
->manager
, "DNS");
757 (void) manager_send_dns_configuration_changed(l
->manager
, l
, /* reset= */ true);
759 manager_llmnr_maybe_stop(l
->manager
);
760 manager_mdns_maybe_stop(l
->manager
);
762 return sd_bus_reply_method_return(message
, NULL
);
765 static int link_object_find(sd_bus
*bus
, const char *path
, const char *interface
, void *userdata
, void **found
, sd_bus_error
*error
) {
766 _cleanup_free_
char *e
= NULL
;
767 Manager
*m
= ASSERT_PTR(userdata
);
776 r
= sd_bus_path_decode(path
, "/org/freedesktop/resolve1/link", &e
);
780 ifindex
= parse_ifindex(e
);
784 link
= hashmap_get(m
->links
, INT_TO_PTR(ifindex
));
792 char* link_bus_path(const Link
*link
) {
793 char *p
, ifindex
[DECIMAL_STR_MAX(link
->ifindex
)];
798 xsprintf(ifindex
, "%i", link
->ifindex
);
800 r
= sd_bus_path_encode("/org/freedesktop/resolve1/link", ifindex
, &p
);
807 static int link_node_enumerator(sd_bus
*bus
, const char *path
, void *userdata
, char ***nodes
, sd_bus_error
*error
) {
808 _cleanup_strv_free_
char **l
= NULL
;
809 Manager
*m
= ASSERT_PTR(userdata
);
817 l
= new0(char*, hashmap_size(m
->links
) + 1);
821 HASHMAP_FOREACH(link
, m
->links
) {
824 p
= link_bus_path(link
);
832 *nodes
= TAKE_PTR(l
);
837 static const sd_bus_vtable link_vtable
[] = {
838 SD_BUS_VTABLE_START(0),
840 SD_BUS_PROPERTY("ScopesMask", "t", property_get_scopes_mask
, 0, 0),
841 SD_BUS_PROPERTY("DNS", "a(iay)", property_get_dns
, 0, 0),
842 SD_BUS_PROPERTY("DNSEx", "a(iayqs)", property_get_dns_ex
, 0, 0),
843 SD_BUS_PROPERTY("CurrentDNSServer", "(iay)", property_get_current_dns_server
, offsetof(Link
, current_dns_server
), 0),
844 SD_BUS_PROPERTY("CurrentDNSServerEx", "(iayqs)", property_get_current_dns_server_ex
, offsetof(Link
, current_dns_server
), 0),
845 SD_BUS_PROPERTY("Domains", "a(sb)", property_get_domains
, 0, 0),
846 SD_BUS_PROPERTY("DefaultRoute", "b", property_get_default_route
, 0, 0),
847 SD_BUS_PROPERTY("LLMNR", "s", property_get_llmnr_support
, 0, 0),
848 SD_BUS_PROPERTY("MulticastDNS", "s", property_get_mdns_support
, 0, 0),
849 SD_BUS_PROPERTY("DNSOverTLS", "s", property_get_dns_over_tls_mode
, 0, 0),
850 SD_BUS_PROPERTY("DNSSEC", "s", property_get_dnssec_mode
, 0, 0),
851 SD_BUS_PROPERTY("DNSSECNegativeTrustAnchors", "as", bus_property_get_string_set
, offsetof(Link
, dnssec_negative_trust_anchors
), 0),
852 SD_BUS_PROPERTY("DNSSECSupported", "b", property_get_dnssec_supported
, 0, 0),
854 SD_BUS_METHOD_WITH_ARGS("SetDNS",
855 SD_BUS_ARGS("a(iay)", addresses
),
857 bus_link_method_set_dns_servers
,
858 SD_BUS_VTABLE_UNPRIVILEGED
),
859 SD_BUS_METHOD_WITH_ARGS("SetDNSEx",
860 SD_BUS_ARGS("a(iayqs)", addresses
),
862 bus_link_method_set_dns_servers_ex
,
863 SD_BUS_VTABLE_UNPRIVILEGED
),
864 SD_BUS_METHOD_WITH_ARGS("SetDomains",
865 SD_BUS_ARGS("a(sb)", domains
),
867 bus_link_method_set_domains
,
868 SD_BUS_VTABLE_UNPRIVILEGED
),
869 SD_BUS_METHOD_WITH_ARGS("SetDefaultRoute",
870 SD_BUS_ARGS("b", enable
),
872 bus_link_method_set_default_route
,
873 SD_BUS_VTABLE_UNPRIVILEGED
),
874 SD_BUS_METHOD_WITH_ARGS("SetLLMNR",
875 SD_BUS_ARGS("s", mode
),
877 bus_link_method_set_llmnr
,
878 SD_BUS_VTABLE_UNPRIVILEGED
),
879 SD_BUS_METHOD_WITH_ARGS("SetMulticastDNS",
880 SD_BUS_ARGS("s", mode
),
882 bus_link_method_set_mdns
,
883 SD_BUS_VTABLE_UNPRIVILEGED
),
884 SD_BUS_METHOD_WITH_ARGS("SetDNSOverTLS",
885 SD_BUS_ARGS("s", mode
),
887 bus_link_method_set_dns_over_tls
,
888 SD_BUS_VTABLE_UNPRIVILEGED
),
889 SD_BUS_METHOD_WITH_ARGS("SetDNSSEC",
890 SD_BUS_ARGS("s", mode
),
892 bus_link_method_set_dnssec
,
893 SD_BUS_VTABLE_UNPRIVILEGED
),
894 SD_BUS_METHOD_WITH_ARGS("SetDNSSECNegativeTrustAnchors",
895 SD_BUS_ARGS("as", names
),
897 bus_link_method_set_dnssec_negative_trust_anchors
,
898 SD_BUS_VTABLE_UNPRIVILEGED
),
899 SD_BUS_METHOD_WITH_ARGS("Revert",
902 bus_link_method_revert
,
903 SD_BUS_VTABLE_UNPRIVILEGED
),
908 const BusObjectImplementation link_object
= {
909 "/org/freedesktop/resolve1/link",
910 "org.freedesktop.resolve1.Link",
911 .fallback_vtables
= BUS_FALLBACK_VTABLES({link_vtable
, link_object_find
}),
912 .node_enumerator
= link_node_enumerator
,