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