]> git.ipfire.org Git - thirdparty/systemd.git/blob - 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
1 /* SPDX-License-Identifier: LGPL-2.1+ */
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"
22 #include "bus-common-errors.h"
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"
28 #include "resolved-resolv-conf.h"
29 #include "strv.h"
30
31 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_resolve_support, resolve_support, ResolveSupport);
32
33 static 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 }
49
50 static 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
79 static 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
95 r = sd_bus_message_open_container(reply, 'a', "(sb)");
96 if (r < 0)
97 return r;
98
99 LIST_FOREACH(domains, d, l->search_domains) {
100 r = sd_bus_message_append(reply, "(sb)", d->name, d->route_only);
101 if (r < 0)
102 return r;
103 }
104
105 return sd_bus_message_close_container(reply);
106 }
107
108 static 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
132 static 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
162 static 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
179 static 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
190 int 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
200 r = verify_unmanaged_link(l, error);
201 if (r < 0)
202 return r;
203
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
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
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
258 s = dns_server_find(l->dns_servers, dns[i].family, &dns[i].address, 0);
259 if (s)
260 dns_server_move_back_and_unmark(s);
261 else {
262 r = dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, dns[i].family, &dns[i].address, 0);
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
272 (void) link_save_user(l);
273 (void) manager_write_resolv_conf(l->manager);
274
275 return sd_bus_reply_method_return(message, NULL);
276
277 clear:
278 dns_server_unlink_all(l->dns_servers);
279 return r;
280 }
281
282 int bus_link_method_set_domains(sd_bus_message *message, void *userdata, sd_bus_error *error) {
283 Link *l = userdata;
284 int r;
285
286 assert(message);
287 assert(l);
288
289 r = verify_unmanaged_link(l, error);
290 if (r < 0)
291 return r;
292
293 r = sd_bus_message_enter_container(message, 'a', "(sb)");
294 if (r < 0)
295 return r;
296
297 for (;;) {
298 const char *name;
299 int route_only;
300
301 r = sd_bus_message_read(message, "(sb)", &name, &route_only);
302 if (r < 0)
303 return r;
304 if (r == 0)
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))
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
318 r = sd_bus_message_rewind(message, false);
319 if (r < 0)
320 return r;
321
322 for (;;) {
323 DnsSearchDomain *d;
324 const char *name;
325 int route_only;
326
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);
334 if (r < 0)
335 goto clear;
336
337 if (r > 0)
338 dns_search_domain_move_back_and_unmark(d);
339 else {
340 r = dns_search_domain_new(l->manager, &d, DNS_SEARCH_DOMAIN_LINK, l, name);
341 if (r < 0)
342 goto clear;
343 }
344
345 d->route_only = route_only;
346 }
347
348 r = sd_bus_message_exit_container(message);
349 if (r < 0)
350 goto clear;
351
352 dns_search_domain_unlink_marked(l->search_domains);
353
354 (void) link_save_user(l);
355 (void) manager_write_resolv_conf(l->manager);
356
357 return sd_bus_reply_method_return(message, NULL);
358
359 clear:
360 dns_search_domain_unlink_all(l->search_domains);
361 return r;
362 }
363
364 int 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
373 r = verify_unmanaged_link(l, error);
374 if (r < 0)
375 return r;
376
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
393 (void) link_save_user(l);
394
395 return sd_bus_reply_method_return(message, NULL);
396 }
397
398 int 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
407 r = verify_unmanaged_link(l, error);
408 if (r < 0)
409 return r;
410
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
427 (void) link_save_user(l);
428
429 return sd_bus_reply_method_return(message, NULL);
430 }
431
432 int 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
441 r = verify_unmanaged_link(l, error);
442 if (r < 0)
443 return r;
444
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
459 (void) link_save_user(l);
460
461 return sd_bus_reply_method_return(message, NULL);
462 }
463
464 int 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;
466 _cleanup_strv_free_ char **ntas = NULL;
467 Link *l = userdata;
468 int r;
469 char **i;
470
471 assert(message);
472 assert(l);
473
474 r = verify_unmanaged_link(l, error);
475 if (r < 0)
476 return r;
477
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)
487 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid negative trust anchor domain: %s", *i);
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
504 (void) link_save_user(l);
505
506 return sd_bus_reply_method_return(message, NULL);
507 }
508
509 int bus_link_method_revert(sd_bus_message *message, void *userdata, sd_bus_error *error) {
510 Link *l = userdata;
511 int r;
512
513 assert(message);
514 assert(l);
515
516 r = verify_unmanaged_link(l, error);
517 if (r < 0)
518 return r;
519
520 link_flush_settings(l);
521 link_allocate_scopes(l);
522 link_add_rrs(l, false);
523
524 (void) link_save_user(l);
525 (void) manager_write_resolv_conf(l->manager);
526
527 return sd_bus_reply_method_return(message, NULL);
528 }
529
530 const 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),
535 SD_BUS_PROPERTY("Domains", "a(sb)", property_get_domains, 0, 0),
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),
538 SD_BUS_PROPERTY("DNSSEC", "s", property_get_dnssec_mode, 0, 0),
539 SD_BUS_PROPERTY("DNSSECNegativeTrustAnchors", "as", property_get_ntas, 0, 0),
540 SD_BUS_PROPERTY("DNSSECSupported", "b", property_get_dnssec_supported, 0, 0),
541
542 SD_BUS_METHOD("SetDNS", "a(iay)", NULL, bus_link_method_set_dns_servers, 0),
543 SD_BUS_METHOD("SetDomains", "a(sb)", NULL, bus_link_method_set_domains, 0),
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
550 SD_BUS_VTABLE_END
551 };
552
553 int 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
582 char *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
599 int 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 }