]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/resolve/resolved-link-bus.c
resolve: add DBus properties which support DNS SNI and port number
[thirdparty/systemd.git] / src / resolve / resolved-link-bus.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #include <net/if.h>
4 #include <netinet/in.h>
5 #include <sys/capability.h>
6
7 #include "alloc-util.h"
8 #include "bus-common-errors.h"
9 #include "bus-get-properties.h"
10 #include "bus-polkit.h"
11 #include "parse-util.h"
12 #include "resolve-util.h"
13 #include "resolved-bus.h"
14 #include "resolved-link-bus.h"
15 #include "resolved-resolv-conf.h"
16 #include "socket-netlink.h"
17 #include "stdio-util.h"
18 #include "strv.h"
19 #include "user-util.h"
20
21 static BUS_DEFINE_PROPERTY_GET(property_get_dnssec_supported, "b", Link, link_dnssec_supported);
22 static BUS_DEFINE_PROPERTY_GET2(property_get_dnssec_mode, "s", Link, link_get_dnssec_mode, dnssec_mode_to_string);
23
24 static int property_get_dns_over_tls_mode(
25 sd_bus *bus,
26 const char *path,
27 const char *interface,
28 const char *property,
29 sd_bus_message *reply,
30 void *userdata,
31 sd_bus_error *error) {
32
33 Link *l = userdata;
34
35 assert(reply);
36 assert(l);
37
38 return sd_bus_message_append(reply, "s", dns_over_tls_mode_to_string(link_get_dns_over_tls_mode(l)));
39 }
40
41 static int property_get_dns_internal(
42 sd_bus *bus,
43 const char *path,
44 const char *interface,
45 const char *property,
46 sd_bus_message *reply,
47 void *userdata,
48 sd_bus_error *error,
49 bool extended) {
50
51 Link *l = userdata;
52 DnsServer *s;
53 int r;
54
55 assert(reply);
56 assert(l);
57
58 r = sd_bus_message_open_container(reply, 'a', extended ? "(iayqs)" : "(iay)");
59 if (r < 0)
60 return r;
61
62 LIST_FOREACH(servers, s, l->dns_servers) {
63 r = bus_dns_server_append(reply, s, false, extended);
64 if (r < 0)
65 return r;
66 }
67
68 return sd_bus_message_close_container(reply);
69 }
70
71 static int property_get_dns(
72 sd_bus *bus,
73 const char *path,
74 const char *interface,
75 const char *property,
76 sd_bus_message *reply,
77 void *userdata,
78 sd_bus_error *error) {
79 return property_get_dns_internal(bus, path, interface, property, reply, userdata, error, false);
80 }
81
82 static int property_get_dns_ex(
83 sd_bus *bus,
84 const char *path,
85 const char *interface,
86 const char *property,
87 sd_bus_message *reply,
88 void *userdata,
89 sd_bus_error *error) {
90 return property_get_dns_internal(bus, path, interface, property, reply, userdata, error, true);
91 }
92
93 static int property_get_current_dns_server_internal(
94 sd_bus *bus,
95 const char *path,
96 const char *interface,
97 const char *property,
98 sd_bus_message *reply,
99 void *userdata,
100 sd_bus_error *error,
101 bool extended) {
102
103 DnsServer *s;
104
105 assert(reply);
106 assert(userdata);
107
108 s = *(DnsServer **) userdata;
109
110 return bus_dns_server_append(reply, s, false, extended);
111 }
112
113 static int property_get_current_dns_server(
114 sd_bus *bus,
115 const char *path,
116 const char *interface,
117 const char *property,
118 sd_bus_message *reply,
119 void *userdata,
120 sd_bus_error *error) {
121 return property_get_current_dns_server_internal(bus, path, interface, property, reply, userdata, error, false);
122 }
123
124 static int property_get_current_dns_server_ex(
125 sd_bus *bus,
126 const char *path,
127 const char *interface,
128 const char *property,
129 sd_bus_message *reply,
130 void *userdata,
131 sd_bus_error *error) {
132 return property_get_current_dns_server_internal(bus, path, interface, property, reply, userdata, error, true);
133 }
134
135 static int property_get_domains(
136 sd_bus *bus,
137 const char *path,
138 const char *interface,
139 const char *property,
140 sd_bus_message *reply,
141 void *userdata,
142 sd_bus_error *error) {
143
144 Link *l = userdata;
145 DnsSearchDomain *d;
146 int r;
147
148 assert(reply);
149 assert(l);
150
151 r = sd_bus_message_open_container(reply, 'a', "(sb)");
152 if (r < 0)
153 return r;
154
155 LIST_FOREACH(domains, d, l->search_domains) {
156 r = sd_bus_message_append(reply, "(sb)", d->name, d->route_only);
157 if (r < 0)
158 return r;
159 }
160
161 return sd_bus_message_close_container(reply);
162 }
163
164 static int property_get_default_route(
165 sd_bus *bus,
166 const char *path,
167 const char *interface,
168 const char *property,
169 sd_bus_message *reply,
170 void *userdata,
171 sd_bus_error *error) {
172
173 Link *l = userdata;
174
175 assert(reply);
176 assert(l);
177
178 /* Return what is configured, if there's something configured */
179 if (l->default_route >= 0)
180 return sd_bus_message_append(reply, "b", l->default_route);
181
182 /* Otherwise report what is in effect */
183 if (l->unicast_scope)
184 return sd_bus_message_append(reply, "b", dns_scope_is_default_route(l->unicast_scope));
185
186 return sd_bus_message_append(reply, "b", false);
187 }
188
189 static int property_get_scopes_mask(
190 sd_bus *bus,
191 const char *path,
192 const char *interface,
193 const char *property,
194 sd_bus_message *reply,
195 void *userdata,
196 sd_bus_error *error) {
197
198 Link *l = userdata;
199 uint64_t mask;
200
201 assert(reply);
202 assert(l);
203
204 mask = (l->unicast_scope ? SD_RESOLVED_DNS : 0) |
205 (l->llmnr_ipv4_scope ? SD_RESOLVED_LLMNR_IPV4 : 0) |
206 (l->llmnr_ipv6_scope ? SD_RESOLVED_LLMNR_IPV6 : 0) |
207 (l->mdns_ipv4_scope ? SD_RESOLVED_MDNS_IPV4 : 0) |
208 (l->mdns_ipv6_scope ? SD_RESOLVED_MDNS_IPV6 : 0);
209
210 return sd_bus_message_append(reply, "t", mask);
211 }
212
213 static int property_get_ntas(
214 sd_bus *bus,
215 const char *path,
216 const char *interface,
217 const char *property,
218 sd_bus_message *reply,
219 void *userdata,
220 sd_bus_error *error) {
221
222 Link *l = userdata;
223 const char *name;
224 Iterator i;
225 int r;
226
227 assert(reply);
228 assert(l);
229
230 r = sd_bus_message_open_container(reply, 'a', "s");
231 if (r < 0)
232 return r;
233
234 SET_FOREACH(name, l->dnssec_negative_trust_anchors, i) {
235 r = sd_bus_message_append(reply, "s", name);
236 if (r < 0)
237 return r;
238 }
239
240 return sd_bus_message_close_container(reply);
241 }
242
243 static int verify_unmanaged_link(Link *l, sd_bus_error *error) {
244 assert(l);
245
246 if (l->flags & IFF_LOOPBACK)
247 return sd_bus_error_setf(error, BUS_ERROR_LINK_BUSY, "Link %s is loopback device.", l->ifname);
248 if (l->is_managed)
249 return sd_bus_error_setf(error, BUS_ERROR_LINK_BUSY, "Link %s is managed.", l->ifname);
250
251 return 0;
252 }
253
254 static int bus_link_method_set_dns_servers_internal(sd_bus_message *message, void *userdata, sd_bus_error *error, bool extended) {
255 struct in_addr_full **dns = NULL;
256 size_t allocated = 0, n = 0;
257 Link *l = userdata;
258 int r;
259
260 assert(message);
261 assert(l);
262
263 r = verify_unmanaged_link(l, error);
264 if (r < 0)
265 return r;
266
267 r = sd_bus_message_enter_container(message, 'a', extended ? "(iayqs)" : "(iay)");
268 if (r < 0)
269 return r;
270
271 for (;;) {
272 const char *server_name = NULL;
273 union in_addr_union a;
274 uint16_t port = 0;
275 const void *d;
276 int family;
277 size_t sz;
278
279 assert_cc(sizeof(int) == sizeof(int32_t));
280
281 r = sd_bus_message_enter_container(message, 'r', extended ? "iayqs" : "iay");
282 if (r < 0)
283 goto finalize;
284 if (r == 0)
285 break;
286
287 r = sd_bus_message_read(message, "i", &family);
288 if (r < 0)
289 goto finalize;
290
291 if (!IN_SET(family, AF_INET, AF_INET6)) {
292 r = sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family);
293 goto finalize;
294 }
295
296 r = sd_bus_message_read_array(message, 'y', &d, &sz);
297 if (r < 0)
298 goto finalize;
299 if (sz != FAMILY_ADDRESS_SIZE(family)) {
300 r = sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid address size");
301 goto finalize;
302 }
303
304 if (!dns_server_address_valid(family, d)) {
305 r = sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid DNS server address");
306 goto finalize;
307 }
308
309 if (extended) {
310 r = sd_bus_message_read(message, "q", &port);
311 if (r < 0)
312 goto finalize;
313
314 if (IN_SET(port, 53, 853))
315 port = 0;
316
317 r = sd_bus_message_read(message, "s", &server_name);
318 if (r < 0)
319 goto finalize;
320 }
321
322 r = sd_bus_message_exit_container(message);
323 if (r < 0)
324 goto finalize;
325
326 if (!GREEDY_REALLOC(dns, allocated, n+1)) {
327 r = -ENOMEM;
328 goto finalize;
329 }
330
331 memcpy(&a, d, sz);
332 r = in_addr_full_new(family, &a, port, 0, server_name, dns + n);
333 if (r < 0)
334 goto finalize;
335 n++;
336 }
337
338 r = sd_bus_message_exit_container(message);
339 if (r < 0)
340 goto finalize;
341
342 r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
343 "org.freedesktop.resolve1.set-dns-servers",
344 NULL, true, UID_INVALID,
345 &l->manager->polkit_registry, error);
346 if (r < 0)
347 goto finalize;
348 if (r == 0) {
349 r = 1; /* Polkit will call us back */
350 goto finalize;
351 }
352
353 dns_server_mark_all(l->dns_servers);
354
355 for (size_t i = 0; i < n; i++) {
356 DnsServer *s;
357
358 s = dns_server_find(l->dns_servers, dns[i]->family, &dns[i]->address, dns[i]->port, 0, dns[i]->server_name);
359 if (s)
360 dns_server_move_back_and_unmark(s);
361 else {
362 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);
363 if (r < 0) {
364 dns_server_unlink_all(l->dns_servers);
365 goto finalize;
366 }
367 }
368
369 }
370
371 dns_server_unlink_marked(l->dns_servers);
372 link_allocate_scopes(l);
373
374 (void) link_save_user(l);
375 (void) manager_write_resolv_conf(l->manager);
376 (void) manager_send_changed(l->manager, "DNS");
377
378 r = sd_bus_reply_method_return(message, NULL);
379
380 finalize:
381 for (size_t i = 0; i < n; i++)
382 in_addr_full_free(dns[i]);
383 free(dns);
384
385 return r;
386 }
387
388 int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_bus_error *error) {
389 return bus_link_method_set_dns_servers_internal(message, userdata, error, false);
390 }
391
392 int bus_link_method_set_dns_servers_ex(sd_bus_message *message, void *userdata, sd_bus_error *error) {
393 return bus_link_method_set_dns_servers_internal(message, userdata, error, true);
394 }
395
396 int bus_link_method_set_domains(sd_bus_message *message, void *userdata, sd_bus_error *error) {
397 Link *l = userdata;
398 int r;
399
400 assert(message);
401 assert(l);
402
403 r = verify_unmanaged_link(l, error);
404 if (r < 0)
405 return r;
406
407 r = sd_bus_message_enter_container(message, 'a', "(sb)");
408 if (r < 0)
409 return r;
410
411 for (;;) {
412 const char *name;
413 int route_only;
414
415 r = sd_bus_message_read(message, "(sb)", &name, &route_only);
416 if (r < 0)
417 return r;
418 if (r == 0)
419 break;
420
421 r = dns_name_is_valid(name);
422 if (r < 0)
423 return r;
424 if (r == 0)
425 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid search domain %s", name);
426 if (!route_only && dns_name_is_root(name))
427 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Root domain is not suitable as search domain");
428 }
429
430 r = sd_bus_message_rewind(message, false);
431 if (r < 0)
432 return r;
433
434 r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
435 "org.freedesktop.resolve1.set-domains",
436 NULL, true, UID_INVALID,
437 &l->manager->polkit_registry, error);
438 if (r < 0)
439 return r;
440 if (r == 0)
441 return 1; /* Polkit will call us back */
442
443 dns_search_domain_mark_all(l->search_domains);
444
445 for (;;) {
446 DnsSearchDomain *d;
447 const char *name;
448 int route_only;
449
450 r = sd_bus_message_read(message, "(sb)", &name, &route_only);
451 if (r < 0)
452 goto clear;
453 if (r == 0)
454 break;
455
456 r = dns_search_domain_find(l->search_domains, name, &d);
457 if (r < 0)
458 goto clear;
459
460 if (r > 0)
461 dns_search_domain_move_back_and_unmark(d);
462 else {
463 r = dns_search_domain_new(l->manager, &d, DNS_SEARCH_DOMAIN_LINK, l, name);
464 if (r < 0)
465 goto clear;
466 }
467
468 d->route_only = route_only;
469 }
470
471 r = sd_bus_message_exit_container(message);
472 if (r < 0)
473 goto clear;
474
475 dns_search_domain_unlink_marked(l->search_domains);
476
477 (void) link_save_user(l);
478 (void) manager_write_resolv_conf(l->manager);
479
480 return sd_bus_reply_method_return(message, NULL);
481
482 clear:
483 dns_search_domain_unlink_all(l->search_domains);
484 return r;
485 }
486
487 int bus_link_method_set_default_route(sd_bus_message *message, void *userdata, sd_bus_error *error) {
488 Link *l = userdata;
489 int r, b;
490
491 assert(message);
492 assert(l);
493
494 r = verify_unmanaged_link(l, error);
495 if (r < 0)
496 return r;
497
498 r = sd_bus_message_read(message, "b", &b);
499 if (r < 0)
500 return r;
501
502 r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
503 "org.freedesktop.resolve1.set-default-route",
504 NULL, true, UID_INVALID,
505 &l->manager->polkit_registry, error);
506 if (r < 0)
507 return r;
508 if (r == 0)
509 return 1; /* Polkit will call us back */
510
511 if (l->default_route != b) {
512 l->default_route = b;
513
514 (void) link_save_user(l);
515 (void) manager_write_resolv_conf(l->manager);
516 }
517
518 return sd_bus_reply_method_return(message, NULL);
519 }
520
521 int bus_link_method_set_llmnr(sd_bus_message *message, void *userdata, sd_bus_error *error) {
522 Link *l = userdata;
523 ResolveSupport mode;
524 const char *llmnr;
525 int r;
526
527 assert(message);
528 assert(l);
529
530 r = verify_unmanaged_link(l, error);
531 if (r < 0)
532 return r;
533
534 r = sd_bus_message_read(message, "s", &llmnr);
535 if (r < 0)
536 return r;
537
538 if (isempty(llmnr))
539 mode = RESOLVE_SUPPORT_YES;
540 else {
541 mode = resolve_support_from_string(llmnr);
542 if (mode < 0)
543 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid LLMNR setting: %s", llmnr);
544 }
545
546 r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
547 "org.freedesktop.resolve1.set-llmnr",
548 NULL, true, UID_INVALID,
549 &l->manager->polkit_registry, error);
550 if (r < 0)
551 return r;
552 if (r == 0)
553 return 1; /* Polkit will call us back */
554
555 l->llmnr_support = mode;
556 link_allocate_scopes(l);
557 link_add_rrs(l, false);
558
559 (void) link_save_user(l);
560
561 return sd_bus_reply_method_return(message, NULL);
562 }
563
564 int bus_link_method_set_mdns(sd_bus_message *message, void *userdata, sd_bus_error *error) {
565 Link *l = userdata;
566 ResolveSupport mode;
567 const char *mdns;
568 int r;
569
570 assert(message);
571 assert(l);
572
573 r = verify_unmanaged_link(l, error);
574 if (r < 0)
575 return r;
576
577 r = sd_bus_message_read(message, "s", &mdns);
578 if (r < 0)
579 return r;
580
581 if (isempty(mdns))
582 mode = RESOLVE_SUPPORT_NO;
583 else {
584 mode = resolve_support_from_string(mdns);
585 if (mode < 0)
586 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid MulticastDNS setting: %s", mdns);
587 }
588
589 r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
590 "org.freedesktop.resolve1.set-mdns",
591 NULL, true, UID_INVALID,
592 &l->manager->polkit_registry, error);
593 if (r < 0)
594 return r;
595 if (r == 0)
596 return 1; /* Polkit will call us back */
597
598 l->mdns_support = mode;
599 link_allocate_scopes(l);
600 link_add_rrs(l, false);
601
602 (void) link_save_user(l);
603
604 return sd_bus_reply_method_return(message, NULL);
605 }
606
607 int bus_link_method_set_dns_over_tls(sd_bus_message *message, void *userdata, sd_bus_error *error) {
608 Link *l = userdata;
609 const char *dns_over_tls;
610 DnsOverTlsMode mode;
611 int r;
612
613 assert(message);
614 assert(l);
615
616 r = verify_unmanaged_link(l, error);
617 if (r < 0)
618 return r;
619
620 r = sd_bus_message_read(message, "s", &dns_over_tls);
621 if (r < 0)
622 return r;
623
624 if (isempty(dns_over_tls))
625 mode = _DNS_OVER_TLS_MODE_INVALID;
626 else {
627 mode = dns_over_tls_mode_from_string(dns_over_tls);
628 if (mode < 0)
629 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid DNSOverTLS setting: %s", dns_over_tls);
630 }
631
632 r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
633 "org.freedesktop.resolve1.set-dns-over-tls",
634 NULL, true, UID_INVALID,
635 &l->manager->polkit_registry, error);
636 if (r < 0)
637 return r;
638 if (r == 0)
639 return 1; /* Polkit will call us back */
640
641 link_set_dns_over_tls_mode(l, mode);
642
643 (void) link_save_user(l);
644
645 return sd_bus_reply_method_return(message, NULL);
646 }
647
648 int bus_link_method_set_dnssec(sd_bus_message *message, void *userdata, sd_bus_error *error) {
649 Link *l = userdata;
650 const char *dnssec;
651 DnssecMode mode;
652 int r;
653
654 assert(message);
655 assert(l);
656
657 r = verify_unmanaged_link(l, error);
658 if (r < 0)
659 return r;
660
661 r = sd_bus_message_read(message, "s", &dnssec);
662 if (r < 0)
663 return r;
664
665 if (isempty(dnssec))
666 mode = _DNSSEC_MODE_INVALID;
667 else {
668 mode = dnssec_mode_from_string(dnssec);
669 if (mode < 0)
670 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid DNSSEC setting: %s", dnssec);
671 }
672
673 r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
674 "org.freedesktop.resolve1.set-dnssec",
675 NULL, true, UID_INVALID,
676 &l->manager->polkit_registry, error);
677 if (r < 0)
678 return r;
679 if (r == 0)
680 return 1; /* Polkit will call us back */
681
682 link_set_dnssec_mode(l, mode);
683
684 (void) link_save_user(l);
685
686 return sd_bus_reply_method_return(message, NULL);
687 }
688
689 int bus_link_method_set_dnssec_negative_trust_anchors(sd_bus_message *message, void *userdata, sd_bus_error *error) {
690 _cleanup_set_free_free_ Set *ns = NULL;
691 _cleanup_strv_free_ char **ntas = NULL;
692 Link *l = userdata;
693 int r;
694 char **i;
695
696 assert(message);
697 assert(l);
698
699 r = verify_unmanaged_link(l, error);
700 if (r < 0)
701 return r;
702
703 ns = set_new(&dns_name_hash_ops);
704 if (!ns)
705 return -ENOMEM;
706
707 r = sd_bus_message_read_strv(message, &ntas);
708 if (r < 0)
709 return r;
710
711 STRV_FOREACH(i, ntas) {
712 r = dns_name_is_valid(*i);
713 if (r < 0)
714 return r;
715 if (r == 0)
716 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
717 "Invalid negative trust anchor domain: %s", *i);
718
719 r = set_put_strdup(&ns, *i);
720 if (r < 0)
721 return r;
722 }
723
724 r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
725 "org.freedesktop.resolve1.set-dnssec-negative-trust-anchors",
726 NULL, true, UID_INVALID,
727 &l->manager->polkit_registry, error);
728 if (r < 0)
729 return r;
730 if (r == 0)
731 return 1; /* Polkit will call us back */
732
733 set_free_free(l->dnssec_negative_trust_anchors);
734 l->dnssec_negative_trust_anchors = TAKE_PTR(ns);
735
736 (void) link_save_user(l);
737
738 return sd_bus_reply_method_return(message, NULL);
739 }
740
741 int bus_link_method_revert(sd_bus_message *message, void *userdata, sd_bus_error *error) {
742 Link *l = userdata;
743 int r;
744
745 assert(message);
746 assert(l);
747
748 r = verify_unmanaged_link(l, error);
749 if (r < 0)
750 return r;
751
752 r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
753 "org.freedesktop.resolve1.revert",
754 NULL, true, UID_INVALID,
755 &l->manager->polkit_registry, error);
756 if (r < 0)
757 return r;
758 if (r == 0)
759 return 1; /* Polkit will call us back */
760
761 link_flush_settings(l);
762 link_allocate_scopes(l);
763 link_add_rrs(l, false);
764
765 (void) link_save_user(l);
766 (void) manager_write_resolv_conf(l->manager);
767 (void) manager_send_changed(l->manager, "DNS");
768
769 return sd_bus_reply_method_return(message, NULL);
770 }
771
772 static int link_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
773 _cleanup_free_ char *e = NULL;
774 Manager *m = userdata;
775 Link *link;
776 int ifindex, r;
777
778 assert(bus);
779 assert(path);
780 assert(interface);
781 assert(found);
782 assert(m);
783
784 r = sd_bus_path_decode(path, "/org/freedesktop/resolve1/link", &e);
785 if (r <= 0)
786 return 0;
787
788 ifindex = parse_ifindex(e);
789 if (ifindex < 0)
790 return 0;
791
792 link = hashmap_get(m->links, INT_TO_PTR(ifindex));
793 if (!link)
794 return 0;
795
796 *found = link;
797 return 1;
798 }
799
800 char *link_bus_path(const Link *link) {
801 char *p, ifindex[DECIMAL_STR_MAX(link->ifindex)];
802 int r;
803
804 assert(link);
805
806 xsprintf(ifindex, "%i", link->ifindex);
807
808 r = sd_bus_path_encode("/org/freedesktop/resolve1/link", ifindex, &p);
809 if (r < 0)
810 return NULL;
811
812 return p;
813 }
814
815 static int link_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
816 _cleanup_strv_free_ char **l = NULL;
817 Manager *m = userdata;
818 Link *link;
819 Iterator i;
820 unsigned c = 0;
821
822 assert(bus);
823 assert(path);
824 assert(m);
825 assert(nodes);
826
827 l = new0(char*, hashmap_size(m->links) + 1);
828 if (!l)
829 return -ENOMEM;
830
831 HASHMAP_FOREACH(link, m->links, i) {
832 char *p;
833
834 p = link_bus_path(link);
835 if (!p)
836 return -ENOMEM;
837
838 l[c++] = p;
839 }
840
841 l[c] = NULL;
842 *nodes = TAKE_PTR(l);
843
844 return 1;
845 }
846
847 static const sd_bus_vtable link_vtable[] = {
848 SD_BUS_VTABLE_START(0),
849
850 SD_BUS_PROPERTY("ScopesMask", "t", property_get_scopes_mask, 0, 0),
851 SD_BUS_PROPERTY("DNS", "a(iay)", property_get_dns, 0, 0),
852 SD_BUS_PROPERTY("DNSEx", "a(iayqs)", property_get_dns_ex, 0, 0),
853 SD_BUS_PROPERTY("CurrentDNSServer", "(iay)", property_get_current_dns_server, offsetof(Link, current_dns_server), 0),
854 SD_BUS_PROPERTY("CurrentDNSServerEx", "(iayqs)", property_get_current_dns_server_ex, offsetof(Link, current_dns_server), 0),
855 SD_BUS_PROPERTY("Domains", "a(sb)", property_get_domains, 0, 0),
856 SD_BUS_PROPERTY("DefaultRoute", "b", property_get_default_route, 0, 0),
857 SD_BUS_PROPERTY("LLMNR", "s", bus_property_get_resolve_support, offsetof(Link, llmnr_support), 0),
858 SD_BUS_PROPERTY("MulticastDNS", "s", bus_property_get_resolve_support, offsetof(Link, mdns_support), 0),
859 SD_BUS_PROPERTY("DNSOverTLS", "s", property_get_dns_over_tls_mode, 0, 0),
860 SD_BUS_PROPERTY("DNSSEC", "s", property_get_dnssec_mode, 0, 0),
861 SD_BUS_PROPERTY("DNSSECNegativeTrustAnchors", "as", property_get_ntas, 0, 0),
862 SD_BUS_PROPERTY("DNSSECSupported", "b", property_get_dnssec_supported, 0, 0),
863
864 SD_BUS_METHOD_WITH_ARGS("SetDNS",
865 SD_BUS_ARGS("a(iay)", addresses),
866 SD_BUS_NO_RESULT,
867 bus_link_method_set_dns_servers,
868 SD_BUS_VTABLE_UNPRIVILEGED),
869 SD_BUS_METHOD_WITH_ARGS("SetDNSEx",
870 SD_BUS_ARGS("a(iayqs)", addresses),
871 SD_BUS_NO_RESULT,
872 bus_link_method_set_dns_servers_ex,
873 SD_BUS_VTABLE_UNPRIVILEGED),
874 SD_BUS_METHOD_WITH_ARGS("SetDomains",
875 SD_BUS_ARGS("a(sb)", domains),
876 SD_BUS_NO_RESULT,
877 bus_link_method_set_domains,
878 SD_BUS_VTABLE_UNPRIVILEGED),
879 SD_BUS_METHOD_WITH_ARGS("SetDefaultRoute",
880 SD_BUS_ARGS("b", enable),
881 SD_BUS_NO_RESULT,
882 bus_link_method_set_default_route,
883 SD_BUS_VTABLE_UNPRIVILEGED),
884 SD_BUS_METHOD_WITH_ARGS("SetLLMNR",
885 SD_BUS_ARGS("s", mode),
886 SD_BUS_NO_RESULT,
887 bus_link_method_set_llmnr,
888 SD_BUS_VTABLE_UNPRIVILEGED),
889 SD_BUS_METHOD_WITH_ARGS("SetMulticastDNS",
890 SD_BUS_ARGS("s", mode),
891 SD_BUS_NO_RESULT,
892 bus_link_method_set_mdns,
893 SD_BUS_VTABLE_UNPRIVILEGED),
894 SD_BUS_METHOD_WITH_ARGS("SetDNSOverTLS",
895 SD_BUS_ARGS("s", mode),
896 SD_BUS_NO_RESULT,
897 bus_link_method_set_dns_over_tls,
898 SD_BUS_VTABLE_UNPRIVILEGED),
899 SD_BUS_METHOD_WITH_ARGS("SetDNSSEC",
900 SD_BUS_ARGS("s", mode),
901 SD_BUS_NO_RESULT,
902 bus_link_method_set_dnssec,
903 SD_BUS_VTABLE_UNPRIVILEGED),
904 SD_BUS_METHOD_WITH_ARGS("SetDNSSECNegativeTrustAnchors",
905 SD_BUS_ARGS("as", names),
906 SD_BUS_NO_RESULT,
907 bus_link_method_set_dnssec_negative_trust_anchors,
908 SD_BUS_VTABLE_UNPRIVILEGED),
909 SD_BUS_METHOD_WITH_ARGS("Revert",
910 SD_BUS_NO_ARGS,
911 SD_BUS_NO_RESULT,
912 bus_link_method_revert,
913 SD_BUS_VTABLE_UNPRIVILEGED),
914
915 SD_BUS_VTABLE_END
916 };
917
918 const BusObjectImplementation link_object = {
919 "/org/freedesktop/resolve1/link",
920 "org.freedesktop.resolve1.Link",
921 .fallback_vtables = BUS_FALLBACK_VTABLES({link_vtable, link_object_find}),
922 .node_enumerator = link_node_enumerator,
923 };