]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-link-bus.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / resolve / resolved-link-bus.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
3abaabda
LP
2/***
3 This file is part of systemd.
4
5 Copyright 2016 Lennart Poettering
6
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.
11
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.
16
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/>.
19***/
20
21#include "alloc-util.h"
04b764bf 22#include "bus-common-errors.h"
3abaabda
LP
23#include "bus-util.h"
24#include "parse-util.h"
25#include "resolve-util.h"
26#include "resolved-bus.h"
27#include "resolved-link-bus.h"
7207052d 28#include "resolved-resolv-conf.h"
3abaabda
LP
29#include "strv.h"
30
31static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_resolve_support, resolve_support, ResolveSupport);
a3712979
LP
32
33static int property_get_dnssec_mode(
34 sd_bus *bus,
35 const char *path,
36 const char *interface,
37 const char *property,
38 sd_bus_message *reply,
39 void *userdata,
40 sd_bus_error *error) {
41
42 Link *l = userdata;
43
44 assert(reply);
45 assert(l);
46
47 return sd_bus_message_append(reply, "s", dnssec_mode_to_string(link_get_dnssec_mode(l)));
48}
3abaabda
LP
49
50static int property_get_dns(
51 sd_bus *bus,
52 const char *path,
53 const char *interface,
54 const char *property,
55 sd_bus_message *reply,
56 void *userdata,
57 sd_bus_error *error) {
58
59 Link *l = userdata;
60 DnsServer *s;
61 int r;
62
63 assert(reply);
64 assert(l);
65
66 r = sd_bus_message_open_container(reply, 'a', "(iay)");
67 if (r < 0)
68 return r;
69
70 LIST_FOREACH(servers, s, l->dns_servers) {
71 r = bus_dns_server_append(reply, s, false);
72 if (r < 0)
73 return r;
74 }
75
76 return sd_bus_message_close_container(reply);
77}
78
79static int property_get_domains(
80 sd_bus *bus,
81 const char *path,
82 const char *interface,
83 const char *property,
84 sd_bus_message *reply,
85 void *userdata,
86 sd_bus_error *error) {
87
88 Link *l = userdata;
89 DnsSearchDomain *d;
90 int r;
91
92 assert(reply);
93 assert(l);
94
ad44b56b 95 r = sd_bus_message_open_container(reply, 'a', "(sb)");
3abaabda
LP
96 if (r < 0)
97 return r;
98
99 LIST_FOREACH(domains, d, l->search_domains) {
ad44b56b 100 r = sd_bus_message_append(reply, "(sb)", d->name, d->route_only);
3abaabda
LP
101 if (r < 0)
102 return r;
103 }
104
105 return sd_bus_message_close_container(reply);
106}
107
108static int property_get_scopes_mask(
109 sd_bus *bus,
110 const char *path,
111 const char *interface,
112 const char *property,
113 sd_bus_message *reply,
114 void *userdata,
115 sd_bus_error *error) {
116
117 Link *l = userdata;
118 uint64_t mask;
119
120 assert(reply);
121 assert(l);
122
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);
128
129 return sd_bus_message_append(reply, "t", mask);
130}
131
132static int property_get_ntas(
133 sd_bus *bus,
134 const char *path,
135 const char *interface,
136 const char *property,
137 sd_bus_message *reply,
138 void *userdata,
139 sd_bus_error *error) {
140
141 Link *l = userdata;
142 const char *name;
143 Iterator i;
144 int r;
145
146 assert(reply);
147 assert(l);
148
149 r = sd_bus_message_open_container(reply, 'a', "s");
150 if (r < 0)
151 return r;
152
153 SET_FOREACH(name, l->dnssec_negative_trust_anchors, i) {
154 r = sd_bus_message_append(reply, "s", name);
155 if (r < 0)
156 return r;
157 }
158
159 return sd_bus_message_close_container(reply);
160}
161
c69fa7e3
LP
162static int property_get_dnssec_supported(
163 sd_bus *bus,
164 const char *path,
165 const char *interface,
166 const char *property,
167 sd_bus_message *reply,
168 void *userdata,
169 sd_bus_error *error) {
170
171 Link *l = userdata;
172
173 assert(reply);
174 assert(l);
175
176 return sd_bus_message_append(reply, "b", link_dnssec_supported(l));
177}
178
04b764bf
LP
179static int verify_unmanaged_link(Link *l, sd_bus_error *error) {
180 assert(l);
181
182 if (l->flags & IFF_LOOPBACK)
183 return sd_bus_error_setf(error, BUS_ERROR_LINK_BUSY, "Link %s is loopback device.", l->name);
184 if (l->is_managed)
185 return sd_bus_error_setf(error, BUS_ERROR_LINK_BUSY, "Link %s is managed.", l->name);
186
187 return 0;
188}
189
d2ec6608
LP
190int 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;
193 Link *l = userdata;
194 unsigned i;
195 int r;
196
197 assert(message);
198 assert(l);
199
04b764bf
LP
200 r = verify_unmanaged_link(l, error);
201 if (r < 0)
202 return r;
203
d2ec6608
LP
204 r = sd_bus_message_enter_container(message, 'a', "(iay)");
205 if (r < 0)
206 return r;
207
208 for (;;) {
209 int family;
210 size_t sz;
211 const void *d;
212
213 assert_cc(sizeof(int) == sizeof(int32_t));
214
215 r = sd_bus_message_enter_container(message, 'r', "iay");
216 if (r < 0)
217 return r;
218 if (r == 0)
219 break;
220
221 r = sd_bus_message_read(message, "i", &family);
222 if (r < 0)
223 return r;
224
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);
227
228 r = sd_bus_message_read_array(message, 'y', &d, &sz);
229 if (r < 0)
230 return r;
231 if (sz != FAMILY_ADDRESS_SIZE(family))
232 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid address size");
233
b30bf55d
LP
234 if (!dns_server_address_valid(family, d))
235 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid DNS server address");
236
d2ec6608
LP
237 r = sd_bus_message_exit_container(message);
238 if (r < 0)
239 return r;
240
241 if (!GREEDY_REALLOC(dns, allocated, n+1))
242 return -ENOMEM;
243
244 dns[n].family = family;
245 memcpy(&dns[n].address, d, sz);
246 n++;
247 }
248
249 r = sd_bus_message_exit_container(message);
250 if (r < 0)
251 return r;
252
253 dns_server_mark_all(l->dns_servers);
254
255 for (i = 0; i < n; i++) {
256 DnsServer *s;
257
2817157b 258 s = dns_server_find(l->dns_servers, dns[i].family, &dns[i].address, 0);
d2ec6608
LP
259 if (s)
260 dns_server_move_back_and_unmark(s);
261 else {
2817157b 262 r = dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, dns[i].family, &dns[i].address, 0);
d2ec6608
LP
263 if (r < 0)
264 goto clear;
265 }
266
267 }
268
269 dns_server_unlink_marked(l->dns_servers);
270 link_allocate_scopes(l);
271
943ef07c 272 (void) link_save_user(l);
7207052d
LP
273 (void) manager_write_resolv_conf(l->manager);
274
d2ec6608
LP
275 return sd_bus_reply_method_return(message, NULL);
276
277clear:
278 dns_server_unlink_all(l->dns_servers);
279 return r;
280}
281
ee116b54 282int bus_link_method_set_domains(sd_bus_message *message, void *userdata, sd_bus_error *error) {
d2ec6608 283 Link *l = userdata;
d2ec6608
LP
284 int r;
285
286 assert(message);
287 assert(l);
288
04b764bf
LP
289 r = verify_unmanaged_link(l, error);
290 if (r < 0)
291 return r;
292
ad44b56b 293 r = sd_bus_message_enter_container(message, 'a', "(sb)");
d2ec6608
LP
294 if (r < 0)
295 return r;
296
ad44b56b
LP
297 for (;;) {
298 const char *name;
299 int route_only;
d2ec6608 300
ad44b56b 301 r = sd_bus_message_read(message, "(sb)", &name, &route_only);
d2ec6608
LP
302 if (r < 0)
303 return r;
304 if (r == 0)
ad44b56b
LP
305 break;
306
307 r = dns_name_is_valid(name);
308 if (r < 0)
309 return r;
310 if (r == 0)
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))
d2ec6608
LP
313 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Root domain is not suitable as search domain");
314 }
315
316 dns_search_domain_mark_all(l->search_domains);
317
ad44b56b
LP
318 r = sd_bus_message_rewind(message, false);
319 if (r < 0)
320 return r;
321
322 for (;;) {
d2ec6608 323 DnsSearchDomain *d;
ad44b56b
LP
324 const char *name;
325 int route_only;
d2ec6608 326
ad44b56b
LP
327 r = sd_bus_message_read(message, "(sb)", &name, &route_only);
328 if (r < 0)
329 goto clear;
330 if (r == 0)
331 break;
332
333 r = dns_search_domain_find(l->search_domains, name, &d);
d2ec6608
LP
334 if (r < 0)
335 goto clear;
336
337 if (r > 0)
338 dns_search_domain_move_back_and_unmark(d);
339 else {
ad44b56b 340 r = dns_search_domain_new(l->manager, &d, DNS_SEARCH_DOMAIN_LINK, l, name);
d2ec6608
LP
341 if (r < 0)
342 goto clear;
343 }
ad44b56b
LP
344
345 d->route_only = route_only;
d2ec6608
LP
346 }
347
ad44b56b
LP
348 r = sd_bus_message_exit_container(message);
349 if (r < 0)
350 goto clear;
351
d2ec6608 352 dns_search_domain_unlink_marked(l->search_domains);
7207052d 353
943ef07c 354 (void) link_save_user(l);
7207052d
LP
355 (void) manager_write_resolv_conf(l->manager);
356
d2ec6608
LP
357 return sd_bus_reply_method_return(message, NULL);
358
359clear:
360 dns_search_domain_unlink_all(l->search_domains);
361 return r;
362}
363
364int bus_link_method_set_llmnr(sd_bus_message *message, void *userdata, sd_bus_error *error) {
365 Link *l = userdata;
366 ResolveSupport mode;
367 const char *llmnr;
368 int r;
369
370 assert(message);
371 assert(l);
372
04b764bf
LP
373 r = verify_unmanaged_link(l, error);
374 if (r < 0)
375 return r;
376
d2ec6608
LP
377 r = sd_bus_message_read(message, "s", &llmnr);
378 if (r < 0)
379 return r;
380
381 if (isempty(llmnr))
382 mode = RESOLVE_SUPPORT_YES;
383 else {
384 mode = resolve_support_from_string(llmnr);
385 if (mode < 0)
386 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid LLMNR setting: %s", llmnr);
387 }
388
389 l->llmnr_support = mode;
390 link_allocate_scopes(l);
391 link_add_rrs(l, false);
392
943ef07c
LP
393 (void) link_save_user(l);
394
d2ec6608
LP
395 return sd_bus_reply_method_return(message, NULL);
396}
397
398int bus_link_method_set_mdns(sd_bus_message *message, void *userdata, sd_bus_error *error) {
399 Link *l = userdata;
400 ResolveSupport mode;
401 const char *mdns;
402 int r;
403
404 assert(message);
405 assert(l);
406
04b764bf
LP
407 r = verify_unmanaged_link(l, error);
408 if (r < 0)
409 return r;
410
d2ec6608
LP
411 r = sd_bus_message_read(message, "s", &mdns);
412 if (r < 0)
413 return r;
414
415 if (isempty(mdns))
416 mode = RESOLVE_SUPPORT_NO;
417 else {
418 mode = resolve_support_from_string(mdns);
419 if (mode < 0)
420 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid MulticastDNS setting: %s", mdns);
421 }
422
423 l->mdns_support = mode;
424 link_allocate_scopes(l);
425 link_add_rrs(l, false);
426
943ef07c
LP
427 (void) link_save_user(l);
428
d2ec6608
LP
429 return sd_bus_reply_method_return(message, NULL);
430}
431
432int bus_link_method_set_dnssec(sd_bus_message *message, void *userdata, sd_bus_error *error) {
433 Link *l = userdata;
434 const char *dnssec;
435 DnssecMode mode;
436 int r;
437
438 assert(message);
439 assert(l);
440
04b764bf
LP
441 r = verify_unmanaged_link(l, error);
442 if (r < 0)
443 return r;
444
d2ec6608
LP
445 r = sd_bus_message_read(message, "s", &dnssec);
446 if (r < 0)
447 return r;
448
449 if (isempty(dnssec))
450 mode = _DNSSEC_MODE_INVALID;
451 else {
452 mode = dnssec_mode_from_string(dnssec);
453 if (mode < 0)
454 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid DNSSEC setting: %s", dnssec);
455 }
456
457 link_set_dnssec_mode(l, mode);
458
943ef07c
LP
459 (void) link_save_user(l);
460
d2ec6608
LP
461 return sd_bus_reply_method_return(message, NULL);
462}
463
464int 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;
c6d92582 466 _cleanup_strv_free_ char **ntas = NULL;
d2ec6608
LP
467 Link *l = userdata;
468 int r;
469 char **i;
470
471 assert(message);
472 assert(l);
473
04b764bf
LP
474 r = verify_unmanaged_link(l, error);
475 if (r < 0)
476 return r;
477
d2ec6608
LP
478 r = sd_bus_message_read_strv(message, &ntas);
479 if (r < 0)
480 return r;
481
482 STRV_FOREACH(i, ntas) {
483 r = dns_name_is_valid(*i);
484 if (r < 0)
485 return r;
486 if (r == 0)
55abd6da 487 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid negative trust anchor domain: %s", *i);
d2ec6608
LP
488 }
489
490 ns = set_new(&dns_name_hash_ops);
491 if (!ns)
492 return -ENOMEM;
493
494 STRV_FOREACH(i, ntas) {
495 r = set_put_strdup(ns, *i);
496 if (r < 0)
497 return r;
498 }
499
500 set_free_free(l->dnssec_negative_trust_anchors);
501 l->dnssec_negative_trust_anchors = ns;
502 ns = NULL;
503
943ef07c
LP
504 (void) link_save_user(l);
505
d2ec6608
LP
506 return sd_bus_reply_method_return(message, NULL);
507}
508
509int bus_link_method_revert(sd_bus_message *message, void *userdata, sd_bus_error *error) {
510 Link *l = userdata;
04b764bf 511 int r;
d2ec6608
LP
512
513 assert(message);
514 assert(l);
515
04b764bf
LP
516 r = verify_unmanaged_link(l, error);
517 if (r < 0)
518 return r;
519
d2ec6608
LP
520 link_flush_settings(l);
521 link_allocate_scopes(l);
522 link_add_rrs(l, false);
523
943ef07c 524 (void) link_save_user(l);
7207052d
LP
525 (void) manager_write_resolv_conf(l->manager);
526
d2ec6608
LP
527 return sd_bus_reply_method_return(message, NULL);
528}
529
3abaabda
LP
530const sd_bus_vtable link_vtable[] = {
531 SD_BUS_VTABLE_START(0),
532
533 SD_BUS_PROPERTY("ScopesMask", "t", property_get_scopes_mask, 0, 0),
534 SD_BUS_PROPERTY("DNS", "a(iay)", property_get_dns, 0, 0),
ad44b56b 535 SD_BUS_PROPERTY("Domains", "a(sb)", property_get_domains, 0, 0),
3abaabda
LP
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),
a3712979 538 SD_BUS_PROPERTY("DNSSEC", "s", property_get_dnssec_mode, 0, 0),
3abaabda 539 SD_BUS_PROPERTY("DNSSECNegativeTrustAnchors", "as", property_get_ntas, 0, 0),
c2cf6e0b 540 SD_BUS_PROPERTY("DNSSECSupported", "b", property_get_dnssec_supported, 0, 0),
3abaabda 541
d2ec6608 542 SD_BUS_METHOD("SetDNS", "a(iay)", NULL, bus_link_method_set_dns_servers, 0),
ee116b54 543 SD_BUS_METHOD("SetDomains", "a(sb)", NULL, bus_link_method_set_domains, 0),
d2ec6608
LP
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),
549
3abaabda
LP
550 SD_BUS_VTABLE_END
551};
552
553int 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;
556 int ifindex;
557 Link *link;
558 int r;
559
560 assert(bus);
561 assert(path);
562 assert(interface);
563 assert(found);
564 assert(m);
565
566 r = sd_bus_path_decode(path, "/org/freedesktop/resolve1/link", &e);
567 if (r <= 0)
568 return 0;
569
570 r = parse_ifindex(e, &ifindex);
571 if (r < 0)
572 return 0;
573
574 link = hashmap_get(m->links, INT_TO_PTR(ifindex));
575 if (!link)
576 return 0;
577
578 *found = link;
579 return 1;
580}
581
582char *link_bus_path(Link *link) {
583 _cleanup_free_ char *ifindex = NULL;
584 char *p;
585 int r;
586
587 assert(link);
588
589 if (asprintf(&ifindex, "%i", link->ifindex) < 0)
590 return NULL;
591
592 r = sd_bus_path_encode("/org/freedesktop/resolve1/link", ifindex, &p);
593 if (r < 0)
594 return NULL;
595
596 return p;
597}
598
599int 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;
602 Link *link;
603 Iterator i;
604 unsigned c = 0;
605
606 assert(bus);
607 assert(path);
608 assert(m);
609 assert(nodes);
610
611 l = new0(char*, hashmap_size(m->links) + 1);
612 if (!l)
613 return -ENOMEM;
614
615 HASHMAP_FOREACH(link, m->links, i) {
616 char *p;
617
618 p = link_bus_path(link);
619 if (!p)
620 return -ENOMEM;
621
622 l[c++] = p;
623 }
624
625 l[c] = NULL;
626 *nodes = l;
627 l = NULL;
628
629 return 1;
630}