]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/resolve/resolved-bus.c
resolved: fully support DNS search domains
[thirdparty/systemd.git] / src / resolve / resolved-bus.c
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
22 #include "alloc-util.h"
23 #include "bus-common-errors.h"
24 #include "bus-util.h"
25 #include "dns-domain.h"
26 #include "resolved-bus.h"
27 #include "resolved-def.h"
28
29 static int reply_query_state(DnsQuery *q) {
30 _cleanup_free_ char *ip = NULL;
31 const char *name;
32 int r;
33
34 if (q->request_address_valid) {
35 r = in_addr_to_string(q->request_family, &q->request_address, &ip);
36 if (r < 0)
37 return r;
38
39 name = ip;
40 } else
41 name = dns_question_first_name(q->question);
42
43 switch (q->state) {
44
45 case DNS_TRANSACTION_NO_SERVERS:
46 return sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_NAME_SERVERS, "No appropriate name servers or networks for name found");
47
48 case DNS_TRANSACTION_TIMEOUT:
49 return sd_bus_reply_method_errorf(q->request, SD_BUS_ERROR_TIMEOUT, "Query timed out");
50
51 case DNS_TRANSACTION_ATTEMPTS_MAX_REACHED:
52 return sd_bus_reply_method_errorf(q->request, SD_BUS_ERROR_TIMEOUT, "All attempts to contact name servers or networks failed");
53
54 case DNS_TRANSACTION_INVALID_REPLY:
55 return sd_bus_reply_method_errorf(q->request, BUS_ERROR_INVALID_REPLY, "Received invalid reply");
56
57 case DNS_TRANSACTION_RESOURCES:
58 return sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_RESOURCES, "Not enough resources");
59
60 case DNS_TRANSACTION_ABORTED:
61 return sd_bus_reply_method_errorf(q->request, BUS_ERROR_ABORTED, "Query aborted");
62
63 case DNS_TRANSACTION_FAILURE: {
64 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
65
66 if (q->answer_rcode == DNS_RCODE_NXDOMAIN)
67 sd_bus_error_setf(&error, _BUS_ERROR_DNS "NXDOMAIN", "'%s' not found", name);
68 else {
69 const char *rc, *n;
70 char p[3]; /* the rcode is 4 bits long */
71
72 rc = dns_rcode_to_string(q->answer_rcode);
73 if (!rc) {
74 sprintf(p, "%i", q->answer_rcode);
75 rc = p;
76 }
77
78 n = strjoina(_BUS_ERROR_DNS, rc);
79 sd_bus_error_setf(&error, n, "Could not resolve '%s', server or network returned error %s", name, rc);
80 }
81
82 return sd_bus_reply_method_error(q->request, &error);
83 }
84
85 case DNS_TRANSACTION_NULL:
86 case DNS_TRANSACTION_PENDING:
87 case DNS_TRANSACTION_SUCCESS:
88 default:
89 assert_not_reached("Impossible state");
90 }
91 }
92
93 static int append_address(sd_bus_message *reply, DnsResourceRecord *rr, int ifindex) {
94 int r;
95
96 assert(reply);
97 assert(rr);
98
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);
104 if (r < 0)
105 return r;
106
107 if (rr->key->type == DNS_TYPE_A) {
108 r = sd_bus_message_append(reply, "i", AF_INET);
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));
113
114 } else if (rr->key->type == DNS_TYPE_AAAA) {
115 r = sd_bus_message_append(reply, "i", AF_INET6);
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));
120 } else
121 return -EAFNOSUPPORT;
122
123 if (r < 0)
124 return r;
125
126 r = sd_bus_message_close_container(reply);
127 if (r < 0)
128 return r;
129
130 return 0;
131 }
132
133 static void bus_method_resolve_hostname_complete(DnsQuery *q) {
134 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *canonical = NULL;
135 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
136 unsigned added = 0;
137 int r;
138
139 assert(q);
140
141 if (q->state != DNS_TRANSACTION_SUCCESS) {
142 r = reply_query_state(q);
143 goto finish;
144 }
145
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_first_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
156 r = sd_bus_message_new_method_return(q->request, &reply);
157 if (r < 0)
158 goto finish;
159
160 r = sd_bus_message_open_container(reply, 'a', "(iiay)");
161 if (r < 0)
162 goto finish;
163
164 if (q->answer) {
165 DnsResourceRecord *rr;
166 int ifindex;
167
168 DNS_ANSWER_FOREACH_IFINDEX(rr, ifindex, q->answer) {
169 r = dns_question_matches_rr(q->question, rr, DNS_SEARCH_DOMAIN_NAME(q->answer_search_domain));
170 if (r < 0)
171 goto finish;
172 if (r == 0)
173 continue;
174
175 r = append_address(reply, rr, ifindex);
176 if (r < 0)
177 goto finish;
178
179 if (!canonical)
180 canonical = dns_resource_record_ref(rr);
181
182 added ++;
183 }
184 }
185
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_first_name(q->question));
188 goto finish;
189 }
190
191 r = sd_bus_message_close_container(reply);
192 if (r < 0)
193 goto finish;
194
195 /* Return the precise spelling and uppercasing and CNAME target reported by the server */
196 assert(canonical);
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));
201 if (r < 0)
202 goto finish;
203
204 r = sd_bus_send(q->manager->bus, reply, NULL);
205
206 finish:
207 if (r < 0) {
208 log_error_errno(r, "Failed to send hostname reply: %m");
209 sd_bus_reply_method_errno(q->request, r, NULL);
210 }
211
212 dns_query_free(q);
213 }
214
215 static int check_ifindex_flags(int ifindex, uint64_t *flags, uint64_t ok, sd_bus_error *error) {
216 assert(flags);
217
218 if (ifindex < 0)
219 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface index");
220
221 if (*flags & ~(SD_RESOLVED_PROTOCOLS_ALL|SD_RESOLVED_NO_CNAME|ok))
222 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid flags parameter");
223
224 if ((*flags & SD_RESOLVED_PROTOCOLS_ALL) == 0) /* If no protocol is enabled, enable all */
225 *flags |= SD_RESOLVED_PROTOCOLS_ALL;
226
227 return 0;
228 }
229
230 static int bus_method_resolve_hostname(sd_bus_message *message, void *userdata, sd_bus_error *error) {
231 _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
232 Manager *m = userdata;
233 const char *hostname;
234 int family, ifindex;
235 uint64_t flags;
236 DnsQuery *q;
237 int r;
238
239 assert(message);
240 assert(m);
241
242 assert_cc(sizeof(int) == sizeof(int32_t));
243
244 r = sd_bus_message_read(message, "isit", &ifindex, &hostname, &family, &flags);
245 if (r < 0)
246 return r;
247
248 if (!IN_SET(family, AF_INET, AF_INET6, AF_UNSPEC))
249 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family);
250
251 r = dns_name_is_valid(hostname);
252 if (r < 0)
253 return r;
254 if (r == 0)
255 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid hostname '%s'", hostname);
256
257 r = check_ifindex_flags(ifindex, &flags, SD_RESOLVED_NO_SEARCH, error);
258 if (r < 0)
259 return r;
260
261 r = dns_question_new_address(&question, family, hostname);
262 if (r < 0)
263 return r;
264
265 r = dns_query_new(m, &q, question, ifindex, flags);
266 if (r < 0)
267 return r;
268
269 q->request = sd_bus_message_ref(message);
270 q->request_family = family;
271 q->complete = bus_method_resolve_hostname_complete;
272
273 r = dns_query_bus_track(q, message);
274 if (r < 0)
275 goto fail;
276
277 r = dns_query_go(q);
278 if (r < 0)
279 goto fail;
280
281 return 1;
282
283 fail:
284 dns_query_free(q);
285 return r;
286 }
287
288 static void bus_method_resolve_address_complete(DnsQuery *q) {
289 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
290 DnsResourceRecord *rr;
291 unsigned added = 0;
292 int ifindex, r;
293
294 assert(q);
295
296 if (q->state != DNS_TRANSACTION_SUCCESS) {
297 r = reply_query_state(q);
298 goto finish;
299 }
300
301 /* We don't process CNAME for PTR lookups. */
302
303 r = sd_bus_message_new_method_return(q->request, &reply);
304 if (r < 0)
305 goto finish;
306
307 r = sd_bus_message_open_container(reply, 'a', "(is)");
308 if (r < 0)
309 goto finish;
310
311 if (q->answer) {
312 DNS_ANSWER_FOREACH_IFINDEX(rr, ifindex, q->answer) {
313 r = dns_question_matches_rr(q->question, rr, NULL);
314 if (r < 0)
315 goto finish;
316 if (r == 0)
317 continue;
318
319 r = sd_bus_message_append(reply, "(is)", ifindex, rr->ptr.name);
320 if (r < 0)
321 goto finish;
322
323 added ++;
324 }
325 }
326
327 if (added <= 0) {
328 _cleanup_free_ char *ip = NULL;
329
330 in_addr_to_string(q->request_family, &q->request_address, &ip);
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));
332 goto finish;
333 }
334
335 r = sd_bus_message_close_container(reply);
336 if (r < 0)
337 goto finish;
338
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
343 r = sd_bus_send(q->manager->bus, reply, NULL);
344
345 finish:
346 if (r < 0) {
347 log_error_errno(r, "Failed to send address reply: %m");
348 sd_bus_reply_method_errno(q->request, r, NULL);
349 }
350
351 dns_query_free(q);
352 }
353
354 static int bus_method_resolve_address(sd_bus_message *message, void *userdata, sd_bus_error *error) {
355 _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
356 Manager *m = userdata;
357 int family, ifindex;
358 uint64_t flags;
359 const void *d;
360 DnsQuery *q;
361 size_t sz;
362 int r;
363
364 assert(message);
365 assert(m);
366
367 assert_cc(sizeof(int) == sizeof(int32_t));
368
369 r = sd_bus_message_read(message, "ii", &ifindex, &family);
370 if (r < 0)
371 return r;
372
373 if (!IN_SET(family, AF_INET, AF_INET6))
374 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family);
375
376 r = sd_bus_message_read_array(message, 'y', &d, &sz);
377 if (r < 0)
378 return r;
379
380 if (sz != FAMILY_ADDRESS_SIZE(family))
381 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid address size");
382
383 r = sd_bus_message_read(message, "t", &flags);
384 if (r < 0)
385 return r;
386
387 r = check_ifindex_flags(ifindex, &flags, 0, error);
388 if (r < 0)
389 return r;
390
391 r = dns_question_new_reverse(&question, family, d);
392 if (r < 0)
393 return r;
394
395 r = dns_query_new(m, &q, question, ifindex, flags|SD_RESOLVED_NO_SEARCH);
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
404 r = dns_query_bus_track(q, message);
405 if (r < 0)
406 goto fail;
407
408 r = dns_query_go(q);
409 if (r < 0)
410 goto fail;
411
412 return 1;
413
414 fail:
415 dns_query_free(q);
416 return r;
417 }
418
419 static 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);
453 }
454
455 static void bus_method_resolve_record_complete(DnsQuery *q) {
456 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
457 unsigned added = 0;
458 int r;
459
460 assert(q);
461
462 if (q->state != DNS_TRANSACTION_SUCCESS) {
463 r = reply_query_state(q);
464 goto finish;
465 }
466
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_first_name(q->question));
470 goto finish;
471 }
472 if (r < 0)
473 goto finish;
474 if (r > 0) /* Following a CNAME */
475 return;
476
477 r = sd_bus_message_new_method_return(q->request, &reply);
478 if (r < 0)
479 goto finish;
480
481 r = sd_bus_message_open_container(reply, 'a', "(iqqay)");
482 if (r < 0)
483 goto finish;
484
485 if (q->answer) {
486 DnsResourceRecord *rr;
487 int ifindex;
488
489 DNS_ANSWER_FOREACH_IFINDEX(rr, ifindex, q->answer) {
490 r = dns_question_matches_rr(q->question, rr, NULL);
491 if (r < 0)
492 goto finish;
493 if (r == 0)
494 continue;
495
496 r = bus_message_append_rr(reply, rr, ifindex);
497 if (r < 0)
498 goto finish;
499
500 added ++;
501 }
502 }
503
504 if (added <= 0) {
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_first_name(q->question));
506 goto finish;
507 }
508
509 r = sd_bus_message_close_container(reply);
510 if (r < 0)
511 goto finish;
512
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
517 r = sd_bus_send(q->manager->bus, reply, NULL);
518
519 finish:
520 if (r < 0) {
521 log_error_errno(r, "Failed to send record reply: %m");
522 sd_bus_reply_method_errno(q->request, r, NULL);
523 }
524
525 dns_query_free(q);
526 }
527
528 static int bus_method_resolve_record(sd_bus_message *message, void *userdata, sd_bus_error *error) {
529 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
530 _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
531 Manager *m = userdata;
532 uint16_t class, type;
533 const char *name;
534 int r, ifindex;
535 uint64_t flags;
536 DnsQuery *q;
537
538 assert(message);
539 assert(m);
540
541 assert_cc(sizeof(int) == sizeof(int32_t));
542
543 r = sd_bus_message_read(message, "isqqt", &ifindex, &name, &class, &type, &flags);
544 if (r < 0)
545 return r;
546
547 r = dns_name_is_valid(name);
548 if (r < 0)
549 return r;
550 if (r == 0)
551 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid name '%s'", name);
552
553 r = check_ifindex_flags(ifindex, &flags, 0, error);
554 if (r < 0)
555 return r;
556
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
569 r = dns_query_new(m, &q, question, ifindex, flags|SD_RESOLVED_NO_SEARCH);
570 if (r < 0)
571 return r;
572
573 q->request = sd_bus_message_ref(message);
574 q->complete = bus_method_resolve_record_complete;
575
576 r = dns_query_bus_track(q, message);
577 if (r < 0)
578 goto fail;
579
580 r = dns_query_go(q);
581 if (r < 0)
582 goto fail;
583
584 return 1;
585
586 fail:
587 dns_query_free(q);
588 return r;
589 }
590
591 static 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_first_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, NULL);
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_first_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, NULL);
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
705 static 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
729 static 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_first_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, NULL);
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_first_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, NULL);
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
868 finish:
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
877 static 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
897 static 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|SD_RESOLVED_NO_SEARCH);
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
942 fail:
943 dns_query_free(aux);
944 return r;
945 }
946
947 static 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_first_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, NULL);
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_first_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
1004 finish:
1005 if (r < 0) {
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
1013 static int bus_method_resolve_service(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1014 _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
1015 const char *name, *type, *domain, *joined;
1016 _cleanup_free_ char *n = NULL;
1017 Manager *m = userdata;
1018 int family, ifindex;
1019 uint64_t flags;
1020 DnsQuery *q;
1021 int r;
1022
1023 assert(message);
1024 assert(m);
1025
1026 assert_cc(sizeof(int) == sizeof(int32_t));
1027
1028 r = sd_bus_message_read(message, "isssit", &ifindex, &name, &type, &domain, &family, &flags);
1029 if (r < 0)
1030 return r;
1031
1032 if (!IN_SET(family, AF_INET, AF_INET6, AF_UNSPEC))
1033 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family);
1034
1035 if (isempty(name))
1036 name = NULL;
1037 else {
1038 if (!dns_service_name_is_valid(name))
1039 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid service name '%s'", name);
1040 }
1041
1042 if (isempty(type))
1043 type = NULL;
1044 else {
1045 r = dns_srv_type_verify(type);
1046 if (r < 0)
1047 return r;
1048 if (r == 0)
1049 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid SRV service type '%s'", type);
1050 }
1051
1052 r = dns_name_is_valid(domain);
1053 if (r < 0)
1054 return r;
1055 if (r == 0)
1056 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid domain '%s'", domain);
1057
1058 if (name && !type)
1059 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Service name cannot be specified without service type.");
1060
1061 r = check_ifindex_flags(ifindex, &flags, SD_RESOLVED_NO_TXT|SD_RESOLVED_NO_ADDRESS, error);
1062 if (r < 0)
1063 return r;
1064
1065 if (type) {
1066 /* If the type is specified, we generate the full domain name to look up ourselves */
1067 r = dns_service_join(name, type, domain, &n);
1068 if (r < 0)
1069 return r;
1070
1071 joined = n;
1072 } else
1073 /* If no type is specified, we assume the domain
1074 * contains the full domain name to lookup already */
1075 joined = domain;
1076
1077 r = dns_question_new_service(&question, joined, !(flags & SD_RESOLVED_NO_TXT));
1078 if (r < 0)
1079 return r;
1080
1081 r = dns_query_new(m, &q, question, ifindex, flags|SD_RESOLVED_NO_SEARCH);
1082 if (r < 0)
1083 return r;
1084
1085 q->request = sd_bus_message_ref(message);
1086 q->request_family = family;
1087 q->complete = bus_method_resolve_service_complete;
1088
1089 r = dns_query_bus_track(q, message);
1090 if (r < 0)
1091 goto fail;
1092
1093 r = dns_query_go(q);
1094 if (r < 0)
1095 goto fail;
1096
1097 return 1;
1098
1099 fail:
1100 dns_query_free(q);
1101 return r;
1102 }
1103
1104 static int append_dns_server(sd_bus_message *reply, DnsServer *s) {
1105 int r;
1106
1107 assert(reply);
1108 assert(s);
1109
1110 r = sd_bus_message_open_container(reply, 'r', "iiay");
1111 if (r < 0)
1112 return r;
1113
1114 r = sd_bus_message_append(reply, "ii", s->link ? s->link->ifindex : 0, s->family);
1115 if (r < 0)
1116 return r;
1117
1118 r = sd_bus_message_append_array(reply, 'y', &s->address, FAMILY_ADDRESS_SIZE(s->family));
1119 if (r < 0)
1120 return r;
1121
1122 return sd_bus_message_close_container(reply);
1123 }
1124
1125 static int bus_property_get_dns_servers(
1126 sd_bus *bus,
1127 const char *path,
1128 const char *interface,
1129 const char *property,
1130 sd_bus_message *reply,
1131 void *userdata,
1132 sd_bus_error *error) {
1133
1134 Manager *m = userdata;
1135 unsigned c = 0;
1136 DnsServer *s;
1137 Iterator i;
1138 Link *l;
1139 int r;
1140
1141 assert(reply);
1142 assert(m);
1143
1144 r = sd_bus_message_open_container(reply, 'a', "(iiay)");
1145 if (r < 0)
1146 return r;
1147
1148 LIST_FOREACH(servers, s, m->dns_servers) {
1149 r = append_dns_server(reply, s);
1150 if (r < 0)
1151 return r;
1152
1153 c++;
1154 }
1155
1156 HASHMAP_FOREACH(l, m->links, i) {
1157 LIST_FOREACH(servers, s, l->dns_servers) {
1158 r = append_dns_server(reply, s);
1159 if (r < 0)
1160 return r;
1161 c++;
1162 }
1163 }
1164
1165 if (c == 0) {
1166 LIST_FOREACH(servers, s, m->fallback_dns_servers) {
1167 r = append_dns_server(reply, s);
1168 if (r < 0)
1169 return r;
1170 }
1171 }
1172
1173 return sd_bus_message_close_container(reply);
1174 }
1175
1176 static int bus_property_get_search_domains(
1177 sd_bus *bus,
1178 const char *path,
1179 const char *interface,
1180 const char *property,
1181 sd_bus_message *reply,
1182 void *userdata,
1183 sd_bus_error *error) {
1184
1185 Manager *m = userdata;
1186 DnsSearchDomain *d;
1187 Iterator i;
1188 Link *l;
1189 int r;
1190
1191 assert(reply);
1192 assert(m);
1193
1194 r = sd_bus_message_open_container(reply, 'a', "(is)");
1195 if (r < 0)
1196 return r;
1197
1198 LIST_FOREACH(domains, d, m->search_domains) {
1199 r = sd_bus_message_append(reply, "(is)", 0, d->name);
1200 if (r < 0)
1201 return r;
1202 }
1203
1204 HASHMAP_FOREACH(l, m->links, i) {
1205 LIST_FOREACH(domains, d, l->search_domains) {
1206 r = sd_bus_message_append(reply, "is", l->ifindex, d->name);
1207 if (r < 0)
1208 return r;
1209 }
1210 }
1211
1212 return sd_bus_message_close_container(reply);
1213 }
1214
1215 static const sd_bus_vtable resolve_vtable[] = {
1216 SD_BUS_VTABLE_START(0),
1217 SD_BUS_PROPERTY("LLMNRHostname", "s", NULL, offsetof(Manager, llmnr_hostname), 0),
1218 SD_BUS_PROPERTY("DNSServers", "a(iiay)", bus_property_get_dns_servers, 0, 0),
1219 SD_BUS_PROPERTY("SearchDomains", "a(is)", bus_property_get_search_domains, 0, 0),
1220
1221 SD_BUS_METHOD("ResolveHostname", "isit", "a(iiay)st", bus_method_resolve_hostname, SD_BUS_VTABLE_UNPRIVILEGED),
1222 SD_BUS_METHOD("ResolveAddress", "iiayt", "a(is)t", bus_method_resolve_address, SD_BUS_VTABLE_UNPRIVILEGED),
1223 SD_BUS_METHOD("ResolveRecord", "isqqt", "a(iqqay)t", bus_method_resolve_record, SD_BUS_VTABLE_UNPRIVILEGED),
1224 SD_BUS_METHOD("ResolveService", "isssit", "a(qqqsa(iiay)s)aayssst", bus_method_resolve_service, SD_BUS_VTABLE_UNPRIVILEGED),
1225 SD_BUS_VTABLE_END,
1226 };
1227
1228 static int on_bus_retry(sd_event_source *s, usec_t usec, void *userdata) {
1229 Manager *m = userdata;
1230
1231 assert(s);
1232 assert(m);
1233
1234 m->bus_retry_event_source = sd_event_source_unref(m->bus_retry_event_source);
1235
1236 manager_connect_bus(m);
1237 return 0;
1238 }
1239
1240 static int match_prepare_for_sleep(sd_bus_message *message, void *userdata, sd_bus_error *ret_error) {
1241 Manager *m = userdata;
1242 int b, r;
1243
1244 assert(message);
1245 assert(m);
1246
1247 r = sd_bus_message_read(message, "b", &b);
1248 if (r < 0) {
1249 log_debug_errno(r, "Failed to parse PrepareForSleep signal: %m");
1250 return 0;
1251 }
1252
1253 if (b)
1254 return 0;
1255
1256 log_debug("Coming back from suspend, verifying all RRs...");
1257
1258 manager_verify_all(m);
1259 return 0;
1260 }
1261
1262 int manager_connect_bus(Manager *m) {
1263 int r;
1264
1265 assert(m);
1266
1267 if (m->bus)
1268 return 0;
1269
1270 r = sd_bus_default_system(&m->bus);
1271 if (r < 0) {
1272 /* We failed to connect? Yuck, we must be in early
1273 * boot. Let's try in 5s again. As soon as we have
1274 * kdbus we can stop doing this... */
1275
1276 log_debug_errno(r, "Failed to connect to bus, trying again in 5s: %m");
1277
1278 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);
1279 if (r < 0)
1280 return log_error_errno(r, "Failed to install bus reconnect time event: %m");
1281
1282 return 0;
1283 }
1284
1285 r = sd_bus_add_object_vtable(m->bus, NULL, "/org/freedesktop/resolve1", "org.freedesktop.resolve1.Manager", resolve_vtable, m);
1286 if (r < 0)
1287 return log_error_errno(r, "Failed to register object: %m");
1288
1289 r = sd_bus_request_name(m->bus, "org.freedesktop.resolve1", 0);
1290 if (r < 0)
1291 return log_error_errno(r, "Failed to register name: %m");
1292
1293 r = sd_bus_attach_event(m->bus, m->event, 0);
1294 if (r < 0)
1295 return log_error_errno(r, "Failed to attach bus to event loop: %m");
1296
1297 r = sd_bus_add_match(m->bus, &m->prepare_for_sleep_slot,
1298 "type='signal',"
1299 "sender='org.freedesktop.login1',"
1300 "interface='org.freedesktop.login1.Manager',"
1301 "member='PrepareForSleep',"
1302 "path='/org/freedesktop/login1'",
1303 match_prepare_for_sleep,
1304 m);
1305 if (r < 0)
1306 log_error_errno(r, "Failed to add match for PrepareForSleep: %m");
1307
1308 return 0;
1309 }