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