]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/resolve/resolved-link-bus.c
resolved: add SetLinkXYZ() method counterparts on the Link object
[thirdparty/systemd.git] / src / resolve / resolved-link-bus.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2016 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include "alloc-util.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 "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', "s");
79 if (r < 0)
80 return r;
81
82 LIST_FOREACH(domains, d, l->search_domains) {
83 r = sd_bus_message_append(reply, "s", d->name);
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 int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_bus_error *error) {
146 _cleanup_free_ struct in_addr_data *dns = NULL;
147 size_t allocated = 0, n = 0;
148 Link *l = userdata;
149 unsigned i;
150 int r;
151
152 assert(message);
153 assert(l);
154
155 r = sd_bus_message_enter_container(message, 'a', "(iay)");
156 if (r < 0)
157 return r;
158
159 for (;;) {
160 int family;
161 size_t sz;
162 const void *d;
163
164 assert_cc(sizeof(int) == sizeof(int32_t));
165
166 r = sd_bus_message_enter_container(message, 'r', "iay");
167 if (r < 0)
168 return r;
169 if (r == 0)
170 break;
171
172 r = sd_bus_message_read(message, "i", &family);
173 if (r < 0)
174 return r;
175
176 if (!IN_SET(family, AF_INET, AF_INET6))
177 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family);
178
179 r = sd_bus_message_read_array(message, 'y', &d, &sz);
180 if (r < 0)
181 return r;
182 if (sz != FAMILY_ADDRESS_SIZE(family))
183 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid address size");
184
185 r = sd_bus_message_exit_container(message);
186 if (r < 0)
187 return r;
188
189 if (!GREEDY_REALLOC(dns, allocated, n+1))
190 return -ENOMEM;
191
192 dns[n].family = family;
193 memcpy(&dns[n].address, d, sz);
194 n++;
195 }
196
197 r = sd_bus_message_exit_container(message);
198 if (r < 0)
199 return r;
200
201 dns_server_mark_all(l->dns_servers);
202
203 for (i = 0; i < n; i++) {
204 DnsServer *s;
205
206 s = dns_server_find(l->dns_servers, dns[i].family, &dns[i].address);
207 if (s)
208 dns_server_move_back_and_unmark(s);
209 else {
210 r = dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, dns[i].family, &dns[i].address);
211 if (r < 0)
212 goto clear;
213 }
214
215 }
216
217 dns_server_unlink_marked(l->dns_servers);
218 link_allocate_scopes(l);
219
220 return sd_bus_reply_method_return(message, NULL);
221
222 clear:
223 dns_server_unlink_all(l->dns_servers);
224 return r;
225 }
226
227 int bus_link_method_set_search_domains(sd_bus_message *message, void *userdata, sd_bus_error *error) {
228 _cleanup_free_ char **domains = NULL;
229 Link *l = userdata;
230 char **i;
231 int r;
232
233 assert(message);
234 assert(l);
235
236 r = sd_bus_message_read_strv(message, &domains);
237 if (r < 0)
238 return r;
239
240 STRV_FOREACH(i, domains) {
241
242 r = dns_name_is_valid(*i);
243 if (r < 0)
244 return r;
245 if (r == 0)
246 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid search domain %s", *i);
247 if (dns_name_is_root(*i))
248 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Root domain is not suitable as search domain");
249 }
250
251 dns_search_domain_mark_all(l->search_domains);
252
253 STRV_FOREACH(i, domains) {
254 DnsSearchDomain *d;
255
256 r = dns_search_domain_find(l->search_domains, *i, &d);
257 if (r < 0)
258 goto clear;
259
260 if (r > 0)
261 dns_search_domain_move_back_and_unmark(d);
262 else {
263 r = dns_search_domain_new(l->manager, NULL, DNS_SEARCH_DOMAIN_LINK, l, *i);
264 if (r < 0)
265 goto clear;
266 }
267 }
268
269 dns_search_domain_unlink_marked(l->search_domains);
270 return sd_bus_reply_method_return(message, NULL);
271
272 clear:
273 dns_search_domain_unlink_all(l->search_domains);
274 return r;
275 }
276
277 int bus_link_method_set_llmnr(sd_bus_message *message, void *userdata, sd_bus_error *error) {
278 Link *l = userdata;
279 ResolveSupport mode;
280 const char *llmnr;
281 int r;
282
283 assert(message);
284 assert(l);
285
286 r = sd_bus_message_read(message, "s", &llmnr);
287 if (r < 0)
288 return r;
289
290 if (isempty(llmnr))
291 mode = RESOLVE_SUPPORT_YES;
292 else {
293 mode = resolve_support_from_string(llmnr);
294 if (mode < 0)
295 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid LLMNR setting: %s", llmnr);
296 }
297
298 l->llmnr_support = mode;
299 link_allocate_scopes(l);
300 link_add_rrs(l, false);
301
302 return sd_bus_reply_method_return(message, NULL);
303 }
304
305 int bus_link_method_set_mdns(sd_bus_message *message, void *userdata, sd_bus_error *error) {
306 Link *l = userdata;
307 ResolveSupport mode;
308 const char *mdns;
309 int r;
310
311 assert(message);
312 assert(l);
313
314 r = sd_bus_message_read(message, "s", &mdns);
315 if (r < 0)
316 return r;
317
318 if (isempty(mdns))
319 mode = RESOLVE_SUPPORT_NO;
320 else {
321 mode = resolve_support_from_string(mdns);
322 if (mode < 0)
323 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid MulticastDNS setting: %s", mdns);
324 }
325
326 l->mdns_support = mode;
327 link_allocate_scopes(l);
328 link_add_rrs(l, false);
329
330 return sd_bus_reply_method_return(message, NULL);
331 }
332
333 int bus_link_method_set_dnssec(sd_bus_message *message, void *userdata, sd_bus_error *error) {
334 Link *l = userdata;
335 const char *dnssec;
336 DnssecMode mode;
337 int r;
338
339 assert(message);
340 assert(l);
341
342 r = sd_bus_message_read(message, "s", &dnssec);
343 if (r < 0)
344 return r;
345
346 if (isempty(dnssec))
347 mode = _DNSSEC_MODE_INVALID;
348 else {
349 mode = dnssec_mode_from_string(dnssec);
350 if (mode < 0)
351 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid DNSSEC setting: %s", dnssec);
352 }
353
354 link_set_dnssec_mode(l, mode);
355
356 return sd_bus_reply_method_return(message, NULL);
357 }
358
359 int bus_link_method_set_dnssec_negative_trust_anchors(sd_bus_message *message, void *userdata, sd_bus_error *error) {
360 _cleanup_set_free_free_ Set *ns = NULL;
361 _cleanup_free_ char **ntas = NULL;
362 Link *l = userdata;
363 int r;
364 char **i;
365
366 assert(message);
367 assert(l);
368
369 r = sd_bus_message_read_strv(message, &ntas);
370 if (r < 0)
371 return r;
372
373 STRV_FOREACH(i, ntas) {
374 r = dns_name_is_valid(*i);
375 if (r < 0)
376 return r;
377 if (r == 0)
378 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid search negative trust anchor domain: %s", *i);
379 }
380
381 ns = set_new(&dns_name_hash_ops);
382 if (!ns)
383 return -ENOMEM;
384
385 STRV_FOREACH(i, ntas) {
386 r = set_put_strdup(ns, *i);
387 if (r < 0)
388 return r;
389 }
390
391 set_free_free(l->dnssec_negative_trust_anchors);
392 l->dnssec_negative_trust_anchors = ns;
393 ns = NULL;
394
395 return sd_bus_reply_method_return(message, NULL);
396 }
397
398 int bus_link_method_revert(sd_bus_message *message, void *userdata, sd_bus_error *error) {
399 Link *l = userdata;
400
401 assert(message);
402 assert(l);
403
404 link_flush_settings(l);
405 link_allocate_scopes(l);
406 link_add_rrs(l, false);
407
408 return sd_bus_reply_method_return(message, NULL);
409 }
410
411 const sd_bus_vtable link_vtable[] = {
412 SD_BUS_VTABLE_START(0),
413
414 SD_BUS_PROPERTY("ScopesMask", "t", property_get_scopes_mask, 0, 0),
415 SD_BUS_PROPERTY("DNS", "a(iay)", property_get_dns, 0, 0),
416 SD_BUS_PROPERTY("Domains", "as", property_get_domains, 0, 0),
417 SD_BUS_PROPERTY("LLMNR", "s", property_get_resolve_support, offsetof(Link, llmnr_support), 0),
418 SD_BUS_PROPERTY("MulticastDNS", "s", property_get_resolve_support, offsetof(Link, mdns_support), 0),
419 SD_BUS_PROPERTY("DNSSEC", "s", property_get_dnssec_mode, offsetof(Link, dnssec_mode), 0),
420 SD_BUS_PROPERTY("DNSSECNegativeTrustAnchors", "as", property_get_ntas, 0, 0),
421
422 SD_BUS_METHOD("SetDNS", "a(iay)", NULL, bus_link_method_set_dns_servers, 0),
423 SD_BUS_METHOD("SetDomains", "as", NULL, bus_link_method_set_search_domains, 0),
424 SD_BUS_METHOD("SetLLMNR", "s", NULL, bus_link_method_set_llmnr, 0),
425 SD_BUS_METHOD("SetMulticastDNS", "s", NULL, bus_link_method_set_mdns, 0),
426 SD_BUS_METHOD("SetDNSSEC", "s", NULL, bus_link_method_set_dnssec, 0),
427 SD_BUS_METHOD("SetDNSSECNegativeTrustAnchors", "as", NULL, bus_link_method_set_dnssec_negative_trust_anchors, 0),
428 SD_BUS_METHOD("Revert", NULL, NULL, bus_link_method_revert, 0),
429
430 SD_BUS_VTABLE_END
431 };
432
433 int link_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
434 _cleanup_free_ char *e = NULL;
435 Manager *m = userdata;
436 int ifindex;
437 Link *link;
438 int r;
439
440 assert(bus);
441 assert(path);
442 assert(interface);
443 assert(found);
444 assert(m);
445
446 r = sd_bus_path_decode(path, "/org/freedesktop/resolve1/link", &e);
447 if (r <= 0)
448 return 0;
449
450 r = parse_ifindex(e, &ifindex);
451 if (r < 0)
452 return 0;
453
454 link = hashmap_get(m->links, INT_TO_PTR(ifindex));
455 if (!link)
456 return 0;
457
458 *found = link;
459 return 1;
460 }
461
462 char *link_bus_path(Link *link) {
463 _cleanup_free_ char *ifindex = NULL;
464 char *p;
465 int r;
466
467 assert(link);
468
469 if (asprintf(&ifindex, "%i", link->ifindex) < 0)
470 return NULL;
471
472 r = sd_bus_path_encode("/org/freedesktop/resolve1/link", ifindex, &p);
473 if (r < 0)
474 return NULL;
475
476 return p;
477 }
478
479 int link_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
480 _cleanup_strv_free_ char **l = NULL;
481 Manager *m = userdata;
482 Link *link;
483 Iterator i;
484 unsigned c = 0;
485
486 assert(bus);
487 assert(path);
488 assert(m);
489 assert(nodes);
490
491 l = new0(char*, hashmap_size(m->links) + 1);
492 if (!l)
493 return -ENOMEM;
494
495 HASHMAP_FOREACH(link, m->links, i) {
496 char *p;
497
498 p = link_bus_path(link);
499 if (!p)
500 return -ENOMEM;
501
502 l[c++] = p;
503 }
504
505 l[c] = NULL;
506 *nodes = l;
507 l = NULL;
508
509 return 1;
510 }