]> git.proxmox.com Git - systemd.git/blame - src/resolve/resolved-bus.c
Merge tag 'upstream/229'
[systemd.git] / src / resolve / resolved-bus.c
CommitLineData
5eef597e
MP
1/***
2 This file is part of systemd.
3
4 Copyright 2014 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
db2df898 20#include "alloc-util.h"
f47781d8 21#include "bus-common-errors.h"
5eef597e 22#include "bus-util.h"
86f210e9 23#include "dns-domain.h"
5eef597e
MP
24#include "resolved-bus.h"
25#include "resolved-def.h"
4c89c718 26#include "resolved-link-bus.h"
5eef597e
MP
27
28static int reply_query_state(DnsQuery *q) {
5eef597e
MP
29
30 switch (q->state) {
31
32 case DNS_TRANSACTION_NO_SERVERS:
33 return sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_NAME_SERVERS, "No appropriate name servers or networks for name found");
34
35 case DNS_TRANSACTION_TIMEOUT:
36 return sd_bus_reply_method_errorf(q->request, SD_BUS_ERROR_TIMEOUT, "Query timed out");
37
38 case DNS_TRANSACTION_ATTEMPTS_MAX_REACHED:
39 return sd_bus_reply_method_errorf(q->request, SD_BUS_ERROR_TIMEOUT, "All attempts to contact name servers or networks failed");
40
41 case DNS_TRANSACTION_INVALID_REPLY:
42 return sd_bus_reply_method_errorf(q->request, BUS_ERROR_INVALID_REPLY, "Received invalid reply");
43
4c89c718
MP
44 case DNS_TRANSACTION_ERRNO:
45 return sd_bus_reply_method_errnof(q->request, q->answer_errno, "Lookup failed due to system error: %m");
5eef597e
MP
46
47 case DNS_TRANSACTION_ABORTED:
48 return sd_bus_reply_method_errorf(q->request, BUS_ERROR_ABORTED, "Query aborted");
49
4c89c718
MP
50 case DNS_TRANSACTION_DNSSEC_FAILED:
51 return sd_bus_reply_method_errorf(q->request, BUS_ERROR_DNSSEC_FAILED, "DNSSEC validation failed: %s",
52 dnssec_result_to_string(q->answer_dnssec_result));
53
54 case DNS_TRANSACTION_NO_TRUST_ANCHOR:
55 return sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_TRUST_ANCHOR, "No suitable trust anchor known");
56
57 case DNS_TRANSACTION_RR_TYPE_UNSUPPORTED:
58 return sd_bus_reply_method_errorf(q->request, BUS_ERROR_RR_TYPE_UNSUPPORTED, "Server does not support requested resource record type");
59
60 case DNS_TRANSACTION_NETWORK_DOWN:
61 return sd_bus_reply_method_errorf(q->request, BUS_ERROR_NETWORK_DOWN, "Network is down");
62
63 case DNS_TRANSACTION_NOT_FOUND:
64 /* We return this as NXDOMAIN. This is only generated when a host doesn't implement LLMNR/TCP, and we
65 * thus quickly know that we cannot resolve an in-addr.arpa or ip6.arpa address. */
66 return sd_bus_reply_method_errorf(q->request, _BUS_ERROR_DNS "NXDOMAIN", "'%s' not found", dns_query_string(q));
67
68 case DNS_TRANSACTION_RCODE_FAILURE: {
69 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
5eef597e
MP
70
71 if (q->answer_rcode == DNS_RCODE_NXDOMAIN)
4c89c718 72 sd_bus_error_setf(&error, _BUS_ERROR_DNS "NXDOMAIN", "'%s' not found", dns_query_string(q));
5eef597e
MP
73 else {
74 const char *rc, *n;
4c89c718 75 char p[DECIMAL_STR_MAX(q->answer_rcode)];
5eef597e
MP
76
77 rc = dns_rcode_to_string(q->answer_rcode);
78 if (!rc) {
79 sprintf(p, "%i", q->answer_rcode);
80 rc = p;
81 }
82
e735f4d4 83 n = strjoina(_BUS_ERROR_DNS, rc);
4c89c718 84 sd_bus_error_setf(&error, n, "Could not resolve '%s', server or network returned error %s", dns_query_string(q), rc);
5eef597e
MP
85 }
86
87 return sd_bus_reply_method_error(q->request, &error);
88 }
89
90 case DNS_TRANSACTION_NULL:
91 case DNS_TRANSACTION_PENDING:
4c89c718 92 case DNS_TRANSACTION_VALIDATING:
5eef597e
MP
93 case DNS_TRANSACTION_SUCCESS:
94 default:
95 assert_not_reached("Impossible state");
96 }
97}
98
13d276d0 99static int append_address(sd_bus_message *reply, DnsResourceRecord *rr, int ifindex) {
5eef597e
MP
100 int r;
101
102 assert(reply);
103 assert(rr);
104
13d276d0
MP
105 r = sd_bus_message_open_container(reply, 'r', "iiay");
106 if (r < 0)
107 return r;
108
109 r = sd_bus_message_append(reply, "i", ifindex);
5eef597e
MP
110 if (r < 0)
111 return r;
112
113 if (rr->key->type == DNS_TYPE_A) {
114 r = sd_bus_message_append(reply, "i", AF_INET);
115 if (r < 0)
116 return r;
117
118 r = sd_bus_message_append_array(reply, 'y', &rr->a.in_addr, sizeof(struct in_addr));
119
120 } else if (rr->key->type == DNS_TYPE_AAAA) {
121 r = sd_bus_message_append(reply, "i", AF_INET6);
122 if (r < 0)
123 return r;
124
125 r = sd_bus_message_append_array(reply, 'y', &rr->aaaa.in6_addr, sizeof(struct in6_addr));
126 } else
127 return -EAFNOSUPPORT;
128
129 if (r < 0)
130 return r;
131
132 r = sd_bus_message_close_container(reply);
133 if (r < 0)
134 return r;
135
136 return 0;
137}
138
139static void bus_method_resolve_hostname_complete(DnsQuery *q) {
4c89c718
MP
140 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *canonical = NULL;
141 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
142 DnsResourceRecord *rr;
143 unsigned added = 0;
144 int ifindex, r;
5eef597e
MP
145
146 assert(q);
147
148 if (q->state != DNS_TRANSACTION_SUCCESS) {
149 r = reply_query_state(q);
150 goto finish;
151 }
152
4c89c718
MP
153 r = dns_query_process_cname(q);
154 if (r == -ELOOP) {
155 r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_CNAME_LOOP, "CNAME loop detected, or CNAME resolving disabled on '%s'", dns_query_string(q));
156 goto finish;
157 }
158 if (r < 0)
159 goto finish;
160 if (r == DNS_QUERY_RESTARTED) /* This was a cname, and the query was restarted. */
161 return;
162
5eef597e
MP
163 r = sd_bus_message_new_method_return(q->request, &reply);
164 if (r < 0)
165 goto finish;
166
13d276d0 167 r = sd_bus_message_open_container(reply, 'a', "(iiay)");
5eef597e
MP
168 if (r < 0)
169 goto finish;
170
4c89c718
MP
171 DNS_ANSWER_FOREACH_IFINDEX(rr, ifindex, q->answer) {
172 DnsQuestion *question;
5eef597e 173
4c89c718 174 question = dns_query_question_for_protocol(q, q->answer_protocol);
5eef597e 175
4c89c718
MP
176 r = dns_question_matches_rr(question, rr, DNS_SEARCH_DOMAIN_NAME(q->answer_search_domain));
177 if (r < 0)
5eef597e 178 goto finish;
4c89c718
MP
179 if (r == 0)
180 continue;
5eef597e 181
4c89c718
MP
182 r = append_address(reply, rr, ifindex);
183 if (r < 0)
5eef597e 184 goto finish;
5eef597e 185
4c89c718
MP
186 if (!canonical)
187 canonical = dns_resource_record_ref(rr);
5eef597e 188
4c89c718
MP
189 added ++;
190 }
5eef597e 191
4c89c718
MP
192 if (added <= 0) {
193 r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR, "'%s' does not have any RR of the requested type", dns_query_string(q));
194 goto finish;
5eef597e
MP
195 }
196
197 r = sd_bus_message_close_container(reply);
198 if (r < 0)
199 goto finish;
200
4c89c718 201 /* Return the precise spelling and uppercasing and CNAME target reported by the server */
5eef597e 202 assert(canonical);
4c89c718
MP
203 r = sd_bus_message_append(
204 reply, "st",
205 DNS_RESOURCE_KEY_NAME(canonical->key),
206 SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family, q->answer_authenticated));
5eef597e
MP
207 if (r < 0)
208 goto finish;
209
210 r = sd_bus_send(q->manager->bus, reply, NULL);
211
212finish:
213 if (r < 0) {
f47781d8 214 log_error_errno(r, "Failed to send hostname reply: %m");
4c89c718 215 sd_bus_reply_method_errno(q->request, r, NULL);
5eef597e
MP
216 }
217
218 dns_query_free(q);
219}
220
4c89c718 221static int check_ifindex_flags(int ifindex, uint64_t *flags, uint64_t ok, sd_bus_error *error) {
5eef597e
MP
222 assert(flags);
223
224 if (ifindex < 0)
225 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface index");
226
4c89c718 227 if (*flags & ~(SD_RESOLVED_PROTOCOLS_ALL|SD_RESOLVED_NO_CNAME|ok))
5eef597e
MP
228 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid flags parameter");
229
4c89c718
MP
230 if ((*flags & SD_RESOLVED_PROTOCOLS_ALL) == 0) /* If no protocol is enabled, enable all */
231 *flags |= SD_RESOLVED_PROTOCOLS_ALL;
5eef597e
MP
232
233 return 0;
234}
235
e3bff60a 236static int bus_method_resolve_hostname(sd_bus_message *message, void *userdata, sd_bus_error *error) {
4c89c718 237 _cleanup_(dns_question_unrefp) DnsQuestion *question_idna = NULL, *question_utf8 = NULL;
5eef597e
MP
238 Manager *m = userdata;
239 const char *hostname;
240 int family, ifindex;
241 uint64_t flags;
242 DnsQuery *q;
243 int r;
244
5eef597e
MP
245 assert(message);
246 assert(m);
247
4c89c718
MP
248 assert_cc(sizeof(int) == sizeof(int32_t));
249
5eef597e
MP
250 r = sd_bus_message_read(message, "isit", &ifindex, &hostname, &family, &flags);
251 if (r < 0)
252 return r;
253
254 if (!IN_SET(family, AF_INET, AF_INET6, AF_UNSPEC))
255 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family);
256
4c89c718 257 r = dns_name_is_valid(hostname);
5eef597e 258 if (r < 0)
4c89c718
MP
259 return r;
260 if (r == 0)
5eef597e
MP
261 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid hostname '%s'", hostname);
262
4c89c718 263 r = check_ifindex_flags(ifindex, &flags, SD_RESOLVED_NO_SEARCH, error);
5eef597e
MP
264 if (r < 0)
265 return r;
266
4c89c718
MP
267 r = dns_question_new_address(&question_utf8, family, hostname, false);
268 if (r < 0)
269 return r;
5eef597e 270
4c89c718
MP
271 r = dns_question_new_address(&question_idna, family, hostname, true);
272 if (r < 0)
273 return r;
5eef597e 274
4c89c718 275 r = dns_query_new(m, &q, question_utf8, question_idna, ifindex, flags);
5eef597e
MP
276 if (r < 0)
277 return r;
278
279 q->request = sd_bus_message_ref(message);
280 q->request_family = family;
5eef597e 281 q->complete = bus_method_resolve_hostname_complete;
4c89c718 282 q->suppress_unroutable_family = family == AF_UNSPEC;
5eef597e 283
e3bff60a 284 r = dns_query_bus_track(q, message);
5eef597e 285 if (r < 0)
4c89c718 286 goto fail;
5eef597e
MP
287
288 r = dns_query_go(q);
4c89c718
MP
289 if (r < 0)
290 goto fail;
5eef597e
MP
291
292 return 1;
4c89c718
MP
293
294fail:
295 dns_query_free(q);
296 return r;
5eef597e
MP
297}
298
299static void bus_method_resolve_address_complete(DnsQuery *q) {
4c89c718
MP
300 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
301 DnsQuestion *question;
302 DnsResourceRecord *rr;
303 unsigned added = 0;
304 int ifindex, r;
5eef597e
MP
305
306 assert(q);
307
308 if (q->state != DNS_TRANSACTION_SUCCESS) {
309 r = reply_query_state(q);
310 goto finish;
311 }
312
4c89c718
MP
313 r = dns_query_process_cname(q);
314 if (r == -ELOOP) {
315 r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_CNAME_LOOP, "CNAME loop detected, or CNAME resolving disabled on '%s'", dns_query_string(q));
316 goto finish;
317 }
318 if (r < 0)
319 goto finish;
320 if (r == DNS_QUERY_RESTARTED) /* This was a cname, and the query was restarted. */
321 return;
322
5eef597e
MP
323 r = sd_bus_message_new_method_return(q->request, &reply);
324 if (r < 0)
325 goto finish;
326
13d276d0 327 r = sd_bus_message_open_container(reply, 'a', "(is)");
5eef597e
MP
328 if (r < 0)
329 goto finish;
330
4c89c718 331 question = dns_query_question_for_protocol(q, q->answer_protocol);
5eef597e 332
4c89c718
MP
333 DNS_ANSWER_FOREACH_IFINDEX(rr, ifindex, q->answer) {
334 r = dns_question_matches_rr(question, rr, NULL);
335 if (r < 0)
336 goto finish;
337 if (r == 0)
338 continue;
5eef597e 339
4c89c718
MP
340 r = sd_bus_message_append(reply, "(is)", ifindex, rr->ptr.name);
341 if (r < 0)
342 goto finish;
5eef597e 343
4c89c718 344 added ++;
5eef597e
MP
345 }
346
4c89c718 347 if (added <= 0) {
5eef597e
MP
348 _cleanup_free_ char *ip = NULL;
349
350 in_addr_to_string(q->request_family, &q->request_address, &ip);
4c89c718 351 r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR, "Address '%s' does not have any RR of requested type", strna(ip));
5eef597e
MP
352 goto finish;
353 }
354
355 r = sd_bus_message_close_container(reply);
356 if (r < 0)
357 goto finish;
358
4c89c718 359 r = sd_bus_message_append(reply, "t", SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family, q->answer_authenticated));
5eef597e
MP
360 if (r < 0)
361 goto finish;
362
363 r = sd_bus_send(q->manager->bus, reply, NULL);
364
365finish:
366 if (r < 0) {
f47781d8 367 log_error_errno(r, "Failed to send address reply: %m");
4c89c718 368 sd_bus_reply_method_errno(q->request, r, NULL);
5eef597e
MP
369 }
370
371 dns_query_free(q);
372}
373
e3bff60a 374static int bus_method_resolve_address(sd_bus_message *message, void *userdata, sd_bus_error *error) {
5eef597e 375 _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
5eef597e
MP
376 Manager *m = userdata;
377 int family, ifindex;
378 uint64_t flags;
379 const void *d;
380 DnsQuery *q;
381 size_t sz;
382 int r;
383
5eef597e
MP
384 assert(message);
385 assert(m);
386
4c89c718
MP
387 assert_cc(sizeof(int) == sizeof(int32_t));
388
5eef597e
MP
389 r = sd_bus_message_read(message, "ii", &ifindex, &family);
390 if (r < 0)
391 return r;
392
393 if (!IN_SET(family, AF_INET, AF_INET6))
394 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family);
395
396 r = sd_bus_message_read_array(message, 'y', &d, &sz);
397 if (r < 0)
398 return r;
399
400 if (sz != FAMILY_ADDRESS_SIZE(family))
401 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid address size");
402
403 r = sd_bus_message_read(message, "t", &flags);
404 if (r < 0)
405 return r;
406
4c89c718 407 r = check_ifindex_flags(ifindex, &flags, 0, error);
5eef597e
MP
408 if (r < 0)
409 return r;
410
4c89c718 411 r = dns_question_new_reverse(&question, family, d);
5eef597e
MP
412 if (r < 0)
413 return r;
414
4c89c718 415 r = dns_query_new(m, &q, question, question, ifindex, flags|SD_RESOLVED_NO_SEARCH);
5eef597e
MP
416 if (r < 0)
417 return r;
418
419 q->request = sd_bus_message_ref(message);
420 q->request_family = family;
421 memcpy(&q->request_address, d, sz);
422 q->complete = bus_method_resolve_address_complete;
423
e3bff60a 424 r = dns_query_bus_track(q, message);
5eef597e 425 if (r < 0)
4c89c718 426 goto fail;
5eef597e
MP
427
428 r = dns_query_go(q);
4c89c718
MP
429 if (r < 0)
430 goto fail;
5eef597e
MP
431
432 return 1;
4c89c718
MP
433
434fail:
435 dns_query_free(q);
436 return r;
437}
438
439static int bus_message_append_rr(sd_bus_message *m, DnsResourceRecord *rr, int ifindex) {
440 int r;
441
442 assert(m);
443 assert(rr);
444
445 r = sd_bus_message_open_container(m, 'r', "iqqay");
446 if (r < 0)
447 return r;
448
449 r = sd_bus_message_append(m, "iqq",
450 ifindex,
451 rr->key->class,
452 rr->key->type);
453 if (r < 0)
454 return r;
455
456 r = dns_resource_record_to_wire_format(rr, false);
457 if (r < 0)
458 return r;
459
460 r = sd_bus_message_append_array(m, 'y', rr->wire_format, rr->wire_format_size);
461 if (r < 0)
462 return r;
463
464 return sd_bus_message_close_container(m);
5eef597e
MP
465}
466
467static void bus_method_resolve_record_complete(DnsQuery *q) {
4c89c718
MP
468 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
469 DnsResourceRecord *rr;
470 DnsQuestion *question;
471 unsigned added = 0;
472 int ifindex;
5eef597e
MP
473 int r;
474
475 assert(q);
476
477 if (q->state != DNS_TRANSACTION_SUCCESS) {
478 r = reply_query_state(q);
479 goto finish;
480 }
481
4c89c718
MP
482 r = dns_query_process_cname(q);
483 if (r == -ELOOP) {
484 r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_CNAME_LOOP, "CNAME loop detected, or CNAME resolving disabled on '%s'", dns_query_string(q));
485 goto finish;
486 }
487 if (r < 0)
488 goto finish;
489 if (r == DNS_QUERY_RESTARTED) /* This was a cname, and the query was restarted. */
490 return;
491
5eef597e
MP
492 r = sd_bus_message_new_method_return(q->request, &reply);
493 if (r < 0)
494 goto finish;
495
13d276d0 496 r = sd_bus_message_open_container(reply, 'a', "(iqqay)");
5eef597e
MP
497 if (r < 0)
498 goto finish;
499
4c89c718 500 question = dns_query_question_for_protocol(q, q->answer_protocol);
5eef597e 501
4c89c718
MP
502 DNS_ANSWER_FOREACH_IFINDEX(rr, ifindex, q->answer) {
503 r = dns_question_matches_rr(question, rr, NULL);
504 if (r < 0)
505 goto finish;
506 if (r == 0)
507 continue;
5eef597e 508
4c89c718
MP
509 r = bus_message_append_rr(reply, rr, ifindex);
510 if (r < 0)
511 goto finish;
5eef597e 512
4c89c718 513 added ++;
5eef597e
MP
514 }
515
516 if (added <= 0) {
4c89c718 517 r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR, "Name '%s' does not have any RR of the requested type", dns_query_string(q));
5eef597e
MP
518 goto finish;
519 }
520
521 r = sd_bus_message_close_container(reply);
522 if (r < 0)
523 goto finish;
524
4c89c718 525 r = sd_bus_message_append(reply, "t", SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family, q->answer_authenticated));
5eef597e
MP
526 if (r < 0)
527 goto finish;
528
529 r = sd_bus_send(q->manager->bus, reply, NULL);
530
531finish:
532 if (r < 0) {
f47781d8 533 log_error_errno(r, "Failed to send record reply: %m");
4c89c718 534 sd_bus_reply_method_errno(q->request, r, NULL);
5eef597e
MP
535 }
536
537 dns_query_free(q);
538}
539
e3bff60a 540static int bus_method_resolve_record(sd_bus_message *message, void *userdata, sd_bus_error *error) {
5eef597e
MP
541 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
542 _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
543 Manager *m = userdata;
544 uint16_t class, type;
545 const char *name;
546 int r, ifindex;
547 uint64_t flags;
548 DnsQuery *q;
549
5eef597e
MP
550 assert(message);
551 assert(m);
552
4c89c718
MP
553 assert_cc(sizeof(int) == sizeof(int32_t));
554
5eef597e
MP
555 r = sd_bus_message_read(message, "isqqt", &ifindex, &name, &class, &type, &flags);
556 if (r < 0)
557 return r;
558
4c89c718 559 r = dns_name_is_valid(name);
5eef597e 560 if (r < 0)
4c89c718
MP
561 return r;
562 if (r == 0)
5eef597e
MP
563 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid name '%s'", name);
564
4c89c718
MP
565 if (!dns_type_is_valid_query(type))
566 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Specified resource record type %" PRIu16 " may not be used in a query.", type);
567 if (dns_type_is_obsolete(type))
568 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Specified DNS resource record type %" PRIu16 " is obsolete.", type);
569
570 r = check_ifindex_flags(ifindex, &flags, 0, error);
5eef597e
MP
571 if (r < 0)
572 return r;
573
574 question = dns_question_new(1);
575 if (!question)
576 return -ENOMEM;
577
578 key = dns_resource_key_new(class, type, name);
579 if (!key)
580 return -ENOMEM;
581
582 r = dns_question_add(question, key);
583 if (r < 0)
584 return r;
585
4c89c718 586 r = dns_query_new(m, &q, question, question, ifindex, flags|SD_RESOLVED_NO_SEARCH);
5eef597e
MP
587 if (r < 0)
588 return r;
589
590 q->request = sd_bus_message_ref(message);
5eef597e
MP
591 q->complete = bus_method_resolve_record_complete;
592
e3bff60a 593 r = dns_query_bus_track(q, message);
5eef597e 594 if (r < 0)
4c89c718 595 goto fail;
5eef597e
MP
596
597 r = dns_query_go(q);
4c89c718
MP
598 if (r < 0)
599 goto fail;
5eef597e
MP
600
601 return 1;
4c89c718
MP
602
603fail:
604 dns_query_free(q);
605 return r;
5eef597e
MP
606}
607
4c89c718
MP
608static int append_srv(DnsQuery *q, sd_bus_message *reply, DnsResourceRecord *rr) {
609 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *canonical = NULL;
610 DnsQuery *aux;
611 int r;
5eef597e 612
4c89c718
MP
613 assert(q);
614 assert(reply);
615 assert(rr);
616 assert(rr->key);
5eef597e 617
4c89c718
MP
618 if (rr->key->type != DNS_TYPE_SRV)
619 return 0;
5eef597e 620
4c89c718
MP
621 if ((q->flags & SD_RESOLVED_NO_ADDRESS) == 0) {
622 /* First, let's see if we could find an appropriate A or AAAA
623 * record for the SRV record */
624 LIST_FOREACH(auxiliary_queries, aux, q->auxiliary_queries) {
625 DnsResourceRecord *zz;
626 DnsQuestion *question;
5eef597e 627
4c89c718
MP
628 if (aux->state != DNS_TRANSACTION_SUCCESS)
629 continue;
630 if (aux->auxiliary_result != 0)
631 continue;
5eef597e 632
4c89c718 633 question = dns_query_question_for_protocol(aux, aux->answer_protocol);
5eef597e 634
4c89c718
MP
635 r = dns_name_equal(dns_question_first_name(question), rr->srv.name);
636 if (r < 0)
637 return r;
638 if (r == 0)
639 continue;
5eef597e 640
4c89c718 641 DNS_ANSWER_FOREACH(zz, aux->answer) {
5eef597e 642
4c89c718
MP
643 r = dns_question_matches_rr(question, zz, NULL);
644 if (r < 0)
645 return r;
646 if (r == 0)
647 continue;
5eef597e 648
4c89c718
MP
649 canonical = dns_resource_record_ref(zz);
650 break;
651 }
5eef597e 652
4c89c718
MP
653 if (canonical)
654 break;
655 }
5eef597e 656
4c89c718
MP
657 /* Is there are successful A/AAAA lookup for this SRV RR? If not, don't add it */
658 if (!canonical)
659 return 0;
660 }
5eef597e 661
4c89c718
MP
662 r = sd_bus_message_open_container(reply, 'r', "qqqsa(iiay)s");
663 if (r < 0)
664 return r;
5eef597e 665
4c89c718
MP
666 r = sd_bus_message_append(
667 reply,
668 "qqqs",
669 rr->srv.priority, rr->srv.weight, rr->srv.port, rr->srv.name);
670 if (r < 0)
671 return r;
5eef597e 672
4c89c718
MP
673 r = sd_bus_message_open_container(reply, 'a', "(iiay)");
674 if (r < 0)
675 return r;
5eef597e 676
4c89c718
MP
677 if ((q->flags & SD_RESOLVED_NO_ADDRESS) == 0) {
678 LIST_FOREACH(auxiliary_queries, aux, q->auxiliary_queries) {
679 DnsResourceRecord *zz;
680 DnsQuestion *question;
681 int ifindex;
5eef597e 682
4c89c718
MP
683 if (aux->state != DNS_TRANSACTION_SUCCESS)
684 continue;
685 if (aux->auxiliary_result != 0)
686 continue;
5eef597e 687
4c89c718 688 question = dns_query_question_for_protocol(aux, aux->answer_protocol);
5eef597e 689
4c89c718
MP
690 r = dns_name_equal(dns_question_first_name(question), rr->srv.name);
691 if (r < 0)
692 return r;
693 if (r == 0)
694 continue;
695
696 DNS_ANSWER_FOREACH_IFINDEX(zz, ifindex, aux->answer) {
697
698 r = dns_question_matches_rr(question, zz, NULL);
699 if (r < 0)
700 return r;
701 if (r == 0)
702 continue;
703
704 r = append_address(reply, zz, ifindex);
705 if (r < 0)
706 return r;
707 }
708 }
709 }
710
711 r = sd_bus_message_close_container(reply);
712 if (r < 0)
713 return r;
714
715 /* Note that above we appended the hostname as encoded in the
716 * SRV, and here the canonical hostname this maps to. */
717 r = sd_bus_message_append(reply, "s", canonical ? DNS_RESOURCE_KEY_NAME(canonical->key) : rr->srv.name);
718 if (r < 0)
719 return r;
720
721 r = sd_bus_message_close_container(reply);
722 if (r < 0)
723 return r;
724
725 return 1;
726}
727
728static int append_txt(sd_bus_message *reply, DnsResourceRecord *rr) {
729 DnsTxtItem *i;
730 int r;
731
732 assert(reply);
733 assert(rr);
734 assert(rr->key);
735
736 if (rr->key->type != DNS_TYPE_TXT)
737 return 0;
738
739 LIST_FOREACH(items, i, rr->txt.items) {
740
741 if (i->length <= 0)
742 continue;
743
744 r = sd_bus_message_append_array(reply, 'y', i->data, i->length);
745 if (r < 0)
746 return r;
747 }
748
749 return 1;
750}
751
752static void resolve_service_all_complete(DnsQuery *q) {
753 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *canonical = NULL;
754 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
755 _cleanup_free_ char *name = NULL, *type = NULL, *domain = NULL;
756 DnsQuestion *question;
757 DnsResourceRecord *rr;
758 unsigned added = 0;
759 DnsQuery *aux;
760 int r;
761
762 assert(q);
763
764 if (q->block_all_complete > 0)
765 return;
766
767 if ((q->flags & SD_RESOLVED_NO_ADDRESS) == 0) {
768 DnsQuery *bad = NULL;
769 bool have_success = false;
770
771 LIST_FOREACH(auxiliary_queries, aux, q->auxiliary_queries) {
772
773 switch (aux->state) {
774
775 case DNS_TRANSACTION_PENDING:
776 /* If an auxiliary query is still pending, let's wait */
777 return;
778
779 case DNS_TRANSACTION_SUCCESS:
780 if (aux->auxiliary_result == 0)
781 have_success = true;
782 else
783 bad = aux;
784 break;
785
786 default:
787 bad = aux;
788 break;
789 }
790 }
791
792 if (!have_success) {
793 /* We can only return one error, hence pick the last error we encountered */
794
795 assert(bad);
796
797 if (bad->state == DNS_TRANSACTION_SUCCESS) {
798 assert(bad->auxiliary_result != 0);
799
800 if (bad->auxiliary_result == -ELOOP) {
801 r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_CNAME_LOOP, "CNAME loop detected, or CNAME resolving disabled on '%s'", dns_query_string(bad));
802 goto finish;
803 }
804
805 r = bad->auxiliary_result;
806 goto finish;
807 }
808
809 r = reply_query_state(bad);
810 goto finish;
811 }
812 }
813
814 r = sd_bus_message_new_method_return(q->request, &reply);
815 if (r < 0)
816 goto finish;
817
818 r = sd_bus_message_open_container(reply, 'a', "(qqqsa(iiay)s)");
819 if (r < 0)
820 goto finish;
821
822 question = dns_query_question_for_protocol(q, q->answer_protocol);
823 DNS_ANSWER_FOREACH(rr, q->answer) {
824 r = dns_question_matches_rr(question, rr, NULL);
825 if (r < 0)
826 goto finish;
827 if (r == 0)
828 continue;
829
830 r = append_srv(q, reply, rr);
831 if (r < 0)
832 goto finish;
833 if (r == 0) /* not an SRV record */
834 continue;
835
836 if (!canonical)
837 canonical = dns_resource_record_ref(rr);
838
839 added++;
840 }
841
842 if (added <= 0) {
843 r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR, "'%s' does not have any RR of the requested type", dns_query_string(q));
844 goto finish;
845 }
846
847 r = sd_bus_message_close_container(reply);
848 if (r < 0)
849 goto finish;
850
851 r = sd_bus_message_open_container(reply, 'a', "ay");
852 if (r < 0)
853 goto finish;
854
855 DNS_ANSWER_FOREACH(rr, q->answer) {
856 r = dns_question_matches_rr(question, rr, NULL);
857 if (r < 0)
858 goto finish;
859 if (r == 0)
860 continue;
861
862 r = append_txt(reply, rr);
863 if (r < 0)
864 goto finish;
865 }
866
867 r = sd_bus_message_close_container(reply);
868 if (r < 0)
869 goto finish;
870
871 assert(canonical);
872 r = dns_service_split(DNS_RESOURCE_KEY_NAME(canonical->key), &name, &type, &domain);
873 if (r < 0)
874 goto finish;
875
876 r = sd_bus_message_append(
877 reply,
878 "ssst",
879 name, type, domain,
880 SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family, q->answer_authenticated));
881 if (r < 0)
882 goto finish;
883
884 r = sd_bus_send(q->manager->bus, reply, NULL);
885
886finish:
887 if (r < 0) {
888 log_error_errno(r, "Failed to send service reply: %m");
889 sd_bus_reply_method_errno(q->request, r, NULL);
890 }
891
892 dns_query_free(q);
893}
894
895static void resolve_service_hostname_complete(DnsQuery *q) {
896 int r;
897
898 assert(q);
899 assert(q->auxiliary_for);
900
901 if (q->state != DNS_TRANSACTION_SUCCESS) {
902 resolve_service_all_complete(q->auxiliary_for);
903 return;
904 }
905
906 r = dns_query_process_cname(q);
907 if (r == DNS_QUERY_RESTARTED) /* This was a cname, and the query was restarted. */
908 return;
909
910 /* This auxiliary lookup is finished or failed, let's see if all are finished now. */
911 q->auxiliary_result = r;
912 resolve_service_all_complete(q->auxiliary_for);
913}
914
915static int resolve_service_hostname(DnsQuery *q, DnsResourceRecord *rr, int ifindex) {
916 _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
917 DnsQuery *aux;
918 int r;
919
920 assert(q);
921 assert(rr);
922 assert(rr->key);
923 assert(rr->key->type == DNS_TYPE_SRV);
924
925 /* OK, we found an SRV record for the service. Let's resolve
926 * the hostname included in it */
927
928 r = dns_question_new_address(&question, q->request_family, rr->srv.name, false);
929 if (r < 0)
930 return r;
931
932 r = dns_query_new(q->manager, &aux, question, question, ifindex, q->flags|SD_RESOLVED_NO_SEARCH);
933 if (r < 0)
934 return r;
935
936 aux->request_family = q->request_family;
937 aux->complete = resolve_service_hostname_complete;
938
939 r = dns_query_make_auxiliary(aux, q);
940 if (r == -EAGAIN) {
941 /* Too many auxiliary lookups? If so, don't complain,
942 * let's just not add this one, we already have more
943 * than enough */
944
945 dns_query_free(aux);
946 return 0;
947 }
948 if (r < 0)
949 goto fail;
950
951 /* Note that auxiliary queries do not track the original bus
952 * client, only the primary request does that. */
953
954 r = dns_query_go(aux);
955 if (r < 0)
956 goto fail;
957
958 return 1;
959
960fail:
961 dns_query_free(aux);
962 return r;
963}
964
965static void bus_method_resolve_service_complete(DnsQuery *q) {
966 bool has_root_domain = false;
967 DnsResourceRecord *rr;
968 DnsQuestion *question;
969 unsigned found = 0;
970 int ifindex, r;
971
972 assert(q);
973
974 if (q->state != DNS_TRANSACTION_SUCCESS) {
975 r = reply_query_state(q);
976 goto finish;
977 }
978
979 r = dns_query_process_cname(q);
980 if (r == -ELOOP) {
981 r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_CNAME_LOOP, "CNAME loop detected, or CNAME resolving disabled on '%s'", dns_query_string(q));
982 goto finish;
983 }
984 if (r < 0)
985 goto finish;
986 if (r == DNS_QUERY_RESTARTED) /* This was a cname, and the query was restarted. */
987 return;
988
989 question = dns_query_question_for_protocol(q, q->answer_protocol);
990
991 DNS_ANSWER_FOREACH_IFINDEX(rr, ifindex, q->answer) {
992 r = dns_question_matches_rr(question, rr, NULL);
993 if (r < 0)
994 goto finish;
995 if (r == 0)
996 continue;
997
998 if (rr->key->type != DNS_TYPE_SRV)
999 continue;
1000
1001 if (dns_name_is_root(rr->srv.name)) {
1002 has_root_domain = true;
1003 continue;
1004 }
1005
1006 if ((q->flags & SD_RESOLVED_NO_ADDRESS) == 0) {
1007 q->block_all_complete ++;
1008 r = resolve_service_hostname(q, rr, ifindex);
1009 q->block_all_complete --;
1010
1011 if (r < 0)
1012 goto finish;
1013 }
1014
1015 found++;
1016 }
1017
1018 if (has_root_domain && found <= 0) {
1019 /* If there's exactly one SRV RR and it uses
1020 * the root domain as host name, then the
1021 * service is explicitly not offered on the
1022 * domain. Report this as a recognizable
1023 * error. See RFC 2782, Section "Usage
1024 * Rules". */
1025 r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_SERVICE, "'%s' does not provide the requested service", dns_query_string(q));
1026 goto finish;
1027 }
1028
1029 if (found <= 0) {
1030 r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR, "'%s' does not have any RR of the requested type", dns_query_string(q));
1031 goto finish;
1032 }
1033
1034 /* Maybe we are already finished? check now... */
1035 resolve_service_all_complete(q);
1036 return;
1037
1038finish:
1039 if (r < 0) {
1040 log_error_errno(r, "Failed to send service reply: %m");
1041 sd_bus_reply_method_errno(q->request, r, NULL);
1042 }
1043
1044 dns_query_free(q);
1045}
1046
1047static int bus_method_resolve_service(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1048 _cleanup_(dns_question_unrefp) DnsQuestion *question_idna = NULL, *question_utf8 = NULL;
1049 const char *name, *type, *domain;
1050 _cleanup_free_ char *n = NULL;
1051 Manager *m = userdata;
1052 int family, ifindex;
1053 uint64_t flags;
1054 DnsQuery *q;
1055 int r;
1056
1057 assert(message);
1058 assert(m);
1059
1060 assert_cc(sizeof(int) == sizeof(int32_t));
1061
1062 r = sd_bus_message_read(message, "isssit", &ifindex, &name, &type, &domain, &family, &flags);
1063 if (r < 0)
1064 return r;
1065
1066 if (!IN_SET(family, AF_INET, AF_INET6, AF_UNSPEC))
1067 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family);
1068
1069 if (isempty(name))
1070 name = NULL;
1071 else if (!dns_service_name_is_valid(name))
1072 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid service name '%s'", name);
1073
1074 if (isempty(type))
1075 type = NULL;
1076 else if (!dns_srv_type_is_valid(type))
1077 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid SRV service type '%s'", type);
1078
1079 r = dns_name_is_valid(domain);
1080 if (r < 0)
1081 return r;
1082 if (r == 0)
1083 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid domain '%s'", domain);
1084
1085 if (name && !type)
1086 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Service name cannot be specified without service type.");
1087
1088 r = check_ifindex_flags(ifindex, &flags, SD_RESOLVED_NO_TXT|SD_RESOLVED_NO_ADDRESS, error);
1089 if (r < 0)
1090 return r;
1091
1092 r = dns_question_new_service(&question_utf8, name, type, domain, !(flags & SD_RESOLVED_NO_TXT), false);
1093 if (r < 0)
1094 return r;
1095
1096 r = dns_question_new_service(&question_idna, name, type, domain, !(flags & SD_RESOLVED_NO_TXT), true);
1097 if (r < 0)
1098 return r;
1099
1100 r = dns_query_new(m, &q, question_utf8, question_idna, ifindex, flags|SD_RESOLVED_NO_SEARCH);
1101 if (r < 0)
1102 return r;
1103
1104 q->request = sd_bus_message_ref(message);
1105 q->request_family = family;
1106 q->complete = bus_method_resolve_service_complete;
1107
1108 r = dns_query_bus_track(q, message);
1109 if (r < 0)
1110 goto fail;
1111
1112 r = dns_query_go(q);
1113 if (r < 0)
1114 goto fail;
1115
1116 return 1;
1117
1118fail:
1119 dns_query_free(q);
1120 return r;
1121}
1122
1123int bus_dns_server_append(sd_bus_message *reply, DnsServer *s, bool with_ifindex) {
1124 int r;
1125
1126 assert(reply);
1127 assert(s);
1128
1129 r = sd_bus_message_open_container(reply, 'r', with_ifindex ? "iiay" : "iay");
1130 if (r < 0)
1131 return r;
1132
1133 if (with_ifindex) {
1134 r = sd_bus_message_append(reply, "i", s->link ? s->link->ifindex : 0);
1135 if (r < 0)
1136 return r;
1137 }
1138
1139 r = sd_bus_message_append(reply, "i", s->family);
1140 if (r < 0)
1141 return r;
1142
1143 r = sd_bus_message_append_array(reply, 'y', &s->address, FAMILY_ADDRESS_SIZE(s->family));
1144 if (r < 0)
1145 return r;
1146
1147 return sd_bus_message_close_container(reply);
1148}
1149
1150static int bus_property_get_dns_servers(
1151 sd_bus *bus,
1152 const char *path,
1153 const char *interface,
1154 const char *property,
1155 sd_bus_message *reply,
1156 void *userdata,
1157 sd_bus_error *error) {
1158
1159 Manager *m = userdata;
1160 unsigned c = 0;
1161 DnsServer *s;
1162 Iterator i;
1163 Link *l;
1164 int r;
1165
1166 assert(reply);
1167 assert(m);
1168
1169 r = sd_bus_message_open_container(reply, 'a', "(iiay)");
1170 if (r < 0)
1171 return r;
1172
1173 LIST_FOREACH(servers, s, m->dns_servers) {
1174 r = bus_dns_server_append(reply, s, true);
1175 if (r < 0)
1176 return r;
1177
1178 c++;
1179 }
1180
1181 HASHMAP_FOREACH(l, m->links, i) {
1182 LIST_FOREACH(servers, s, l->dns_servers) {
1183 r = bus_dns_server_append(reply, s, true);
1184 if (r < 0)
1185 return r;
1186 c++;
1187 }
1188 }
1189
1190 if (c == 0) {
1191 LIST_FOREACH(servers, s, m->fallback_dns_servers) {
1192 r = bus_dns_server_append(reply, s, true);
1193 if (r < 0)
1194 return r;
1195 }
1196 }
1197
1198 return sd_bus_message_close_container(reply);
1199}
1200
1201static int bus_property_get_search_domains(
1202 sd_bus *bus,
1203 const char *path,
1204 const char *interface,
1205 const char *property,
1206 sd_bus_message *reply,
1207 void *userdata,
1208 sd_bus_error *error) {
1209
1210 Manager *m = userdata;
1211 DnsSearchDomain *d;
1212 Iterator i;
1213 Link *l;
1214 int r;
1215
1216 assert(reply);
1217 assert(m);
1218
1219 r = sd_bus_message_open_container(reply, 'a', "(isb)");
1220 if (r < 0)
1221 return r;
1222
1223 LIST_FOREACH(domains, d, m->search_domains) {
1224 r = sd_bus_message_append(reply, "(isb)", 0, d->name, d->route_only);
1225 if (r < 0)
1226 return r;
1227 }
1228
1229 HASHMAP_FOREACH(l, m->links, i) {
1230 LIST_FOREACH(domains, d, l->search_domains) {
1231 r = sd_bus_message_append(reply, "(isb)", l->ifindex, d->name, d->route_only);
1232 if (r < 0)
1233 return r;
1234 }
1235 }
1236
1237 return sd_bus_message_close_container(reply);
1238}
1239
1240static int bus_property_get_transaction_statistics(
1241 sd_bus *bus,
1242 const char *path,
1243 const char *interface,
1244 const char *property,
1245 sd_bus_message *reply,
1246 void *userdata,
1247 sd_bus_error *error) {
1248
1249 Manager *m = userdata;
1250
1251 assert(reply);
1252 assert(m);
1253
1254 return sd_bus_message_append(reply, "(tt)",
1255 (uint64_t) hashmap_size(m->dns_transactions),
1256 (uint64_t) m->n_transactions_total);
1257}
1258
1259static int bus_property_get_cache_statistics(
1260 sd_bus *bus,
1261 const char *path,
1262 const char *interface,
1263 const char *property,
1264 sd_bus_message *reply,
1265 void *userdata,
1266 sd_bus_error *error) {
1267
1268 uint64_t size = 0, hit = 0, miss = 0;
1269 Manager *m = userdata;
1270 DnsScope *s;
1271
1272 assert(reply);
1273 assert(m);
1274
1275 LIST_FOREACH(scopes, s, m->dns_scopes) {
1276 size += dns_cache_size(&s->cache);
1277 hit += s->cache.n_hit;
1278 miss += s->cache.n_miss;
1279 }
1280
1281 return sd_bus_message_append(reply, "(ttt)", size, hit, miss);
1282}
1283
1284static int bus_property_get_dnssec_statistics(
1285 sd_bus *bus,
1286 const char *path,
1287 const char *interface,
1288 const char *property,
1289 sd_bus_message *reply,
1290 void *userdata,
1291 sd_bus_error *error) {
1292
1293 Manager *m = userdata;
1294
1295 assert(reply);
1296 assert(m);
1297
1298 return sd_bus_message_append(reply, "(tttt)",
1299 (uint64_t) m->n_dnssec_verdict[DNSSEC_SECURE],
1300 (uint64_t) m->n_dnssec_verdict[DNSSEC_INSECURE],
1301 (uint64_t) m->n_dnssec_verdict[DNSSEC_BOGUS],
1302 (uint64_t) m->n_dnssec_verdict[DNSSEC_INDETERMINATE]);
1303}
1304
1305static int bus_property_get_dnssec_supported(
1306 sd_bus *bus,
1307 const char *path,
1308 const char *interface,
1309 const char *property,
1310 sd_bus_message *reply,
1311 void *userdata,
1312 sd_bus_error *error) {
1313
1314 Manager *m = userdata;
1315
1316 assert(reply);
1317 assert(m);
1318
1319 return sd_bus_message_append(reply, "b", manager_dnssec_supported(m));
1320}
1321
1322static int bus_method_reset_statistics(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1323 Manager *m = userdata;
1324 DnsScope *s;
1325
1326 assert(message);
1327 assert(m);
1328
1329 LIST_FOREACH(scopes, s, m->dns_scopes)
1330 s->cache.n_hit = s->cache.n_miss = 0;
1331
1332 m->n_transactions_total = 0;
1333 zero(m->n_dnssec_verdict);
1334
1335 return sd_bus_reply_method_return(message, NULL);
1336}
1337
1338static int get_any_link(Manager *m, int ifindex, Link **ret, sd_bus_error *error) {
1339 Link *l;
1340
1341 assert(m);
1342 assert(ret);
1343
1344 if (ifindex <= 0)
1345 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface index");
1346
1347 l = hashmap_get(m->links, INT_TO_PTR(ifindex));
1348 if (!l)
1349 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_LINK, "Link %i not known", ifindex);
1350
1351 *ret = l;
1352 return 0;
1353}
1354
1355static int get_unmanaged_link(Manager *m, int ifindex, Link **ret, sd_bus_error *error) {
1356 Link *l;
1357 int r;
1358
1359 assert(m);
1360 assert(ret);
1361
1362 r = get_any_link(m, ifindex, &l, error);
1363 if (r < 0)
1364 return r;
1365
1366 if (l->flags & IFF_LOOPBACK)
1367 return sd_bus_error_setf(error, BUS_ERROR_LINK_BUSY, "Link %s is loopback device.", l->name);
1368 if (l->is_managed)
1369 return sd_bus_error_setf(error, BUS_ERROR_LINK_BUSY, "Link %s is managed.", l->name);
1370
1371 *ret = l;
1372 return 0;
1373}
1374
1375static int call_link_method(Manager *m, sd_bus_message *message, sd_bus_message_handler_t handler, sd_bus_error *error) {
1376 int ifindex, r;
1377 Link *l;
1378
1379 assert(m);
1380 assert(message);
1381 assert(handler);
1382
1383 assert_cc(sizeof(int) == sizeof(int32_t));
1384 r = sd_bus_message_read(message, "i", &ifindex);
1385 if (r < 0)
1386 return r;
1387
1388 r = get_unmanaged_link(m, ifindex, &l, error);
1389 if (r < 0)
1390 return r;
1391
1392 return handler(message, l, error);
1393}
1394
1395static int bus_method_set_link_dns_servers(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1396 return call_link_method(userdata, message, bus_link_method_set_dns_servers, error);
1397}
1398
1399static int bus_method_set_link_search_domains(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1400 return call_link_method(userdata, message, bus_link_method_set_search_domains, error);
1401}
1402
1403static int bus_method_set_link_llmnr(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1404 return call_link_method(userdata, message, bus_link_method_set_llmnr, error);
1405}
1406
1407static int bus_method_set_link_mdns(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1408 return call_link_method(userdata, message, bus_link_method_set_mdns, error);
1409}
1410
1411static int bus_method_set_link_dnssec(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1412 return call_link_method(userdata, message, bus_link_method_set_dnssec, error);
1413}
1414
1415static int bus_method_set_link_dnssec_negative_trust_anchors(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1416 return call_link_method(userdata, message, bus_link_method_set_dnssec_negative_trust_anchors, error);
1417}
1418
1419static int bus_method_revert_link(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1420 return call_link_method(userdata, message, bus_link_method_revert, error);
1421}
1422
1423static int bus_method_get_link(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1424 _cleanup_free_ char *p = NULL;
1425 Manager *m = userdata;
1426 int r, ifindex;
1427 Link *l;
1428
1429 assert(message);
1430 assert(m);
1431
1432 assert_cc(sizeof(int) == sizeof(int32_t));
1433 r = sd_bus_message_read(message, "i", &ifindex);
1434 if (r < 0)
1435 return r;
1436
1437 r = get_any_link(m, ifindex, &l, error);
1438 if (r < 0)
1439 return r;
1440
1441 p = link_bus_path(l);
1442 if (!p)
1443 return -ENOMEM;
1444
1445 return sd_bus_reply_method_return(message, "o", p);
1446}
1447
1448static const sd_bus_vtable resolve_vtable[] = {
1449 SD_BUS_VTABLE_START(0),
1450 SD_BUS_PROPERTY("LLMNRHostname", "s", NULL, offsetof(Manager, llmnr_hostname), 0),
1451 SD_BUS_PROPERTY("DNS", "a(iiay)", bus_property_get_dns_servers, 0, 0),
1452 SD_BUS_PROPERTY("SearchDomains", "a(isb)", bus_property_get_search_domains, 0, 0),
1453 SD_BUS_PROPERTY("TransactionStatistics", "(tt)", bus_property_get_transaction_statistics, 0, 0),
1454 SD_BUS_PROPERTY("CacheStatistics", "(ttt)", bus_property_get_cache_statistics, 0, 0),
1455 SD_BUS_PROPERTY("DNSSECStatistics", "(tttt)", bus_property_get_dnssec_statistics, 0, 0),
1456 SD_BUS_PROPERTY("DNSSECSupported", "b", bus_property_get_dnssec_supported, 0, 0),
1457
1458 SD_BUS_METHOD("ResolveHostname", "isit", "a(iiay)st", bus_method_resolve_hostname, SD_BUS_VTABLE_UNPRIVILEGED),
1459 SD_BUS_METHOD("ResolveAddress", "iiayt", "a(is)t", bus_method_resolve_address, SD_BUS_VTABLE_UNPRIVILEGED),
1460 SD_BUS_METHOD("ResolveRecord", "isqqt", "a(iqqay)t", bus_method_resolve_record, SD_BUS_VTABLE_UNPRIVILEGED),
1461 SD_BUS_METHOD("ResolveService", "isssit", "a(qqqsa(iiay)s)aayssst", bus_method_resolve_service, SD_BUS_VTABLE_UNPRIVILEGED),
1462 SD_BUS_METHOD("ResetStatistics", NULL, NULL, bus_method_reset_statistics, 0),
1463 SD_BUS_METHOD("GetLink", "i", "o", bus_method_get_link, SD_BUS_VTABLE_UNPRIVILEGED),
1464 SD_BUS_METHOD("SetLinkDNS", "ia(iay)", NULL, bus_method_set_link_dns_servers, 0),
1465 SD_BUS_METHOD("SetLinkDomains", "ia(sb)", NULL, bus_method_set_link_search_domains, 0),
1466 SD_BUS_METHOD("SetLinkLLMNR", "is", NULL, bus_method_set_link_llmnr, 0),
1467 SD_BUS_METHOD("SetLinkMulticastDNS", "is", NULL, bus_method_set_link_mdns, 0),
1468 SD_BUS_METHOD("SetLinkDNSSEC", "is", NULL, bus_method_set_link_dnssec, 0),
1469 SD_BUS_METHOD("SetLinkDNSSECNegativeTrustAnchors", "ias", NULL, bus_method_set_link_dnssec_negative_trust_anchors, 0),
1470 SD_BUS_METHOD("RevertLink", "i", NULL, bus_method_revert_link, 0),
1471
1472 SD_BUS_VTABLE_END,
1473};
1474
1475static int on_bus_retry(sd_event_source *s, usec_t usec, void *userdata) {
1476 Manager *m = userdata;
1477
1478 assert(s);
1479 assert(m);
1480
1481 m->bus_retry_event_source = sd_event_source_unref(m->bus_retry_event_source);
1482
1483 manager_connect_bus(m);
1484 return 0;
1485}
1486
1487static int match_prepare_for_sleep(sd_bus_message *message, void *userdata, sd_bus_error *ret_error) {
1488 Manager *m = userdata;
1489 int b, r;
1490
1491 assert(message);
1492 assert(m);
1493
1494 r = sd_bus_message_read(message, "b", &b);
1495 if (r < 0) {
1496 log_debug_errno(r, "Failed to parse PrepareForSleep signal: %m");
1497 return 0;
1498 }
1499
1500 if (b)
1501 return 0;
1502
1503 log_debug("Coming back from suspend, verifying all RRs...");
1504
1505 manager_verify_all(m);
1506 return 0;
1507}
1508
1509int manager_connect_bus(Manager *m) {
1510 int r;
1511
1512 assert(m);
1513
1514 if (m->bus)
1515 return 0;
1516
1517 r = sd_bus_default_system(&m->bus);
1518 if (r < 0) {
1519 /* We failed to connect? Yuck, we must be in early
1520 * boot. Let's try in 5s again. As soon as we have
1521 * kdbus we can stop doing this... */
1522
1523 log_debug_errno(r, "Failed to connect to bus, trying again in 5s: %m");
1524
1525 r = sd_event_add_time(m->event, &m->bus_retry_event_source, CLOCK_MONOTONIC, now(CLOCK_MONOTONIC) + 5*USEC_PER_SEC, 0, on_bus_retry, m);
1526 if (r < 0)
1527 return log_error_errno(r, "Failed to install bus reconnect time event: %m");
1528
1529 (void) sd_event_source_set_description(m->bus_retry_event_source, "bus-retry");
1530 return 0;
1531 }
1532
1533 r = sd_bus_add_object_vtable(m->bus, NULL, "/org/freedesktop/resolve1", "org.freedesktop.resolve1.Manager", resolve_vtable, m);
1534 if (r < 0)
1535 return log_error_errno(r, "Failed to register object: %m");
1536
1537 r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/resolve1/link", "org.freedesktop.resolve1.Link", link_vtable, link_object_find, m);
1538 if (r < 0)
1539 return log_error_errno(r, "Failed to register link objects: %m");
1540
1541 r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/resolve1/link", link_node_enumerator, m);
1542 if (r < 0)
1543 return log_error_errno(r, "Failed to register link enumerator: %m");
5eef597e
MP
1544
1545 r = sd_bus_request_name(m->bus, "org.freedesktop.resolve1", 0);
f47781d8
MP
1546 if (r < 0)
1547 return log_error_errno(r, "Failed to register name: %m");
5eef597e
MP
1548
1549 r = sd_bus_attach_event(m->bus, m->event, 0);
f47781d8
MP
1550 if (r < 0)
1551 return log_error_errno(r, "Failed to attach bus to event loop: %m");
5eef597e
MP
1552
1553 r = sd_bus_add_match(m->bus, &m->prepare_for_sleep_slot,
1554 "type='signal',"
1555 "sender='org.freedesktop.login1',"
1556 "interface='org.freedesktop.login1.Manager',"
1557 "member='PrepareForSleep',"
1558 "path='/org/freedesktop/login1'",
1559 match_prepare_for_sleep,
1560 m);
1561 if (r < 0)
f47781d8 1562 log_error_errno(r, "Failed to add match for PrepareForSleep: %m");
5eef597e
MP
1563
1564 return 0;
1565}