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