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