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