]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-bus.c
resolved: log each time we increase the DNSSEC verdict counters
[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"
3abaabda 28#include "resolved-link-bus.h"
74b2466e 29
ad867662 30static int reply_query_state(DnsQuery *q) {
ad867662
LP
31
32 switch (q->state) {
74b2466e 33
ec2c5e43 34 case DNS_TRANSACTION_NO_SERVERS:
309e9d86 35 return sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_NAME_SERVERS, "No appropriate name servers or networks for name found");
74b2466e 36
ec2c5e43 37 case DNS_TRANSACTION_TIMEOUT:
ad867662 38 return sd_bus_reply_method_errorf(q->request, SD_BUS_ERROR_TIMEOUT, "Query timed out");
74b2466e 39
ec2c5e43 40 case DNS_TRANSACTION_ATTEMPTS_MAX_REACHED:
ad867662
LP
41 return sd_bus_reply_method_errorf(q->request, SD_BUS_ERROR_TIMEOUT, "All attempts to contact name servers or networks failed");
42
818f766b
LP
43 case DNS_TRANSACTION_INVALID_REPLY:
44 return sd_bus_reply_method_errorf(q->request, BUS_ERROR_INVALID_REPLY, "Received invalid reply");
45
ec2c5e43 46 case DNS_TRANSACTION_RESOURCES:
ad867662
LP
47 return sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_RESOURCES, "Not enough resources");
48
818f766b
LP
49 case DNS_TRANSACTION_ABORTED:
50 return sd_bus_reply_method_errorf(q->request, BUS_ERROR_ABORTED, "Query aborted");
74b2466e 51
547973de 52 case DNS_TRANSACTION_DNSSEC_FAILED:
a761c1ca 53 return sd_bus_reply_method_errorf(q->request, BUS_ERROR_DNSSEC_FAILED, "DNSSEC validation failed: %s",
019036a4 54 dnssec_result_to_string(q->answer_dnssec_result));
547973de 55
b2b796b8
LP
56 case DNS_TRANSACTION_NO_TRUST_ANCHOR:
57 return sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_TRUST_ANCHOR, "No suitable trust anchor known");
58
91adc4db
LP
59 case DNS_TRANSACTION_RR_TYPE_UNSUPPORTED:
60 return sd_bus_reply_method_errorf(q->request, BUS_ERROR_RR_TYPE_UNSUPPORTED, "Server does not support requested resource record type");
61
edbcc1fd
LP
62 case DNS_TRANSACTION_NETWORK_DOWN:
63 return sd_bus_reply_method_errorf(q->request, BUS_ERROR_NETWORK_DOWN, "Network is down");
64
3bbdc31d 65 case DNS_TRANSACTION_RCODE_FAILURE: {
4afd3348 66 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
74b2466e 67
faa133f3 68 if (q->answer_rcode == DNS_RCODE_NXDOMAIN)
23b298bc 69 sd_bus_error_setf(&error, _BUS_ERROR_DNS "NXDOMAIN", "'%s' not found", dns_query_string(q));
74b2466e
LP
70 else {
71 const char *rc, *n;
ad867662 72 char p[3]; /* the rcode is 4 bits long */
74b2466e 73
faa133f3 74 rc = dns_rcode_to_string(q->answer_rcode);
74b2466e 75 if (!rc) {
faa133f3 76 sprintf(p, "%i", q->answer_rcode);
74b2466e
LP
77 rc = p;
78 }
79
63c372cb 80 n = strjoina(_BUS_ERROR_DNS, rc);
23b298bc 81 sd_bus_error_setf(&error, n, "Could not resolve '%s', server or network returned error %s", dns_query_string(q), rc);
74b2466e
LP
82 }
83
ad867662 84 return sd_bus_reply_method_error(q->request, &error);
74b2466e
LP
85 }
86
ec2c5e43
LP
87 case DNS_TRANSACTION_NULL:
88 case DNS_TRANSACTION_PENDING:
ef9fb66c 89 case DNS_TRANSACTION_VALIDATING:
ec2c5e43 90 case DNS_TRANSACTION_SUCCESS:
8ba9fd9c 91 default:
ad867662
LP
92 assert_not_reached("Impossible state");
93 }
94}
74b2466e 95
78c6a153 96static int append_address(sd_bus_message *reply, DnsResourceRecord *rr, int ifindex) {
8ba9fd9c
LP
97 int r;
98
99 assert(reply);
100 assert(rr);
101
78c6a153
LP
102 r = sd_bus_message_open_container(reply, 'r', "iiay");
103 if (r < 0)
104 return r;
105
106 r = sd_bus_message_append(reply, "i", ifindex);
8ba9fd9c
LP
107 if (r < 0)
108 return r;
109
faa133f3 110 if (rr->key->type == DNS_TYPE_A) {
0dd25fb9 111 r = sd_bus_message_append(reply, "i", AF_INET);
8ba9fd9c
LP
112 if (r < 0)
113 return r;
114
115 r = sd_bus_message_append_array(reply, 'y', &rr->a.in_addr, sizeof(struct in_addr));
faa133f3
LP
116
117 } else if (rr->key->type == DNS_TYPE_AAAA) {
0dd25fb9 118 r = sd_bus_message_append(reply, "i", AF_INET6);
8ba9fd9c
LP
119 if (r < 0)
120 return r;
121
122 r = sd_bus_message_append_array(reply, 'y', &rr->aaaa.in6_addr, sizeof(struct in6_addr));
faa133f3
LP
123 } else
124 return -EAFNOSUPPORT;
125
8ba9fd9c
LP
126 if (r < 0)
127 return r;
128
8ba9fd9c
LP
129 r = sd_bus_message_close_container(reply);
130 if (r < 0)
131 return r;
132
133 return 0;
134}
135
ad867662 136static void bus_method_resolve_hostname_complete(DnsQuery *q) {
45ec7efb 137 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *canonical = NULL;
4afd3348 138 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
ce736ace 139 DnsResourceRecord *rr;
45ec7efb 140 unsigned added = 0;
ce736ace 141 int ifindex, r;
74b2466e 142
ad867662 143 assert(q);
74b2466e 144
ec2c5e43 145 if (q->state != DNS_TRANSACTION_SUCCESS) {
ad867662
LP
146 r = reply_query_state(q);
147 goto finish;
148 }
74b2466e 149
45ec7efb
LP
150 r = dns_query_process_cname(q);
151 if (r == -ELOOP) {
23b298bc 152 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
153 goto finish;
154 }
155 if (r < 0)
156 goto finish;
7588460a 157 if (r == DNS_QUERY_RESTARTED) /* This was a cname, and the query was restarted. */
45ec7efb
LP
158 return;
159
ad867662
LP
160 r = sd_bus_message_new_method_return(q->request, &reply);
161 if (r < 0)
162 goto finish;
74b2466e 163
78c6a153 164 r = sd_bus_message_open_container(reply, 'a', "(iiay)");
51323288
LP
165 if (r < 0)
166 goto finish;
8ba9fd9c 167
ce736ace
LP
168 DNS_ANSWER_FOREACH_IFINDEX(rr, ifindex, q->answer) {
169 DnsQuestion *question;
23b298bc 170
ce736ace 171 question = dns_query_question_for_protocol(q, q->answer_protocol);
23b298bc 172
ce736ace
LP
173 r = dns_question_matches_rr(question, rr, DNS_SEARCH_DOMAIN_NAME(q->answer_search_domain));
174 if (r < 0)
175 goto finish;
176 if (r == 0)
177 continue;
74b2466e 178
ce736ace
LP
179 r = append_address(reply, rr, ifindex);
180 if (r < 0)
181 goto finish;
74b2466e 182
ce736ace
LP
183 if (!canonical)
184 canonical = dns_resource_record_ref(rr);
309e9d86 185
ce736ace 186 added ++;
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
3abaabda 1119int bus_dns_server_append(sd_bus_message *reply, DnsServer *s, bool with_ifindex) {
7f220d94
LP
1120 int r;
1121
1122 assert(reply);
1123 assert(s);
1124
3abaabda 1125 r = sd_bus_message_open_container(reply, 'r', with_ifindex ? "iiay" : "iay");
7f220d94
LP
1126 if (r < 0)
1127 return r;
1128
3abaabda
LP
1129 if (with_ifindex) {
1130 r = sd_bus_message_append(reply, "i", s->link ? s->link->ifindex : 0);
1131 if (r < 0)
1132 return r;
1133 }
1134
1135 r = sd_bus_message_append(reply, "i", s->family);
7f220d94
LP
1136 if (r < 0)
1137 return r;
1138
1139 r = sd_bus_message_append_array(reply, 'y', &s->address, FAMILY_ADDRESS_SIZE(s->family));
1140 if (r < 0)
1141 return r;
1142
1143 return sd_bus_message_close_container(reply);
1144}
1145
1146static int bus_property_get_dns_servers(
1147 sd_bus *bus,
1148 const char *path,
1149 const char *interface,
1150 const char *property,
1151 sd_bus_message *reply,
1152 void *userdata,
1153 sd_bus_error *error) {
1154
1155 Manager *m = userdata;
1156 unsigned c = 0;
1157 DnsServer *s;
1158 Iterator i;
1159 Link *l;
1160 int r;
1161
1162 assert(reply);
1163 assert(m);
1164
1165 r = sd_bus_message_open_container(reply, 'a', "(iiay)");
1166 if (r < 0)
1167 return r;
1168
1169 LIST_FOREACH(servers, s, m->dns_servers) {
3abaabda 1170 r = bus_dns_server_append(reply, s, true);
7f220d94
LP
1171 if (r < 0)
1172 return r;
1173
1174 c++;
1175 }
1176
1177 HASHMAP_FOREACH(l, m->links, i) {
1178 LIST_FOREACH(servers, s, l->dns_servers) {
3abaabda 1179 r = bus_dns_server_append(reply, s, true);
7f220d94
LP
1180 if (r < 0)
1181 return r;
1182 c++;
1183 }
1184 }
1185
1186 if (c == 0) {
1187 LIST_FOREACH(servers, s, m->fallback_dns_servers) {
3abaabda 1188 r = bus_dns_server_append(reply, s, true);
7f220d94
LP
1189 if (r < 0)
1190 return r;
1191 }
1192 }
1193
1194 return sd_bus_message_close_container(reply);
1195}
1196
1197static int bus_property_get_search_domains(
1198 sd_bus *bus,
1199 const char *path,
1200 const char *interface,
1201 const char *property,
1202 sd_bus_message *reply,
1203 void *userdata,
1204 sd_bus_error *error) {
1205
1206 Manager *m = userdata;
1207 DnsSearchDomain *d;
1208 Iterator i;
1209 Link *l;
1210 int r;
1211
1212 assert(reply);
1213 assert(m);
1214
1215 r = sd_bus_message_open_container(reply, 'a', "(is)");
1216 if (r < 0)
1217 return r;
1218
1219 LIST_FOREACH(domains, d, m->search_domains) {
1220 r = sd_bus_message_append(reply, "(is)", 0, d->name);
1221 if (r < 0)
1222 return r;
1223 }
1224
1225 HASHMAP_FOREACH(l, m->links, i) {
1226 LIST_FOREACH(domains, d, l->search_domains) {
1227 r = sd_bus_message_append(reply, "is", l->ifindex, d->name);
1228 if (r < 0)
1229 return r;
1230 }
1231 }
1232
1233 return sd_bus_message_close_container(reply);
1234}
1235
a150ff5e
LP
1236static int bus_property_get_transaction_statistics(
1237 sd_bus *bus,
1238 const char *path,
1239 const char *interface,
1240 const char *property,
1241 sd_bus_message *reply,
1242 void *userdata,
1243 sd_bus_error *error) {
1244
1245 Manager *m = userdata;
1246
1247 assert(reply);
1248 assert(m);
1249
1250 return sd_bus_message_append(reply, "(tt)",
1251 (uint64_t) hashmap_size(m->dns_transactions),
1252 (uint64_t) m->n_transactions_total);
1253}
1254
1255static int bus_property_get_cache_statistics(
1256 sd_bus *bus,
1257 const char *path,
1258 const char *interface,
1259 const char *property,
1260 sd_bus_message *reply,
1261 void *userdata,
1262 sd_bus_error *error) {
1263
1264 uint64_t size = 0, hit = 0, miss = 0;
1265 Manager *m = userdata;
1266 DnsScope *s;
1267
1268 assert(reply);
1269 assert(m);
1270
1271 LIST_FOREACH(scopes, s, m->dns_scopes) {
1272 size += dns_cache_size(&s->cache);
1273 hit += s->cache.n_hit;
1274 miss += s->cache.n_miss;
1275 }
1276
1277 return sd_bus_message_append(reply, "(ttt)", size, hit, miss);
1278}
1279
1280static int bus_property_get_dnssec_statistics(
1281 sd_bus *bus,
1282 const char *path,
1283 const char *interface,
1284 const char *property,
1285 sd_bus_message *reply,
1286 void *userdata,
1287 sd_bus_error *error) {
1288
1289 Manager *m = userdata;
1290
1291 assert(reply);
1292 assert(m);
1293
1294 return sd_bus_message_append(reply, "(tttt)",
59c5b597
LP
1295 (uint64_t) m->n_dnssec_verdict[DNSSEC_SECURE],
1296 (uint64_t) m->n_dnssec_verdict[DNSSEC_INSECURE],
1297 (uint64_t) m->n_dnssec_verdict[DNSSEC_BOGUS],
1298 (uint64_t) m->n_dnssec_verdict[DNSSEC_INDETERMINATE]);
a150ff5e
LP
1299}
1300
593f665c
LP
1301static int bus_property_get_dnssec_supported(
1302 sd_bus *bus,
1303 const char *path,
1304 const char *interface,
1305 const char *property,
1306 sd_bus_message *reply,
1307 void *userdata,
1308 sd_bus_error *error) {
1309
1310 Manager *m = userdata;
593f665c
LP
1311
1312 assert(reply);
1313 assert(m);
1314
c69fa7e3 1315 return sd_bus_message_append(reply, "b", manager_dnssec_supported(m));
593f665c
LP
1316}
1317
a150ff5e
LP
1318static int bus_method_reset_statistics(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1319 Manager *m = userdata;
1320 DnsScope *s;
1321
1322 assert(message);
1323 assert(m);
1324
1325 LIST_FOREACH(scopes, s, m->dns_scopes)
1326 s->cache.n_hit = s->cache.n_miss = 0;
1327
1328 m->n_transactions_total = 0;
59c5b597 1329 zero(m->n_dnssec_verdict);
a150ff5e
LP
1330
1331 return sd_bus_reply_method_return(message, NULL);
1332}
1333
3abaabda 1334static int get_any_link(Manager *m, int ifindex, Link **ret, sd_bus_error *error) {
97e5d693
LP
1335 Link *l;
1336
1337 assert(m);
3abaabda 1338 assert(ret);
97e5d693
LP
1339
1340 if (ifindex <= 0)
1341 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface index");
1342
1343 l = hashmap_get(m->links, INT_TO_PTR(ifindex));
1344 if (!l)
1345 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_LINK, "Link %i not known", ifindex);
3abaabda
LP
1346
1347 *ret = l;
1348 return 0;
1349}
1350
1351static int get_unmanaged_link(Manager *m, int ifindex, Link **ret, sd_bus_error *error) {
1352 Link *l;
1353 int r;
1354
1355 assert(m);
1356 assert(ret);
1357
1358 r = get_any_link(m, ifindex, &l, error);
1359 if (r < 0)
1360 return r;
1361
97e5d693
LP
1362 if (l->flags & IFF_LOOPBACK)
1363 return sd_bus_error_setf(error, BUS_ERROR_LINK_BUSY, "Link %s is loopback device.", l->name);
1364 if (l->is_managed)
1365 return sd_bus_error_setf(error, BUS_ERROR_LINK_BUSY, "Link %s is managed.", l->name);
1366
1367 *ret = l;
1368 return 0;
1369}
1370
d2ec6608 1371static int call_link_method(Manager *m, sd_bus_message *message, sd_bus_message_handler_t handler, sd_bus_error *error) {
97e5d693 1372 int ifindex, r;
97e5d693
LP
1373 Link *l;
1374
97e5d693 1375 assert(m);
97e5d693 1376 assert(message);
d2ec6608 1377 assert(handler);
97e5d693 1378
d2ec6608 1379 assert_cc(sizeof(int) == sizeof(int32_t));
97e5d693
LP
1380 r = sd_bus_message_read(message, "i", &ifindex);
1381 if (r < 0)
1382 return r;
1383
1384 r = get_unmanaged_link(m, ifindex, &l, error);
1385 if (r < 0)
1386 return r;
1387
d2ec6608
LP
1388 return handler(message, l, error);
1389}
97e5d693 1390
d2ec6608
LP
1391static int bus_method_set_link_dns_servers(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1392 return call_link_method(userdata, message, bus_link_method_set_dns_servers, error);
1393}
97e5d693 1394
d2ec6608
LP
1395static int bus_method_set_link_search_domains(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1396 return call_link_method(userdata, message, bus_link_method_set_search_domains, error);
97e5d693
LP
1397}
1398
1399static int bus_method_set_link_llmnr(sd_bus_message *message, void *userdata, sd_bus_error *error) {
d2ec6608 1400 return call_link_method(userdata, message, bus_link_method_set_llmnr, error);
97e5d693
LP
1401}
1402
1403static int bus_method_set_link_mdns(sd_bus_message *message, void *userdata, sd_bus_error *error) {
d2ec6608 1404 return call_link_method(userdata, message, bus_link_method_set_mdns, error);
97e5d693
LP
1405}
1406
1407static int bus_method_set_link_dnssec(sd_bus_message *message, void *userdata, sd_bus_error *error) {
d2ec6608 1408 return call_link_method(userdata, message, bus_link_method_set_dnssec, error);
97e5d693
LP
1409}
1410
1411static int bus_method_set_link_dnssec_negative_trust_anchors(sd_bus_message *message, void *userdata, sd_bus_error *error) {
d2ec6608 1412 return call_link_method(userdata, message, bus_link_method_set_dnssec_negative_trust_anchors, error);
97e5d693
LP
1413}
1414
1415static int bus_method_revert_link(sd_bus_message *message, void *userdata, sd_bus_error *error) {
d2ec6608 1416 return call_link_method(userdata, message, bus_link_method_revert, error);
97e5d693
LP
1417}
1418
3abaabda
LP
1419static int bus_method_get_link(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1420 _cleanup_free_ char *p = NULL;
1421 Manager *m = userdata;
1422 int r, ifindex;
1423 Link *l;
1424
1425 assert(message);
1426 assert(m);
1427
1428 assert_cc(sizeof(int) == sizeof(int32_t));
3abaabda
LP
1429 r = sd_bus_message_read(message, "i", &ifindex);
1430 if (r < 0)
1431 return r;
1432
1433 r = get_any_link(m, ifindex, &l, error);
1434 if (r < 0)
1435 return r;
1436
1437 p = link_bus_path(l);
1438 if (!p)
1439 return -ENOMEM;
1440
1441 return sd_bus_reply_method_return(message, "o", p);
1442}
1443
74b2466e
LP
1444static const sd_bus_vtable resolve_vtable[] = {
1445 SD_BUS_VTABLE_START(0),
7f220d94 1446 SD_BUS_PROPERTY("LLMNRHostname", "s", NULL, offsetof(Manager, llmnr_hostname), 0),
e40f0647
LP
1447 SD_BUS_PROPERTY("DNS", "a(iiay)", bus_property_get_dns_servers, 0, 0),
1448 SD_BUS_PROPERTY("Domains", "a(is)", bus_property_get_search_domains, 0, 0),
a150ff5e
LP
1449 SD_BUS_PROPERTY("TransactionStatistics", "(tt)", bus_property_get_transaction_statistics, 0, 0),
1450 SD_BUS_PROPERTY("CacheStatistics", "(ttt)", bus_property_get_cache_statistics, 0, 0),
1451 SD_BUS_PROPERTY("DNSSECStatistics", "(tttt)", bus_property_get_dnssec_statistics, 0, 0),
593f665c 1452 SD_BUS_PROPERTY("DNSSECSupported", "b", bus_property_get_dnssec_supported, 0, 0),
7f220d94 1453
78c6a153
LP
1454 SD_BUS_METHOD("ResolveHostname", "isit", "a(iiay)st", bus_method_resolve_hostname, SD_BUS_VTABLE_UNPRIVILEGED),
1455 SD_BUS_METHOD("ResolveAddress", "iiayt", "a(is)t", bus_method_resolve_address, SD_BUS_VTABLE_UNPRIVILEGED),
1456 SD_BUS_METHOD("ResolveRecord", "isqqt", "a(iqqay)t", bus_method_resolve_record, SD_BUS_VTABLE_UNPRIVILEGED),
45ec7efb 1457 SD_BUS_METHOD("ResolveService", "isssit", "a(qqqsa(iiay)s)aayssst", bus_method_resolve_service, SD_BUS_VTABLE_UNPRIVILEGED),
a150ff5e 1458 SD_BUS_METHOD("ResetStatistics", NULL, NULL, bus_method_reset_statistics, 0),
3abaabda 1459 SD_BUS_METHOD("GetLink", "i", "o", bus_method_get_link, SD_BUS_VTABLE_UNPRIVILEGED),
97e5d693 1460 SD_BUS_METHOD("SetLinkDNS", "ia(iay)", NULL, bus_method_set_link_dns_servers, 0),
d2ec6608 1461 SD_BUS_METHOD("SetLinkDomains", "ias", NULL, bus_method_set_link_search_domains, 0),
97e5d693
LP
1462 SD_BUS_METHOD("SetLinkLLMNR", "is", NULL, bus_method_set_link_llmnr, 0),
1463 SD_BUS_METHOD("SetLinkMulticastDNS", "is", NULL, bus_method_set_link_mdns, 0),
1464 SD_BUS_METHOD("SetLinkDNSSEC", "is", NULL, bus_method_set_link_dnssec, 0),
1465 SD_BUS_METHOD("SetLinkDNSSECNegativeTrustAnchors", "ias", NULL, bus_method_set_link_dnssec_negative_trust_anchors, 0),
1466 SD_BUS_METHOD("RevertLink", "i", NULL, bus_method_revert_link, 0),
1467
74b2466e
LP
1468 SD_BUS_VTABLE_END,
1469};
1470
1471static int on_bus_retry(sd_event_source *s, usec_t usec, void *userdata) {
1472 Manager *m = userdata;
1473
1474 assert(s);
1475 assert(m);
1476
1477 m->bus_retry_event_source = sd_event_source_unref(m->bus_retry_event_source);
1478
1479 manager_connect_bus(m);
1480 return 0;
1481}
1482
19070062 1483static int match_prepare_for_sleep(sd_bus_message *message, void *userdata, sd_bus_error *ret_error) {
902bb5d8
LP
1484 Manager *m = userdata;
1485 int b, r;
1486
19070062
LP
1487 assert(message);
1488 assert(m);
902bb5d8
LP
1489
1490 r = sd_bus_message_read(message, "b", &b);
1491 if (r < 0) {
da927ba9 1492 log_debug_errno(r, "Failed to parse PrepareForSleep signal: %m");
902bb5d8
LP
1493 return 0;
1494 }
1495
1496 if (b)
1497 return 0;
1498
1499 log_debug("Coming back from suspend, verifying all RRs...");
1500
1501 manager_verify_all(m);
1502 return 0;
1503}
1504
74b2466e
LP
1505int manager_connect_bus(Manager *m) {
1506 int r;
1507
1508 assert(m);
1509
1510 if (m->bus)
1511 return 0;
1512
1513 r = sd_bus_default_system(&m->bus);
1514 if (r < 0) {
1515 /* We failed to connect? Yuck, we must be in early
1516 * boot. Let's try in 5s again. As soon as we have
1517 * kdbus we can stop doing this... */
1518
da927ba9 1519 log_debug_errno(r, "Failed to connect to bus, trying again in 5s: %m");
74b2466e
LP
1520
1521 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
1522 if (r < 0)
1523 return log_error_errno(r, "Failed to install bus reconnect time event: %m");
74b2466e 1524
aa4a9deb 1525 (void) sd_event_source_set_description(m->bus_retry_event_source, "bus-retry");
74b2466e
LP
1526 return 0;
1527 }
1528
4d1cf1e2 1529 r = sd_bus_add_object_vtable(m->bus, NULL, "/org/freedesktop/resolve1", "org.freedesktop.resolve1.Manager", resolve_vtable, m);
f647962d
MS
1530 if (r < 0)
1531 return log_error_errno(r, "Failed to register object: %m");
74b2466e 1532
3abaabda
LP
1533 r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/resolve1/link", "org.freedesktop.resolve1.Link", link_vtable, link_object_find, m);
1534 if (r < 0)
1535 return log_error_errno(r, "Failed to register link objects: %m");
1536
1537 r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/resolve1/link", link_node_enumerator, m);
1538 if (r < 0)
1539 return log_error_errno(r, "Failed to register link enumerator: %m");
1540
74b2466e 1541 r = sd_bus_request_name(m->bus, "org.freedesktop.resolve1", 0);
f647962d
MS
1542 if (r < 0)
1543 return log_error_errno(r, "Failed to register name: %m");
74b2466e
LP
1544
1545 r = sd_bus_attach_event(m->bus, m->event, 0);
f647962d
MS
1546 if (r < 0)
1547 return log_error_errno(r, "Failed to attach bus to event loop: %m");
74b2466e 1548
902bb5d8
LP
1549 r = sd_bus_add_match(m->bus, &m->prepare_for_sleep_slot,
1550 "type='signal',"
1551 "sender='org.freedesktop.login1',"
1552 "interface='org.freedesktop.login1.Manager',"
1553 "member='PrepareForSleep',"
1554 "path='/org/freedesktop/login1'",
1555 match_prepare_for_sleep,
1556 m);
1557 if (r < 0)
da927ba9 1558 log_error_errno(r, "Failed to add match for PrepareForSleep: %m");
902bb5d8 1559
74b2466e
LP
1560 return 0;
1561}