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