]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-link-bus.c
resolved: fix RR key reduction logic
[thirdparty/systemd.git] / src / resolve / resolved-link-bus.c
CommitLineData
3abaabda
LP
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
30static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_resolve_support, resolve_support, ResolveSupport);
31static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_dnssec_mode, dnssec_mode, DnssecMode);
32
33static 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
62static 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
91static 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
115static 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
c69fa7e3
LP
145static 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
d2ec6608
LP
162int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_bus_error *error) {
163 _cleanup_free_ struct in_addr_data *dns = NULL;
164 size_t allocated = 0, n = 0;
165 Link *l = userdata;
166 unsigned i;
167 int r;
168
169 assert(message);
170 assert(l);
171
172 r = sd_bus_message_enter_container(message, 'a', "(iay)");
173 if (r < 0)
174 return r;
175
176 for (;;) {
177 int family;
178 size_t sz;
179 const void *d;
180
181 assert_cc(sizeof(int) == sizeof(int32_t));
182
183 r = sd_bus_message_enter_container(message, 'r', "iay");
184 if (r < 0)
185 return r;
186 if (r == 0)
187 break;
188
189 r = sd_bus_message_read(message, "i", &family);
190 if (r < 0)
191 return r;
192
193 if (!IN_SET(family, AF_INET, AF_INET6))
194 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family);
195
196 r = sd_bus_message_read_array(message, 'y', &d, &sz);
197 if (r < 0)
198 return r;
199 if (sz != FAMILY_ADDRESS_SIZE(family))
200 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid address size");
201
202 r = sd_bus_message_exit_container(message);
203 if (r < 0)
204 return r;
205
206 if (!GREEDY_REALLOC(dns, allocated, n+1))
207 return -ENOMEM;
208
209 dns[n].family = family;
210 memcpy(&dns[n].address, d, sz);
211 n++;
212 }
213
214 r = sd_bus_message_exit_container(message);
215 if (r < 0)
216 return r;
217
218 dns_server_mark_all(l->dns_servers);
219
220 for (i = 0; i < n; i++) {
221 DnsServer *s;
222
223 s = dns_server_find(l->dns_servers, dns[i].family, &dns[i].address);
224 if (s)
225 dns_server_move_back_and_unmark(s);
226 else {
227 r = dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, dns[i].family, &dns[i].address);
228 if (r < 0)
229 goto clear;
230 }
231
232 }
233
234 dns_server_unlink_marked(l->dns_servers);
235 link_allocate_scopes(l);
236
237 return sd_bus_reply_method_return(message, NULL);
238
239clear:
240 dns_server_unlink_all(l->dns_servers);
241 return r;
242}
243
244int bus_link_method_set_search_domains(sd_bus_message *message, void *userdata, sd_bus_error *error) {
245 _cleanup_free_ char **domains = NULL;
246 Link *l = userdata;
247 char **i;
248 int r;
249
250 assert(message);
251 assert(l);
252
253 r = sd_bus_message_read_strv(message, &domains);
254 if (r < 0)
255 return r;
256
257 STRV_FOREACH(i, domains) {
258
259 r = dns_name_is_valid(*i);
260 if (r < 0)
261 return r;
262 if (r == 0)
263 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid search domain %s", *i);
264 if (dns_name_is_root(*i))
265 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Root domain is not suitable as search domain");
266 }
267
268 dns_search_domain_mark_all(l->search_domains);
269
270 STRV_FOREACH(i, domains) {
271 DnsSearchDomain *d;
272
273 r = dns_search_domain_find(l->search_domains, *i, &d);
274 if (r < 0)
275 goto clear;
276
277 if (r > 0)
278 dns_search_domain_move_back_and_unmark(d);
279 else {
280 r = dns_search_domain_new(l->manager, NULL, DNS_SEARCH_DOMAIN_LINK, l, *i);
281 if (r < 0)
282 goto clear;
283 }
284 }
285
286 dns_search_domain_unlink_marked(l->search_domains);
287 return sd_bus_reply_method_return(message, NULL);
288
289clear:
290 dns_search_domain_unlink_all(l->search_domains);
291 return r;
292}
293
294int bus_link_method_set_llmnr(sd_bus_message *message, void *userdata, sd_bus_error *error) {
295 Link *l = userdata;
296 ResolveSupport mode;
297 const char *llmnr;
298 int r;
299
300 assert(message);
301 assert(l);
302
303 r = sd_bus_message_read(message, "s", &llmnr);
304 if (r < 0)
305 return r;
306
307 if (isempty(llmnr))
308 mode = RESOLVE_SUPPORT_YES;
309 else {
310 mode = resolve_support_from_string(llmnr);
311 if (mode < 0)
312 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid LLMNR setting: %s", llmnr);
313 }
314
315 l->llmnr_support = mode;
316 link_allocate_scopes(l);
317 link_add_rrs(l, false);
318
319 return sd_bus_reply_method_return(message, NULL);
320}
321
322int bus_link_method_set_mdns(sd_bus_message *message, void *userdata, sd_bus_error *error) {
323 Link *l = userdata;
324 ResolveSupport mode;
325 const char *mdns;
326 int r;
327
328 assert(message);
329 assert(l);
330
331 r = sd_bus_message_read(message, "s", &mdns);
332 if (r < 0)
333 return r;
334
335 if (isempty(mdns))
336 mode = RESOLVE_SUPPORT_NO;
337 else {
338 mode = resolve_support_from_string(mdns);
339 if (mode < 0)
340 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid MulticastDNS setting: %s", mdns);
341 }
342
343 l->mdns_support = mode;
344 link_allocate_scopes(l);
345 link_add_rrs(l, false);
346
347 return sd_bus_reply_method_return(message, NULL);
348}
349
350int bus_link_method_set_dnssec(sd_bus_message *message, void *userdata, sd_bus_error *error) {
351 Link *l = userdata;
352 const char *dnssec;
353 DnssecMode mode;
354 int r;
355
356 assert(message);
357 assert(l);
358
359 r = sd_bus_message_read(message, "s", &dnssec);
360 if (r < 0)
361 return r;
362
363 if (isempty(dnssec))
364 mode = _DNSSEC_MODE_INVALID;
365 else {
366 mode = dnssec_mode_from_string(dnssec);
367 if (mode < 0)
368 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid DNSSEC setting: %s", dnssec);
369 }
370
371 link_set_dnssec_mode(l, mode);
372
373 return sd_bus_reply_method_return(message, NULL);
374}
375
376int bus_link_method_set_dnssec_negative_trust_anchors(sd_bus_message *message, void *userdata, sd_bus_error *error) {
377 _cleanup_set_free_free_ Set *ns = NULL;
378 _cleanup_free_ char **ntas = NULL;
379 Link *l = userdata;
380 int r;
381 char **i;
382
383 assert(message);
384 assert(l);
385
386 r = sd_bus_message_read_strv(message, &ntas);
387 if (r < 0)
388 return r;
389
390 STRV_FOREACH(i, ntas) {
391 r = dns_name_is_valid(*i);
392 if (r < 0)
393 return r;
394 if (r == 0)
395 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid search negative trust anchor domain: %s", *i);
396 }
397
398 ns = set_new(&dns_name_hash_ops);
399 if (!ns)
400 return -ENOMEM;
401
402 STRV_FOREACH(i, ntas) {
403 r = set_put_strdup(ns, *i);
404 if (r < 0)
405 return r;
406 }
407
408 set_free_free(l->dnssec_negative_trust_anchors);
409 l->dnssec_negative_trust_anchors = ns;
410 ns = NULL;
411
412 return sd_bus_reply_method_return(message, NULL);
413}
414
415int bus_link_method_revert(sd_bus_message *message, void *userdata, sd_bus_error *error) {
416 Link *l = userdata;
417
418 assert(message);
419 assert(l);
420
421 link_flush_settings(l);
422 link_allocate_scopes(l);
423 link_add_rrs(l, false);
424
425 return sd_bus_reply_method_return(message, NULL);
426}
427
3abaabda
LP
428const sd_bus_vtable link_vtable[] = {
429 SD_BUS_VTABLE_START(0),
430
431 SD_BUS_PROPERTY("ScopesMask", "t", property_get_scopes_mask, 0, 0),
432 SD_BUS_PROPERTY("DNS", "a(iay)", property_get_dns, 0, 0),
433 SD_BUS_PROPERTY("Domains", "as", property_get_domains, 0, 0),
434 SD_BUS_PROPERTY("LLMNR", "s", property_get_resolve_support, offsetof(Link, llmnr_support), 0),
435 SD_BUS_PROPERTY("MulticastDNS", "s", property_get_resolve_support, offsetof(Link, mdns_support), 0),
436 SD_BUS_PROPERTY("DNSSEC", "s", property_get_dnssec_mode, offsetof(Link, dnssec_mode), 0),
437 SD_BUS_PROPERTY("DNSSECNegativeTrustAnchors", "as", property_get_ntas, 0, 0),
c69fa7e3 438 SD_BUS_PROPERTY("DNSSECSupport", "b", property_get_dnssec_supported, 0, 0),
3abaabda 439
d2ec6608
LP
440 SD_BUS_METHOD("SetDNS", "a(iay)", NULL, bus_link_method_set_dns_servers, 0),
441 SD_BUS_METHOD("SetDomains", "as", NULL, bus_link_method_set_search_domains, 0),
442 SD_BUS_METHOD("SetLLMNR", "s", NULL, bus_link_method_set_llmnr, 0),
443 SD_BUS_METHOD("SetMulticastDNS", "s", NULL, bus_link_method_set_mdns, 0),
444 SD_BUS_METHOD("SetDNSSEC", "s", NULL, bus_link_method_set_dnssec, 0),
445 SD_BUS_METHOD("SetDNSSECNegativeTrustAnchors", "as", NULL, bus_link_method_set_dnssec_negative_trust_anchors, 0),
446 SD_BUS_METHOD("Revert", NULL, NULL, bus_link_method_revert, 0),
447
3abaabda
LP
448 SD_BUS_VTABLE_END
449};
450
451int link_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
452 _cleanup_free_ char *e = NULL;
453 Manager *m = userdata;
454 int ifindex;
455 Link *link;
456 int r;
457
458 assert(bus);
459 assert(path);
460 assert(interface);
461 assert(found);
462 assert(m);
463
464 r = sd_bus_path_decode(path, "/org/freedesktop/resolve1/link", &e);
465 if (r <= 0)
466 return 0;
467
468 r = parse_ifindex(e, &ifindex);
469 if (r < 0)
470 return 0;
471
472 link = hashmap_get(m->links, INT_TO_PTR(ifindex));
473 if (!link)
474 return 0;
475
476 *found = link;
477 return 1;
478}
479
480char *link_bus_path(Link *link) {
481 _cleanup_free_ char *ifindex = NULL;
482 char *p;
483 int r;
484
485 assert(link);
486
487 if (asprintf(&ifindex, "%i", link->ifindex) < 0)
488 return NULL;
489
490 r = sd_bus_path_encode("/org/freedesktop/resolve1/link", ifindex, &p);
491 if (r < 0)
492 return NULL;
493
494 return p;
495}
496
497int link_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
498 _cleanup_strv_free_ char **l = NULL;
499 Manager *m = userdata;
500 Link *link;
501 Iterator i;
502 unsigned c = 0;
503
504 assert(bus);
505 assert(path);
506 assert(m);
507 assert(nodes);
508
509 l = new0(char*, hashmap_size(m->links) + 1);
510 if (!l)
511 return -ENOMEM;
512
513 HASHMAP_FOREACH(link, m->links, i) {
514 char *p;
515
516 p = link_bus_path(link);
517 if (!p)
518 return -ENOMEM;
519
520 l[c++] = p;
521 }
522
523 l[c] = NULL;
524 *nodes = l;
525 l = NULL;
526
527 return 1;
528}