]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-bus.c
resolved: add ResolveService() bus call for resolving SRV and DNS-SD services
[thirdparty/systemd.git] / src / resolve / resolved-bus.c
CommitLineData
74b2466e
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2014 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
b5efdb8a 22#include "alloc-util.h"
96aad8d1 23#include "bus-common-errors.h"
74b2466e 24#include "bus-util.h"
4ad7f276 25#include "dns-domain.h"
39d8db04 26#include "resolved-bus.h"
51323288 27#include "resolved-def.h"
74b2466e 28
ad867662
LP
29static int reply_query_state(DnsQuery *q) {
30 _cleanup_free_ char *ip = NULL;
31 const char *name;
74b2466e
LP
32 int r;
33
45ec7efb 34 if (q->request_address_valid) {
ad867662
LP
35 r = in_addr_to_string(q->request_family, &q->request_address, &ip);
36 if (r < 0)
37 return r;
74b2466e 38
ad867662 39 name = ip;
45ec7efb
LP
40 } else
41 name = dns_question_name(q->question);
ad867662
LP
42
43 switch (q->state) {
74b2466e 44
ec2c5e43 45 case DNS_TRANSACTION_NO_SERVERS:
309e9d86 46 return sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_NAME_SERVERS, "No appropriate name servers or networks for name found");
74b2466e 47
ec2c5e43 48 case DNS_TRANSACTION_TIMEOUT:
ad867662 49 return sd_bus_reply_method_errorf(q->request, SD_BUS_ERROR_TIMEOUT, "Query timed out");
74b2466e 50
ec2c5e43 51 case DNS_TRANSACTION_ATTEMPTS_MAX_REACHED:
ad867662
LP
52 return sd_bus_reply_method_errorf(q->request, SD_BUS_ERROR_TIMEOUT, "All attempts to contact name servers or networks failed");
53
818f766b
LP
54 case DNS_TRANSACTION_INVALID_REPLY:
55 return sd_bus_reply_method_errorf(q->request, BUS_ERROR_INVALID_REPLY, "Received invalid reply");
56
ec2c5e43 57 case DNS_TRANSACTION_RESOURCES:
ad867662
LP
58 return sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_RESOURCES, "Not enough resources");
59
818f766b
LP
60 case DNS_TRANSACTION_ABORTED:
61 return sd_bus_reply_method_errorf(q->request, BUS_ERROR_ABORTED, "Query aborted");
74b2466e 62
ec2c5e43 63 case DNS_TRANSACTION_FAILURE: {
74b2466e
LP
64 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
65
faa133f3 66 if (q->answer_rcode == DNS_RCODE_NXDOMAIN)
ad867662 67 sd_bus_error_setf(&error, _BUS_ERROR_DNS "NXDOMAIN", "'%s' not found", name);
74b2466e
LP
68 else {
69 const char *rc, *n;
ad867662 70 char p[3]; /* the rcode is 4 bits long */
74b2466e 71
faa133f3 72 rc = dns_rcode_to_string(q->answer_rcode);
74b2466e 73 if (!rc) {
faa133f3 74 sprintf(p, "%i", q->answer_rcode);
74b2466e
LP
75 rc = p;
76 }
77
63c372cb 78 n = strjoina(_BUS_ERROR_DNS, rc);
ad867662 79 sd_bus_error_setf(&error, n, "Could not resolve '%s', server or network returned error %s", name, rc);
74b2466e
LP
80 }
81
ad867662 82 return sd_bus_reply_method_error(q->request, &error);
74b2466e
LP
83 }
84
ec2c5e43
LP
85 case DNS_TRANSACTION_NULL:
86 case DNS_TRANSACTION_PENDING:
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;
ad867662 135 _cleanup_bus_message_unref_ 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) {
148 r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_CNAME_LOOP, "CNAME loop detected, or CNAME resolving disabled on '%s'", dns_question_name(q->question));
149 goto finish;
150 }
151 if (r < 0)
152 goto finish;
153 if (r > 0) /* This was a cname, and the query was restarted. */
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
LP
168 DNS_ANSWER_FOREACH_IFINDEX(rr, ifindex, q->answer) {
169 r = dns_question_matches_rr(q->question, rr);
8ba9fd9c 170 if (r < 0)
2d4c5cbc 171 goto finish;
45ec7efb 172 if (r == 0)
3339cb71 173 continue;
74b2466e 174
45ec7efb 175 r = append_address(reply, rr, ifindex);
3339cb71
LP
176 if (r < 0)
177 goto finish;
74b2466e 178
3339cb71 179 if (!canonical)
45ec7efb 180 canonical = dns_resource_record_ref(rr);
309e9d86 181
3339cb71
LP
182 added ++;
183 }
8ba9fd9c 184 }
74b2466e 185
45ec7efb
LP
186 if (added <= 0) {
187 r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR, "'%s' does not have any RR of the requested type", dns_question_name(q->question));
188 goto finish;
74b2466e
LP
189 }
190
ad867662
LP
191 r = sd_bus_message_close_container(reply);
192 if (r < 0)
193 goto finish;
194
45ec7efb 195 /* Return the precise spelling and uppercasing and CNAME target reported by the server */
309e9d86 196 assert(canonical);
45ec7efb
LP
197 r = sd_bus_message_append(
198 reply, "st",
199 DNS_RESOURCE_KEY_NAME(canonical->key),
200 SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family));
309e9d86
LP
201 if (r < 0)
202 goto finish;
203
ad867662 204 r = sd_bus_send(q->manager->bus, reply, NULL);
ad867662 205
74b2466e 206finish:
2d4c5cbc 207 if (r < 0) {
da927ba9 208 log_error_errno(r, "Failed to send hostname reply: %m");
45ec7efb 209 sd_bus_reply_method_errno(q->request, r, NULL);
2d4c5cbc 210 }
74b2466e
LP
211
212 dns_query_free(q);
213}
214
45ec7efb 215static int check_ifindex_flags(int ifindex, uint64_t *flags, uint64_t ok, sd_bus_error *error) {
51323288
LP
216 assert(flags);
217
218 if (ifindex < 0)
219 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface index");
220
45ec7efb 221 if (*flags & ~(SD_RESOLVED_PROTOCOLS_ALL|SD_RESOLVED_NO_CNAME|ok))
51323288
LP
222 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid flags parameter");
223
45ec7efb
LP
224 if ((*flags & SD_RESOLVED_PROTOCOLS_ALL) == 0) /* If no protocol is enabled, enable all */
225 *flags |= SD_RESOLVED_PROTOCOLS_ALL;
51323288
LP
226
227 return 0;
228}
229
19070062 230static int bus_method_resolve_hostname(sd_bus_message *message, void *userdata, sd_bus_error *error) {
faa133f3 231 _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
74b2466e
LP
232 Manager *m = userdata;
233 const char *hostname;
51323288
LP
234 int family, ifindex;
235 uint64_t flags;
74b2466e 236 DnsQuery *q;
74b2466e
LP
237 int r;
238
74b2466e
LP
239 assert(message);
240 assert(m);
241
45ec7efb
LP
242 assert_cc(sizeof(int) == sizeof(int32_t));
243
51323288 244 r = sd_bus_message_read(message, "isit", &ifindex, &hostname, &family, &flags);
74b2466e
LP
245 if (r < 0)
246 return r;
247
248 if (!IN_SET(family, AF_INET, AF_INET6, AF_UNSPEC))
0dd25fb9 249 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family);
74b2466e 250
45ec7efb 251 r = dns_name_is_valid(hostname);
7b9f7afc 252 if (r < 0)
45ec7efb
LP
253 return r;
254 if (r == 0)
74b2466e
LP
255 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid hostname '%s'", hostname);
256
45ec7efb 257 r = check_ifindex_flags(ifindex, &flags, 0, error);
51323288
LP
258 if (r < 0)
259 return r;
260
45ec7efb
LP
261 r = dns_question_new_address(&question, family, hostname);
262 if (r < 0)
263 return r;
74b2466e 264
51323288 265 r = dns_query_new(m, &q, question, ifindex, flags);
74b2466e
LP
266 if (r < 0)
267 return r;
268
269 q->request = sd_bus_message_ref(message);
270 q->request_family = family;
74b2466e
LP
271 q->complete = bus_method_resolve_hostname_complete;
272
966c66e3 273 r = dns_query_bus_track(q, message);
82bd6ddd 274 if (r < 0)
45ec7efb 275 goto fail;
82bd6ddd 276
322345fd 277 r = dns_query_go(q);
45ec7efb
LP
278 if (r < 0)
279 goto fail;
74b2466e
LP
280
281 return 1;
45ec7efb
LP
282
283fail:
284 dns_query_free(q);
285 return r;
74b2466e
LP
286}
287
288static void bus_method_resolve_address_complete(DnsQuery *q) {
ad867662 289 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
45ec7efb
LP
290 DnsResourceRecord *rr;
291 unsigned added = 0;
292 int ifindex, r;
74b2466e
LP
293
294 assert(q);
295
ec2c5e43 296 if (q->state != DNS_TRANSACTION_SUCCESS) {
ad867662
LP
297 r = reply_query_state(q);
298 goto finish;
299 }
74b2466e 300
45ec7efb
LP
301 /* We don't process CNAME for PTR lookups. */
302
ad867662
LP
303 r = sd_bus_message_new_method_return(q->request, &reply);
304 if (r < 0)
305 goto finish;
74b2466e 306
78c6a153 307 r = sd_bus_message_open_container(reply, 'a', "(is)");
ad867662
LP
308 if (r < 0)
309 goto finish;
74b2466e 310
3339cb71 311 if (q->answer) {
45ec7efb
LP
312 DNS_ANSWER_FOREACH_IFINDEX(rr, ifindex, q->answer) {
313 r = dns_question_matches_rr(q->question, rr);
3339cb71 314 if (r < 0)
2d4c5cbc 315 goto finish;
3339cb71
LP
316 if (r == 0)
317 continue;
74b2466e 318
45ec7efb 319 r = sd_bus_message_append(reply, "(is)", ifindex, rr->ptr.name);
3339cb71
LP
320 if (r < 0)
321 goto finish;
74b2466e 322
3339cb71
LP
323 added ++;
324 }
ad867662 325 }
74b2466e 326
45ec7efb 327 if (added <= 0) {
ad867662 328 _cleanup_free_ char *ip = NULL;
74b2466e 329
ad867662 330 in_addr_to_string(q->request_family, &q->request_address, &ip);
45ec7efb 331 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 332 goto finish;
74b2466e
LP
333 }
334
ad867662
LP
335 r = sd_bus_message_close_container(reply);
336 if (r < 0)
337 goto finish;
74b2466e 338
51323288
LP
339 r = sd_bus_message_append(reply, "t", SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family));
340 if (r < 0)
341 goto finish;
342
ad867662 343 r = sd_bus_send(q->manager->bus, reply, NULL);
74b2466e
LP
344
345finish:
2d4c5cbc 346 if (r < 0) {
da927ba9 347 log_error_errno(r, "Failed to send address reply: %m");
45ec7efb 348 sd_bus_reply_method_errno(q->request, r, NULL);
2d4c5cbc 349 }
74b2466e
LP
350
351 dns_query_free(q);
352}
353
19070062 354static int bus_method_resolve_address(sd_bus_message *message, void *userdata, sd_bus_error *error) {
faa133f3 355 _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
74b2466e 356 Manager *m = userdata;
faa133f3 357 int family, ifindex;
51323288 358 uint64_t flags;
74b2466e 359 const void *d;
74b2466e
LP
360 DnsQuery *q;
361 size_t sz;
362 int r;
363
74b2466e
LP
364 assert(message);
365 assert(m);
366
45ec7efb
LP
367 assert_cc(sizeof(int) == sizeof(int32_t));
368
51323288 369 r = sd_bus_message_read(message, "ii", &ifindex, &family);
74b2466e
LP
370 if (r < 0)
371 return r;
372
373 if (!IN_SET(family, AF_INET, AF_INET6))
0dd25fb9 374 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family);
74b2466e
LP
375
376 r = sd_bus_message_read_array(message, 'y', &d, &sz);
377 if (r < 0)
378 return r;
379
0dd25fb9 380 if (sz != FAMILY_ADDRESS_SIZE(family))
74b2466e
LP
381 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid address size");
382
51323288
LP
383 r = sd_bus_message_read(message, "t", &flags);
384 if (r < 0)
385 return r;
386
45ec7efb 387 r = check_ifindex_flags(ifindex, &flags, 0, error);
faa133f3
LP
388 if (r < 0)
389 return r;
390
45ec7efb 391 r = dns_question_new_reverse(&question, family, d);
74b2466e
LP
392 if (r < 0)
393 return r;
394
51323288 395 r = dns_query_new(m, &q, question, ifindex, flags);
74b2466e
LP
396 if (r < 0)
397 return r;
398
399 q->request = sd_bus_message_ref(message);
400 q->request_family = family;
401 memcpy(&q->request_address, d, sz);
402 q->complete = bus_method_resolve_address_complete;
403
966c66e3 404 r = dns_query_bus_track(q, message);
82bd6ddd 405 if (r < 0)
45ec7efb 406 goto fail;
82bd6ddd 407
322345fd 408 r = dns_query_go(q);
45ec7efb
LP
409 if (r < 0)
410 goto fail;
74b2466e
LP
411
412 return 1;
45ec7efb
LP
413
414fail:
415 dns_query_free(q);
416 return r;
417}
418
419static int bus_message_append_rr(sd_bus_message *m, DnsResourceRecord *rr, int ifindex) {
420 _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
421 size_t start;
422 int r;
423
424 assert(m);
425 assert(rr);
426
427 r = sd_bus_message_open_container(m, 'r', "iqqay");
428 if (r < 0)
429 return r;
430
431 r = sd_bus_message_append(m, "iqq",
432 ifindex,
433 rr->key->class,
434 rr->key->type);
435 if (r < 0)
436 return r;
437
438 r = dns_packet_new(&p, DNS_PROTOCOL_DNS, 0);
439 if (r < 0)
440 return r;
441
442 p->refuse_compression = true;
443
444 r = dns_packet_append_rr(p, rr, &start);
445 if (r < 0)
446 return r;
447
448 r = sd_bus_message_append_array(m, 'y', DNS_PACKET_DATA(p) + start, p->size - start);
449 if (r < 0)
450 return r;
451
452 return sd_bus_message_close_container(m);
74b2466e
LP
453}
454
2d4c5cbc
LP
455static void bus_method_resolve_record_complete(DnsQuery *q) {
456 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
45ec7efb 457 unsigned added = 0;
2d4c5cbc
LP
458 int r;
459
460 assert(q);
461
ec2c5e43 462 if (q->state != DNS_TRANSACTION_SUCCESS) {
2d4c5cbc
LP
463 r = reply_query_state(q);
464 goto finish;
465 }
466
45ec7efb
LP
467 r = dns_query_process_cname(q);
468 if (r == -ELOOP) {
469 r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_CNAME_LOOP, "CNAME loop detected, or CNAME resolving disabled on '%s'", dns_question_name(q->question));
470 goto finish;
471 }
472 if (r < 0)
473 goto finish;
474 if (r > 0) /* Following a CNAME */
475 return;
476
2d4c5cbc
LP
477 r = sd_bus_message_new_method_return(q->request, &reply);
478 if (r < 0)
479 goto finish;
480
78c6a153 481 r = sd_bus_message_open_container(reply, 'a', "(iqqay)");
2d4c5cbc
LP
482 if (r < 0)
483 goto finish;
484
485 if (q->answer) {
45ec7efb
LP
486 DnsResourceRecord *rr;
487 int ifindex;
2d4c5cbc 488
45ec7efb
LP
489 DNS_ANSWER_FOREACH_IFINDEX(rr, ifindex, q->answer) {
490 r = dns_question_matches_rr(q->question, rr);
2d4c5cbc
LP
491 if (r < 0)
492 goto finish;
493 if (r == 0)
494 continue;
495
45ec7efb 496 r = bus_message_append_rr(reply, rr, ifindex);
2d4c5cbc
LP
497 if (r < 0)
498 goto finish;
499
500 added ++;
501 }
502 }
503
504 if (added <= 0) {
45ec7efb 505 r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR, "Name '%s' does not have any RR of the requested type", dns_question_name(q->question));
2d4c5cbc
LP
506 goto finish;
507 }
508
509 r = sd_bus_message_close_container(reply);
510 if (r < 0)
511 goto finish;
512
51323288
LP
513 r = sd_bus_message_append(reply, "t", SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family));
514 if (r < 0)
515 goto finish;
516
2d4c5cbc
LP
517 r = sd_bus_send(q->manager->bus, reply, NULL);
518
519finish:
520 if (r < 0) {
da927ba9 521 log_error_errno(r, "Failed to send record reply: %m");
45ec7efb 522 sd_bus_reply_method_errno(q->request, r, NULL);
2d4c5cbc
LP
523 }
524
525 dns_query_free(q);
526}
527
19070062 528static int bus_method_resolve_record(sd_bus_message *message, void *userdata, sd_bus_error *error) {
2d4c5cbc
LP
529 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
530 _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
2d4c5cbc 531 Manager *m = userdata;
2d4c5cbc
LP
532 uint16_t class, type;
533 const char *name;
51323288
LP
534 int r, ifindex;
535 uint64_t flags;
536 DnsQuery *q;
2d4c5cbc 537
2d4c5cbc
LP
538 assert(message);
539 assert(m);
540
45ec7efb
LP
541 assert_cc(sizeof(int) == sizeof(int32_t));
542
51323288 543 r = sd_bus_message_read(message, "isqqt", &ifindex, &name, &class, &type, &flags);
2d4c5cbc
LP
544 if (r < 0)
545 return r;
546
45ec7efb 547 r = dns_name_is_valid(name);
7b9f7afc 548 if (r < 0)
45ec7efb
LP
549 return r;
550 if (r == 0)
7b9f7afc
LP
551 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid name '%s'", name);
552
45ec7efb 553 r = check_ifindex_flags(ifindex, &flags, 0, error);
51323288
LP
554 if (r < 0)
555 return r;
556
2d4c5cbc
LP
557 question = dns_question_new(1);
558 if (!question)
559 return -ENOMEM;
560
561 key = dns_resource_key_new(class, type, name);
562 if (!key)
563 return -ENOMEM;
564
565 r = dns_question_add(question, key);
566 if (r < 0)
567 return r;
568
51323288 569 r = dns_query_new(m, &q, question, ifindex, flags);
2d4c5cbc
LP
570 if (r < 0)
571 return r;
572
573 q->request = sd_bus_message_ref(message);
2d4c5cbc
LP
574 q->complete = bus_method_resolve_record_complete;
575
966c66e3 576 r = dns_query_bus_track(q, message);
82bd6ddd 577 if (r < 0)
45ec7efb 578 goto fail;
82bd6ddd 579
2d4c5cbc 580 r = dns_query_go(q);
45ec7efb
LP
581 if (r < 0)
582 goto fail;
583
584 return 1;
585
586fail:
587 dns_query_free(q);
588 return r;
589}
590
591static int append_srv(DnsQuery *q, sd_bus_message *reply, DnsResourceRecord *rr) {
592 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *canonical = NULL;
593 DnsQuery *aux;
594 int r;
595
596 assert(q);
597 assert(reply);
598 assert(rr);
599 assert(rr->key);
600
601 if (rr->key->type != DNS_TYPE_SRV)
602 return 0;
603
604 if ((q->flags & SD_RESOLVED_NO_ADDRESS) == 0) {
605 /* First, let's see if we could find an appropriate A or AAAA
606 * record for the SRV record */
607 LIST_FOREACH(auxiliary_queries, aux, q->auxiliary_queries) {
608 DnsResourceRecord *zz;
609
610 if (aux->state != DNS_TRANSACTION_SUCCESS)
611 continue;
612 if (aux->auxiliary_result != 0)
613 continue;
614
615 r = dns_name_equal(dns_question_name(aux->question), rr->srv.name);
616 if (r < 0)
617 return r;
618 if (r == 0)
619 continue;
620
621 DNS_ANSWER_FOREACH(zz, aux->answer) {
622
623 r = dns_question_matches_rr(aux->question, zz);
624 if (r < 0)
625 return r;
626 if (r == 0)
627 continue;
628
629 canonical = dns_resource_record_ref(zz);
630 break;
631 }
632
633 if (canonical)
634 break;
635 }
636
637 /* Is there are successful A/AAAA lookup for this SRV RR? If not, don't add it */
638 if (!canonical)
639 return 0;
640 }
641
642 r = sd_bus_message_open_container(reply, 'r', "qqqsa(iiay)s");
643 if (r < 0)
644 return r;
645
646 r = sd_bus_message_append(
647 reply,
648 "qqqs",
649 rr->srv.priority, rr->srv.weight, rr->srv.port, rr->srv.name);
650 if (r < 0)
651 return r;
652
653 r = sd_bus_message_open_container(reply, 'a', "(iiay)");
654 if (r < 0)
655 return r;
656
657 if ((q->flags & SD_RESOLVED_NO_ADDRESS) == 0) {
658 LIST_FOREACH(auxiliary_queries, aux, q->auxiliary_queries) {
659 DnsResourceRecord *zz;
660 int ifindex;
661
662 if (aux->state != DNS_TRANSACTION_SUCCESS)
663 continue;
664 if (aux->auxiliary_result != 0)
665 continue;
666
667 r = dns_name_equal(dns_question_name(aux->question), rr->srv.name);
668 if (r < 0)
669 return r;
670 if (r == 0)
671 continue;
672
673 DNS_ANSWER_FOREACH_IFINDEX(zz, ifindex, aux->answer) {
674
675 r = dns_question_matches_rr(aux->question, zz);
676 if (r < 0)
677 return r;
678 if (r == 0)
679 continue;
680
681 r = append_address(reply, zz, ifindex);
682 if (r < 0)
683 return r;
684 }
685 }
686 }
687
688 r = sd_bus_message_close_container(reply);
689 if (r < 0)
690 return r;
691
692 /* Note that above we appended the hostname as encoded in the
693 * SRV, and here the canonical hostname this maps to. */
694 r = sd_bus_message_append(reply, "s", canonical ? DNS_RESOURCE_KEY_NAME(canonical->key) : rr->srv.name);
695 if (r < 0)
696 return r;
697
698 r = sd_bus_message_close_container(reply);
699 if (r < 0)
700 return r;
701
702 return 1;
703}
704
705static int append_txt(sd_bus_message *reply, DnsResourceRecord *rr) {
706 DnsTxtItem *i;
707 int r;
708
709 assert(reply);
710 assert(rr);
711 assert(rr->key);
712
713 if (rr->key->type != DNS_TYPE_TXT)
714 return 0;
715
716 LIST_FOREACH(items, i, rr->txt.items) {
717
718 if (i->length <= 0)
719 continue;
720
721 r = sd_bus_message_append_array(reply, 'y', i->data, i->length);
722 if (r < 0)
723 return r;
724 }
725
726 return 1;
727}
728
729static void resolve_service_all_complete(DnsQuery *q) {
730 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *canonical = NULL;
731 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
732 _cleanup_free_ char *name = NULL, *type = NULL, *domain = NULL;
733 DnsQuery *aux;
734 unsigned added = false;
735 int r;
736
737 assert(q);
738
739 if (q->block_all_complete > 0)
740 return;
741
742 if ((q->flags & SD_RESOLVED_NO_ADDRESS) == 0) {
743 DnsQuery *bad = NULL;
744 bool have_success = false;
745
746 LIST_FOREACH(auxiliary_queries, aux, q->auxiliary_queries) {
747
748 switch (aux->state) {
749
750 case DNS_TRANSACTION_PENDING:
751 /* If an auxiliary query is still pending, let's wait */
752 return;
753
754 case DNS_TRANSACTION_SUCCESS:
755 if (aux->auxiliary_result == 0)
756 have_success = true;
757 else
758 bad = aux;
759 break;
760
761 default:
762 bad = aux;
763 break;
764 }
765 }
766
767 if (!have_success) {
768 /* We can only return one error, hence pick the last error we encountered */
769
770 assert(bad);
771
772 if (bad->state == DNS_TRANSACTION_SUCCESS) {
773 assert(bad->auxiliary_result != 0);
774
775 if (bad->auxiliary_result == -ELOOP) {
776 r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_CNAME_LOOP, "CNAME loop detected, or CNAME resolving disabled on '%s'", dns_question_name(bad->question));
777 goto finish;
778 }
779
780 r = bad->auxiliary_result;
781 goto finish;
782 }
783
784 r = reply_query_state(bad);
785 goto finish;
786 }
787 }
788
789 r = sd_bus_message_new_method_return(q->request, &reply);
790 if (r < 0)
791 goto finish;
792
793 r = sd_bus_message_open_container(reply, 'a', "(qqqsa(iiay)s)");
794 if (r < 0)
795 goto finish;
796
797 if (q->answer) {
798 DnsResourceRecord *rr;
799
800 DNS_ANSWER_FOREACH(rr, q->answer) {
801 r = dns_question_matches_rr(q->question, rr);
802 if (r < 0)
803 goto finish;
804 if (r == 0)
805 continue;
806
807 r = append_srv(q, reply, rr);
808 if (r < 0)
809 goto finish;
810 if (r == 0) /* not an SRV record */
811 continue;
812
813 if (!canonical)
814 canonical = dns_resource_record_ref(rr);
815
816 added++;
817 }
818 }
819
820 if (added <= 0) {
821 r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR, "'%s' does not have any RR of the requested type", dns_question_name(q->question));
822 goto finish;
823 }
824
825 r = sd_bus_message_close_container(reply);
826 if (r < 0)
827 goto finish;
828
829 r = sd_bus_message_open_container(reply, 'a', "ay");
830 if (r < 0)
831 goto finish;
832
833 if (q->answer) {
834 DnsResourceRecord *rr;
835
836 DNS_ANSWER_FOREACH(rr, q->answer) {
837 r = dns_question_matches_rr(q->question, rr);
838 if (r < 0)
839 goto finish;
840 if (r == 0)
841 continue;
842
843 r = append_txt(reply, rr);
844 if (r < 0)
845 goto finish;
846 }
847 }
848
849 r = sd_bus_message_close_container(reply);
850 if (r < 0)
851 goto finish;
852
853 assert(canonical);
854 r = dns_service_split(DNS_RESOURCE_KEY_NAME(canonical->key), &name, &type, &domain);
855 if (r < 0)
856 goto finish;
857
858 r = sd_bus_message_append(
859 reply,
860 "ssst",
861 name, type, domain,
862 SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family));
863 if (r < 0)
864 goto finish;
865
866 r = sd_bus_send(q->manager->bus, reply, NULL);
867
868finish:
869 if (r < 0) {
870 log_error_errno(r, "Failed to send service reply: %m");
871 sd_bus_reply_method_errno(q->request, r, NULL);
872 }
873
874 dns_query_free(q);
875}
876
877static void resolve_service_hostname_complete(DnsQuery *q) {
878 int r;
879
880 assert(q);
881 assert(q->auxiliary_for);
882
883 if (q->state != DNS_TRANSACTION_SUCCESS) {
884 resolve_service_all_complete(q->auxiliary_for);
885 return;
886 }
887
888 r = dns_query_process_cname(q);
889 if (r > 0) /* This was a cname, and the query was restarted. */
890 return;
891
892 /* This auxiliary lookup is finished or failed, let's see if all are finished now. */
893 q->auxiliary_result = r;
894 resolve_service_all_complete(q->auxiliary_for);
895}
896
897static int resolve_service_hostname(DnsQuery *q, DnsResourceRecord *rr, int ifindex) {
898 _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
899 DnsQuery *aux;
900 int r;
901
902 assert(q);
903 assert(rr);
904 assert(rr->key);
905 assert(rr->key->type == DNS_TYPE_SRV);
906
907 /* OK, we found an SRV record for the service. Let's resolve
908 * the hostname included in it */
909
910 r = dns_question_new_address(&question, q->request_family, rr->srv.name);
911 if (r < 0)
912 return r;
913
914 r = dns_query_new(q->manager, &aux, question, ifindex, q->flags);
915 if (r < 0)
916 return r;
917
918 aux->request_family = q->request_family;
919 aux->complete = resolve_service_hostname_complete;
920
921 r = dns_query_make_auxiliary(aux, q);
922 if (r == -EAGAIN) {
923 /* Too many auxiliary lookups? If so, don't complain,
924 * let's just not add this one, we already have more
925 * than enough */
926
927 dns_query_free(aux);
928 return 0;
929 }
930 if (r < 0)
931 goto fail;
932
933 /* Note that auxiliary queries do not track the original bus
934 * client, only the primary request does that. */
935
936 r = dns_query_go(aux);
937 if (r < 0)
938 goto fail;
939
940 return 1;
941
942fail:
943 dns_query_free(aux);
944 return r;
945}
946
947static void bus_method_resolve_service_complete(DnsQuery *q) {
948 unsigned found = 0;
949 int r;
950
951 assert(q);
952
953 if (q->state != DNS_TRANSACTION_SUCCESS) {
954 r = reply_query_state(q);
955 goto finish;
956 }
957
958 r = dns_query_process_cname(q);
959 if (r == -ELOOP) {
960 r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_CNAME_LOOP, "CNAME loop detected, or CNAME resolving disabled on '%s'", dns_question_name(q->question));
961 goto finish;
962 }
963 if (r < 0)
964 goto finish;
965 if (r > 0) /* This was a cname, and the query was restarted. */
966 return;
967
968 if (q->answer) {
969 DnsResourceRecord *rr;
970 int ifindex;
971
972 DNS_ANSWER_FOREACH_IFINDEX(rr, ifindex, q->answer) {
973 r = dns_question_matches_rr(q->question, rr);
974 if (r < 0)
975 goto finish;
976 if (r == 0)
977 continue;
978
979 if (rr->key->type != DNS_TYPE_SRV)
980 continue;
981
982 if ((q->flags & SD_RESOLVED_NO_ADDRESS) == 0) {
983 q->block_all_complete ++;
984 r = resolve_service_hostname(q, rr, ifindex);
985 q->block_all_complete --;
986
987 if (r < 0)
988 goto finish;
989 }
990
991 found++;
992 }
993 }
994
995 if (found <= 0) {
996 r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR, "'%s' does not have any RR of the requested type", dns_question_name(q->question));
997 goto finish;
998 }
999
1000 /* Maybe we are already finished? check now... */
1001 resolve_service_all_complete(q);
1002 return;
1003
1004finish:
2d4c5cbc 1005 if (r < 0) {
45ec7efb
LP
1006 log_error_errno(r, "Failed to send service reply: %m");
1007 sd_bus_reply_method_errno(q->request, r, NULL);
1008 }
1009
1010 dns_query_free(q);
1011}
1012
1013static int bus_method_resolve_service(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1014 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
1015 _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
1016 const char *name, *type, *domain, *joined;
1017 _cleanup_free_ char *n = NULL;
1018 Manager *m = userdata;
1019 int family, ifindex;
1020 uint64_t flags;
1021 DnsQuery *q;
1022 int r;
1023
1024 assert(message);
1025 assert(m);
1026
1027 assert_cc(sizeof(int) == sizeof(int32_t));
1028
1029 r = sd_bus_message_read(message, "isssit", &ifindex, &name, &type, &domain, &family, &flags);
1030 if (r < 0)
2d4c5cbc 1031 return r;
45ec7efb
LP
1032
1033 if (!IN_SET(family, AF_INET, AF_INET6, AF_UNSPEC))
1034 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family);
1035
1036 if (isempty(name))
1037 name = NULL;
1038 else {
1039 if (!dns_service_name_is_valid(name))
1040 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid service name '%s'", name);
2d4c5cbc
LP
1041 }
1042
45ec7efb
LP
1043 if (isempty(type))
1044 type = NULL;
1045 else {
1046 r = dns_srv_type_verify(type);
1047 if (r < 0)
1048 return r;
1049 if (r == 0)
1050 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid SRV service type '%s'", type);
1051 }
1052
1053 r = dns_name_is_valid(domain);
1054 if (r < 0)
1055 return r;
1056 if (r == 0)
1057 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid domain '%s'", domain);
1058
1059 if (name && !type)
1060 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Service name cannot be specified without service type.");
1061
1062 r = check_ifindex_flags(ifindex, &flags, SD_RESOLVED_NO_TXT|SD_RESOLVED_NO_ADDRESS, error);
1063 if (r < 0)
1064 return r;
1065
1066 if (type) {
1067 /* If the type is specified, we generate the full domain name to look up ourselves */
1068 r = dns_service_join(name, type, domain, &n);
1069 if (r < 0)
1070 return r;
1071
1072 joined = n;
1073 } else
1074 /* If no type is specified, we assume the domain
1075 * contains the full domain name to lookup already */
1076 joined = domain;
1077
1078 r = dns_question_new_service(&question, joined, !(flags & SD_RESOLVED_NO_TXT));
1079 if (r < 0)
1080 return r;
1081
1082 r = dns_query_new(m, &q, question, ifindex, flags);
1083 if (r < 0)
1084 return r;
1085
1086 q->request = sd_bus_message_ref(message);
1087 q->request_family = family;
1088 q->complete = bus_method_resolve_service_complete;
1089
1090 r = dns_query_bus_track(q, message);
1091 if (r < 0)
1092 goto fail;
1093
1094 r = dns_query_go(q);
1095 if (r < 0)
1096 goto fail;
1097
2d4c5cbc 1098 return 1;
45ec7efb
LP
1099
1100fail:
1101 dns_query_free(q);
1102 return r;
2d4c5cbc
LP
1103}
1104
74b2466e
LP
1105static const sd_bus_vtable resolve_vtable[] = {
1106 SD_BUS_VTABLE_START(0),
78c6a153
LP
1107 SD_BUS_METHOD("ResolveHostname", "isit", "a(iiay)st", bus_method_resolve_hostname, SD_BUS_VTABLE_UNPRIVILEGED),
1108 SD_BUS_METHOD("ResolveAddress", "iiayt", "a(is)t", bus_method_resolve_address, SD_BUS_VTABLE_UNPRIVILEGED),
1109 SD_BUS_METHOD("ResolveRecord", "isqqt", "a(iqqay)t", bus_method_resolve_record, SD_BUS_VTABLE_UNPRIVILEGED),
45ec7efb 1110 SD_BUS_METHOD("ResolveService", "isssit", "a(qqqsa(iiay)s)aayssst", bus_method_resolve_service, SD_BUS_VTABLE_UNPRIVILEGED),
74b2466e
LP
1111 SD_BUS_VTABLE_END,
1112};
1113
1114static int on_bus_retry(sd_event_source *s, usec_t usec, void *userdata) {
1115 Manager *m = userdata;
1116
1117 assert(s);
1118 assert(m);
1119
1120 m->bus_retry_event_source = sd_event_source_unref(m->bus_retry_event_source);
1121
1122 manager_connect_bus(m);
1123 return 0;
1124}
1125
19070062 1126static int match_prepare_for_sleep(sd_bus_message *message, void *userdata, sd_bus_error *ret_error) {
902bb5d8
LP
1127 Manager *m = userdata;
1128 int b, r;
1129
19070062
LP
1130 assert(message);
1131 assert(m);
902bb5d8
LP
1132
1133 r = sd_bus_message_read(message, "b", &b);
1134 if (r < 0) {
da927ba9 1135 log_debug_errno(r, "Failed to parse PrepareForSleep signal: %m");
902bb5d8
LP
1136 return 0;
1137 }
1138
1139 if (b)
1140 return 0;
1141
1142 log_debug("Coming back from suspend, verifying all RRs...");
1143
1144 manager_verify_all(m);
1145 return 0;
1146}
1147
74b2466e
LP
1148int manager_connect_bus(Manager *m) {
1149 int r;
1150
1151 assert(m);
1152
1153 if (m->bus)
1154 return 0;
1155
1156 r = sd_bus_default_system(&m->bus);
1157 if (r < 0) {
1158 /* We failed to connect? Yuck, we must be in early
1159 * boot. Let's try in 5s again. As soon as we have
1160 * kdbus we can stop doing this... */
1161
da927ba9 1162 log_debug_errno(r, "Failed to connect to bus, trying again in 5s: %m");
74b2466e
LP
1163
1164 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
1165 if (r < 0)
1166 return log_error_errno(r, "Failed to install bus reconnect time event: %m");
74b2466e
LP
1167
1168 return 0;
1169 }
1170
4d1cf1e2 1171 r = sd_bus_add_object_vtable(m->bus, NULL, "/org/freedesktop/resolve1", "org.freedesktop.resolve1.Manager", resolve_vtable, m);
f647962d
MS
1172 if (r < 0)
1173 return log_error_errno(r, "Failed to register object: %m");
74b2466e
LP
1174
1175 r = sd_bus_request_name(m->bus, "org.freedesktop.resolve1", 0);
f647962d
MS
1176 if (r < 0)
1177 return log_error_errno(r, "Failed to register name: %m");
74b2466e
LP
1178
1179 r = sd_bus_attach_event(m->bus, m->event, 0);
f647962d
MS
1180 if (r < 0)
1181 return log_error_errno(r, "Failed to attach bus to event loop: %m");
74b2466e 1182
902bb5d8
LP
1183 r = sd_bus_add_match(m->bus, &m->prepare_for_sleep_slot,
1184 "type='signal',"
1185 "sender='org.freedesktop.login1',"
1186 "interface='org.freedesktop.login1.Manager',"
1187 "member='PrepareForSleep',"
1188 "path='/org/freedesktop/login1'",
1189 match_prepare_for_sleep,
1190 m);
1191 if (r < 0)
da927ba9 1192 log_error_errno(r, "Failed to add match for PrepareForSleep: %m");
902bb5d8 1193
74b2466e
LP
1194 return 0;
1195}