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