]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/resolve/resolved-link-bus.c
Merge pull request #3520 from keszybz/add-release.md
[thirdparty/systemd.git] / src / resolve / resolved-link-bus.c
1 /***
2 This file is part of systemd.
3
4 Copyright 2016 Lennart Poettering
5
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #include "alloc-util.h"
21 #include "bus-common-errors.h"
22 #include "bus-util.h"
23 #include "parse-util.h"
24 #include "resolve-util.h"
25 #include "resolved-bus.h"
26 #include "resolved-link-bus.h"
27 #include "resolved-resolv-conf.h"
28 #include "strv.h"
29
30 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_resolve_support, resolve_support, ResolveSupport);
31 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_dnssec_mode, dnssec_mode, DnssecMode);
32
33 static int property_get_dns(
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 DnsServer *s;
44 int r;
45
46 assert(reply);
47 assert(l);
48
49 r = sd_bus_message_open_container(reply, 'a', "(iay)");
50 if (r < 0)
51 return r;
52
53 LIST_FOREACH(servers, s, l->dns_servers) {
54 r = bus_dns_server_append(reply, s, false);
55 if (r < 0)
56 return r;
57 }
58
59 return sd_bus_message_close_container(reply);
60 }
61
62 static int property_get_domains(
63 sd_bus *bus,
64 const char *path,
65 const char *interface,
66 const char *property,
67 sd_bus_message *reply,
68 void *userdata,
69 sd_bus_error *error) {
70
71 Link *l = userdata;
72 DnsSearchDomain *d;
73 int r;
74
75 assert(reply);
76 assert(l);
77
78 r = sd_bus_message_open_container(reply, 'a', "(sb)");
79 if (r < 0)
80 return r;
81
82 LIST_FOREACH(domains, d, l->search_domains) {
83 r = sd_bus_message_append(reply, "(sb)", d->name, d->route_only);
84 if (r < 0)
85 return r;
86 }
87
88 return sd_bus_message_close_container(reply);
89 }
90
91 static int property_get_scopes_mask(
92 sd_bus *bus,
93 const char *path,
94 const char *interface,
95 const char *property,
96 sd_bus_message *reply,
97 void *userdata,
98 sd_bus_error *error) {
99
100 Link *l = userdata;
101 uint64_t mask;
102
103 assert(reply);
104 assert(l);
105
106 mask = (l->unicast_scope ? SD_RESOLVED_DNS : 0) |
107 (l->llmnr_ipv4_scope ? SD_RESOLVED_LLMNR_IPV4 : 0) |
108 (l->llmnr_ipv6_scope ? SD_RESOLVED_LLMNR_IPV6 : 0) |
109 (l->mdns_ipv4_scope ? SD_RESOLVED_MDNS_IPV4 : 0) |
110 (l->mdns_ipv6_scope ? SD_RESOLVED_MDNS_IPV6 : 0);
111
112 return sd_bus_message_append(reply, "t", mask);
113 }
114
115 static int property_get_ntas(
116 sd_bus *bus,
117 const char *path,
118 const char *interface,
119 const char *property,
120 sd_bus_message *reply,
121 void *userdata,
122 sd_bus_error *error) {
123
124 Link *l = userdata;
125 const char *name;
126 Iterator i;
127 int r;
128
129 assert(reply);
130 assert(l);
131
132 r = sd_bus_message_open_container(reply, 'a', "s");
133 if (r < 0)
134 return r;
135
136 SET_FOREACH(name, l->dnssec_negative_trust_anchors, i) {
137 r = sd_bus_message_append(reply, "s", name);
138 if (r < 0)
139 return r;
140 }
141
142 return sd_bus_message_close_container(reply);
143 }
144
145 static int property_get_dnssec_supported(
146 sd_bus *bus,
147 const char *path,
148 const char *interface,
149 const char *property,
150 sd_bus_message *reply,
151 void *userdata,
152 sd_bus_error *error) {
153
154 Link *l = userdata;
155
156 assert(reply);
157 assert(l);
158
159 return sd_bus_message_append(reply, "b", link_dnssec_supported(l));
160 }
161
162 static int verify_unmanaged_link(Link *l, sd_bus_error *error) {
163 assert(l);
164
165 if (l->flags & IFF_LOOPBACK)
166 return sd_bus_error_setf(error, BUS_ERROR_LINK_BUSY, "Link %s is loopback device.", l->name);
167 if (l->is_managed)
168 return sd_bus_error_setf(error, BUS_ERROR_LINK_BUSY, "Link %s is managed.", l->name);
169
170 return 0;
171 }
172
173 int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_bus_error *error) {
174 _cleanup_free_ struct in_addr_data *dns = NULL;
175 size_t allocated = 0, n = 0;
176 Link *l = userdata;
177 unsigned i;
178 int r;
179
180 assert(message);
181 assert(l);
182
183 r = verify_unmanaged_link(l, error);
184 if (r < 0)
185 return r;
186
187 r = sd_bus_message_enter_container(message, 'a', "(iay)");
188 if (r < 0)
189 return r;
190
191 for (;;) {
192 int family;
193 size_t sz;
194 const void *d;
195
196 assert_cc(sizeof(int) == sizeof(int32_t));
197
198 r = sd_bus_message_enter_container(message, 'r', "iay");
199 if (r < 0)
200 return r;
201 if (r == 0)
202 break;
203
204 r = sd_bus_message_read(message, "i", &family);
205 if (r < 0)
206 return r;
207
208 if (!IN_SET(family, AF_INET, AF_INET6))
209 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family);
210
211 r = sd_bus_message_read_array(message, 'y', &d, &sz);
212 if (r < 0)
213 return r;
214 if (sz != FAMILY_ADDRESS_SIZE(family))
215 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid address size");
216
217 r = sd_bus_message_exit_container(message);
218 if (r < 0)
219 return r;
220
221 if (!GREEDY_REALLOC(dns, allocated, n+1))
222 return -ENOMEM;
223
224 dns[n].family = family;
225 memcpy(&dns[n].address, d, sz);
226 n++;
227 }
228
229 r = sd_bus_message_exit_container(message);
230 if (r < 0)
231 return r;
232
233 dns_server_mark_all(l->dns_servers);
234
235 for (i = 0; i < n; i++) {
236 DnsServer *s;
237
238 s = dns_server_find(l->dns_servers, dns[i].family, &dns[i].address, 0);
239 if (s)
240 dns_server_move_back_and_unmark(s);
241 else {
242 r = dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, dns[i].family, &dns[i].address, 0);
243 if (r < 0)
244 goto clear;
245 }
246
247 }
248
249 dns_server_unlink_marked(l->dns_servers);
250 link_allocate_scopes(l);
251
252 (void) manager_write_resolv_conf(l->manager);
253
254 return sd_bus_reply_method_return(message, NULL);
255
256 clear:
257 dns_server_unlink_all(l->dns_servers);
258 return r;
259 }
260
261 int bus_link_method_set_domains(sd_bus_message *message, void *userdata, sd_bus_error *error) {
262 Link *l = userdata;
263 int r;
264
265 assert(message);
266 assert(l);
267
268 r = verify_unmanaged_link(l, error);
269 if (r < 0)
270 return r;
271
272 r = sd_bus_message_enter_container(message, 'a', "(sb)");
273 if (r < 0)
274 return r;
275
276 for (;;) {
277 const char *name;
278 int route_only;
279
280 r = sd_bus_message_read(message, "(sb)", &name, &route_only);
281 if (r < 0)
282 return r;
283 if (r == 0)
284 break;
285
286 r = dns_name_is_valid(name);
287 if (r < 0)
288 return r;
289 if (r == 0)
290 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid search domain %s", name);
291 if (!route_only && dns_name_is_root(name))
292 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Root domain is not suitable as search domain");
293 }
294
295 dns_search_domain_mark_all(l->search_domains);
296
297 r = sd_bus_message_rewind(message, false);
298 if (r < 0)
299 return r;
300
301 for (;;) {
302 DnsSearchDomain *d;
303 const char *name;
304 int route_only;
305
306 r = sd_bus_message_read(message, "(sb)", &name, &route_only);
307 if (r < 0)
308 goto clear;
309 if (r == 0)
310 break;
311
312 r = dns_search_domain_find(l->search_domains, name, &d);
313 if (r < 0)
314 goto clear;
315
316 if (r > 0)
317 dns_search_domain_move_back_and_unmark(d);
318 else {
319 r = dns_search_domain_new(l->manager, &d, DNS_SEARCH_DOMAIN_LINK, l, name);
320 if (r < 0)
321 goto clear;
322 }
323
324 d->route_only = route_only;
325 }
326
327 r = sd_bus_message_exit_container(message);
328 if (r < 0)
329 goto clear;
330
331 dns_search_domain_unlink_marked(l->search_domains);
332
333 (void) manager_write_resolv_conf(l->manager);
334
335 return sd_bus_reply_method_return(message, NULL);
336
337 clear:
338 dns_search_domain_unlink_all(l->search_domains);
339 return r;
340 }
341
342 int bus_link_method_set_llmnr(sd_bus_message *message, void *userdata, sd_bus_error *error) {
343 Link *l = userdata;
344 ResolveSupport mode;
345 const char *llmnr;
346 int r;
347
348 assert(message);
349 assert(l);
350
351 r = verify_unmanaged_link(l, error);
352 if (r < 0)
353 return r;
354
355 r = sd_bus_message_read(message, "s", &llmnr);
356 if (r < 0)
357 return r;
358
359 if (isempty(llmnr))
360 mode = RESOLVE_SUPPORT_YES;
361 else {
362 mode = resolve_support_from_string(llmnr);
363 if (mode < 0)
364 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid LLMNR setting: %s", llmnr);
365 }
366
367 l->llmnr_support = mode;
368 link_allocate_scopes(l);
369 link_add_rrs(l, false);
370
371 return sd_bus_reply_method_return(message, NULL);
372 }
373
374 int bus_link_method_set_mdns(sd_bus_message *message, void *userdata, sd_bus_error *error) {
375 Link *l = userdata;
376 ResolveSupport mode;
377 const char *mdns;
378 int r;
379
380 assert(message);
381 assert(l);
382
383 r = verify_unmanaged_link(l, error);
384 if (r < 0)
385 return r;
386
387 r = sd_bus_message_read(message, "s", &mdns);
388 if (r < 0)
389 return r;
390
391 if (isempty(mdns))
392 mode = RESOLVE_SUPPORT_NO;
393 else {
394 mode = resolve_support_from_string(mdns);
395 if (mode < 0)
396 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid MulticastDNS setting: %s", mdns);
397 }
398
399 l->mdns_support = mode;
400 link_allocate_scopes(l);
401 link_add_rrs(l, false);
402
403 return sd_bus_reply_method_return(message, NULL);
404 }
405
406 int bus_link_method_set_dnssec(sd_bus_message *message, void *userdata, sd_bus_error *error) {
407 Link *l = userdata;
408 const char *dnssec;
409 DnssecMode mode;
410 int r;
411
412 assert(message);
413 assert(l);
414
415 r = verify_unmanaged_link(l, error);
416 if (r < 0)
417 return r;
418
419 r = sd_bus_message_read(message, "s", &dnssec);
420 if (r < 0)
421 return r;
422
423 if (isempty(dnssec))
424 mode = _DNSSEC_MODE_INVALID;
425 else {
426 mode = dnssec_mode_from_string(dnssec);
427 if (mode < 0)
428 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid DNSSEC setting: %s", dnssec);
429 }
430
431 link_set_dnssec_mode(l, mode);
432
433 return sd_bus_reply_method_return(message, NULL);
434 }
435
436 int bus_link_method_set_dnssec_negative_trust_anchors(sd_bus_message *message, void *userdata, sd_bus_error *error) {
437 _cleanup_set_free_free_ Set *ns = NULL;
438 _cleanup_free_ char **ntas = NULL;
439 Link *l = userdata;
440 int r;
441 char **i;
442
443 assert(message);
444 assert(l);
445
446 r = verify_unmanaged_link(l, error);
447 if (r < 0)
448 return r;
449
450 r = sd_bus_message_read_strv(message, &ntas);
451 if (r < 0)
452 return r;
453
454 STRV_FOREACH(i, ntas) {
455 r = dns_name_is_valid(*i);
456 if (r < 0)
457 return r;
458 if (r == 0)
459 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid negative trust anchor domain: %s", *i);
460 }
461
462 ns = set_new(&dns_name_hash_ops);
463 if (!ns)
464 return -ENOMEM;
465
466 STRV_FOREACH(i, ntas) {
467 r = set_put_strdup(ns, *i);
468 if (r < 0)
469 return r;
470 }
471
472 set_free_free(l->dnssec_negative_trust_anchors);
473 l->dnssec_negative_trust_anchors = ns;
474 ns = NULL;
475
476 return sd_bus_reply_method_return(message, NULL);
477 }
478
479 int bus_link_method_revert(sd_bus_message *message, void *userdata, sd_bus_error *error) {
480 Link *l = userdata;
481 int r;
482
483 assert(message);
484 assert(l);
485
486 r = verify_unmanaged_link(l, error);
487 if (r < 0)
488 return r;
489
490 link_flush_settings(l);
491 link_allocate_scopes(l);
492 link_add_rrs(l, false);
493
494 (void) manager_write_resolv_conf(l->manager);
495
496 return sd_bus_reply_method_return(message, NULL);
497 }
498
499 const sd_bus_vtable link_vtable[] = {
500 SD_BUS_VTABLE_START(0),
501
502 SD_BUS_PROPERTY("ScopesMask", "t", property_get_scopes_mask, 0, 0),
503 SD_BUS_PROPERTY("DNS", "a(iay)", property_get_dns, 0, 0),
504 SD_BUS_PROPERTY("Domains", "a(sb)", property_get_domains, 0, 0),
505 SD_BUS_PROPERTY("LLMNR", "s", property_get_resolve_support, offsetof(Link, llmnr_support), 0),
506 SD_BUS_PROPERTY("MulticastDNS", "s", property_get_resolve_support, offsetof(Link, mdns_support), 0),
507 SD_BUS_PROPERTY("DNSSEC", "s", property_get_dnssec_mode, offsetof(Link, dnssec_mode), 0),
508 SD_BUS_PROPERTY("DNSSECNegativeTrustAnchors", "as", property_get_ntas, 0, 0),
509 SD_BUS_PROPERTY("DNSSECSupported", "b", property_get_dnssec_supported, 0, 0),
510
511 SD_BUS_METHOD("SetDNS", "a(iay)", NULL, bus_link_method_set_dns_servers, 0),
512 SD_BUS_METHOD("SetDomains", "a(sb)", NULL, bus_link_method_set_domains, 0),
513 SD_BUS_METHOD("SetLLMNR", "s", NULL, bus_link_method_set_llmnr, 0),
514 SD_BUS_METHOD("SetMulticastDNS", "s", NULL, bus_link_method_set_mdns, 0),
515 SD_BUS_METHOD("SetDNSSEC", "s", NULL, bus_link_method_set_dnssec, 0),
516 SD_BUS_METHOD("SetDNSSECNegativeTrustAnchors", "as", NULL, bus_link_method_set_dnssec_negative_trust_anchors, 0),
517 SD_BUS_METHOD("Revert", NULL, NULL, bus_link_method_revert, 0),
518
519 SD_BUS_VTABLE_END
520 };
521
522 int link_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
523 _cleanup_free_ char *e = NULL;
524 Manager *m = userdata;
525 int ifindex;
526 Link *link;
527 int r;
528
529 assert(bus);
530 assert(path);
531 assert(interface);
532 assert(found);
533 assert(m);
534
535 r = sd_bus_path_decode(path, "/org/freedesktop/resolve1/link", &e);
536 if (r <= 0)
537 return 0;
538
539 r = parse_ifindex(e, &ifindex);
540 if (r < 0)
541 return 0;
542
543 link = hashmap_get(m->links, INT_TO_PTR(ifindex));
544 if (!link)
545 return 0;
546
547 *found = link;
548 return 1;
549 }
550
551 char *link_bus_path(Link *link) {
552 _cleanup_free_ char *ifindex = NULL;
553 char *p;
554 int r;
555
556 assert(link);
557
558 if (asprintf(&ifindex, "%i", link->ifindex) < 0)
559 return NULL;
560
561 r = sd_bus_path_encode("/org/freedesktop/resolve1/link", ifindex, &p);
562 if (r < 0)
563 return NULL;
564
565 return p;
566 }
567
568 int link_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
569 _cleanup_strv_free_ char **l = NULL;
570 Manager *m = userdata;
571 Link *link;
572 Iterator i;
573 unsigned c = 0;
574
575 assert(bus);
576 assert(path);
577 assert(m);
578 assert(nodes);
579
580 l = new0(char*, hashmap_size(m->links) + 1);
581 if (!l)
582 return -ENOMEM;
583
584 HASHMAP_FOREACH(link, m->links, i) {
585 char *p;
586
587 p = link_bus_path(link);
588 if (!p)
589 return -ENOMEM;
590
591 l[c++] = p;
592 }
593
594 l[c] = NULL;
595 *nodes = l;
596 l = NULL;
597
598 return 1;
599 }