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