]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/resolve/resolved-dns-query.c
Merge pull request #7376 from keszybz/simplify-root-options
[thirdparty/systemd.git] / src / resolve / resolved-dns-query.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright 2014 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #include "alloc-util.h"
22 #include "dns-domain.h"
23 #include "dns-type.h"
24 #include "hostname-util.h"
25 #include "local-addresses.h"
26 #include "resolved-dns-query.h"
27 #include "resolved-dns-synthesize.h"
28 #include "resolved-etc-hosts.h"
29 #include "string-util.h"
30
31 /* How long to wait for the query in total */
32 #define QUERY_TIMEOUT_USEC (60 * USEC_PER_SEC)
33
34 #define CNAME_MAX 8
35 #define QUERIES_MAX 2048
36 #define AUXILIARY_QUERIES_MAX 64
37
38 static int dns_query_candidate_new(DnsQueryCandidate **ret, DnsQuery *q, DnsScope *s) {
39 DnsQueryCandidate *c;
40
41 assert(ret);
42 assert(q);
43 assert(s);
44
45 c = new0(DnsQueryCandidate, 1);
46 if (!c)
47 return -ENOMEM;
48
49 c->query = q;
50 c->scope = s;
51
52 LIST_PREPEND(candidates_by_query, q->candidates, c);
53 LIST_PREPEND(candidates_by_scope, s->query_candidates, c);
54
55 *ret = c;
56 return 0;
57 }
58
59 static void dns_query_candidate_stop(DnsQueryCandidate *c) {
60 DnsTransaction *t;
61
62 assert(c);
63
64 while ((t = set_steal_first(c->transactions))) {
65 set_remove(t->notify_query_candidates, c);
66 set_remove(t->notify_query_candidates_done, c);
67 dns_transaction_gc(t);
68 }
69 }
70
71 DnsQueryCandidate* dns_query_candidate_free(DnsQueryCandidate *c) {
72
73 if (!c)
74 return NULL;
75
76 dns_query_candidate_stop(c);
77
78 set_free(c->transactions);
79 dns_search_domain_unref(c->search_domain);
80
81 if (c->query)
82 LIST_REMOVE(candidates_by_query, c->query->candidates, c);
83
84 if (c->scope)
85 LIST_REMOVE(candidates_by_scope, c->scope->query_candidates, c);
86
87 return mfree(c);
88 }
89
90 static int dns_query_candidate_next_search_domain(DnsQueryCandidate *c) {
91 DnsSearchDomain *next = NULL;
92
93 assert(c);
94
95 if (c->search_domain && c->search_domain->linked)
96 next = c->search_domain->domains_next;
97 else
98 next = dns_scope_get_search_domains(c->scope);
99
100 for (;;) {
101 if (!next) /* We hit the end of the list */
102 return 0;
103
104 if (!next->route_only)
105 break;
106
107 /* Skip over route-only domains */
108 next = next->domains_next;
109 }
110
111 dns_search_domain_unref(c->search_domain);
112 c->search_domain = dns_search_domain_ref(next);
113
114 return 1;
115 }
116
117 static int dns_query_candidate_add_transaction(DnsQueryCandidate *c, DnsResourceKey *key) {
118 DnsTransaction *t;
119 int r;
120
121 assert(c);
122 assert(key);
123
124 t = dns_scope_find_transaction(c->scope, key, true);
125 if (!t) {
126 r = dns_transaction_new(&t, c->scope, key);
127 if (r < 0)
128 return r;
129 } else {
130 if (set_contains(c->transactions, t))
131 return 0;
132 }
133
134 r = set_ensure_allocated(&c->transactions, NULL);
135 if (r < 0)
136 goto gc;
137
138 r = set_ensure_allocated(&t->notify_query_candidates, NULL);
139 if (r < 0)
140 goto gc;
141
142 r = set_ensure_allocated(&t->notify_query_candidates_done, NULL);
143 if (r < 0)
144 goto gc;
145
146 r = set_put(t->notify_query_candidates, c);
147 if (r < 0)
148 goto gc;
149
150 r = set_put(c->transactions, t);
151 if (r < 0) {
152 (void) set_remove(t->notify_query_candidates, c);
153 goto gc;
154 }
155
156 t->clamp_ttl = c->query->clamp_ttl;
157 return 1;
158
159 gc:
160 dns_transaction_gc(t);
161 return r;
162 }
163
164 static int dns_query_candidate_go(DnsQueryCandidate *c) {
165 DnsTransaction *t;
166 Iterator i;
167 int r;
168 unsigned n = 0;
169
170 assert(c);
171
172 /* Start the transactions that are not started yet */
173 SET_FOREACH(t, c->transactions, i) {
174 if (t->state != DNS_TRANSACTION_NULL)
175 continue;
176
177 r = dns_transaction_go(t);
178 if (r < 0)
179 return r;
180
181 n++;
182 }
183
184 /* If there was nothing to start, then let's proceed immediately */
185 if (n == 0)
186 dns_query_candidate_notify(c);
187
188 return 0;
189 }
190
191 static DnsTransactionState dns_query_candidate_state(DnsQueryCandidate *c) {
192 DnsTransactionState state = DNS_TRANSACTION_NO_SERVERS;
193 DnsTransaction *t;
194 Iterator i;
195
196 assert(c);
197
198 if (c->error_code != 0)
199 return DNS_TRANSACTION_ERRNO;
200
201 SET_FOREACH(t, c->transactions, i) {
202
203 switch (t->state) {
204
205 case DNS_TRANSACTION_NULL:
206 /* If there's a NULL transaction pending, then
207 * this means not all transactions where
208 * started yet, and we were called from within
209 * the stackframe that is supposed to start
210 * remaining transactions. In this case,
211 * simply claim the candidate is pending. */
212
213 case DNS_TRANSACTION_PENDING:
214 case DNS_TRANSACTION_VALIDATING:
215 /* If there's one transaction currently in
216 * VALIDATING state, then this means there's
217 * also one in PENDING state, hence we can
218 * return PENDING immediately. */
219 return DNS_TRANSACTION_PENDING;
220
221 case DNS_TRANSACTION_SUCCESS:
222 state = t->state;
223 break;
224
225 default:
226 if (state != DNS_TRANSACTION_SUCCESS)
227 state = t->state;
228
229 break;
230 }
231 }
232
233 return state;
234 }
235
236 static bool dns_query_candidate_is_routable(DnsQueryCandidate *c, uint16_t type) {
237 int family;
238
239 assert(c);
240
241 /* Checks whether the specified RR type matches an address family that is routable on the link(s) the scope of
242 * this candidate belongs to. Specifically, whether there's a routable IPv4 address on it if we query an A RR,
243 * or a routable IPv6 address if we query an AAAA RR. */
244
245 if (!c->query->suppress_unroutable_family)
246 return true;
247
248 if (c->scope->protocol != DNS_PROTOCOL_DNS)
249 return true;
250
251 family = dns_type_to_af(type);
252 if (family < 0)
253 return true;
254
255 if (c->scope->link)
256 return link_relevant(c->scope->link, family, false);
257 else
258 return manager_routable(c->scope->manager, family);
259 }
260
261 static int dns_query_candidate_setup_transactions(DnsQueryCandidate *c) {
262 DnsQuestion *question;
263 DnsResourceKey *key;
264 int n = 0, r;
265
266 assert(c);
267
268 dns_query_candidate_stop(c);
269
270 question = dns_query_question_for_protocol(c->query, c->scope->protocol);
271
272 /* Create one transaction per question key */
273 DNS_QUESTION_FOREACH(key, question) {
274 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *new_key = NULL;
275 DnsResourceKey *qkey;
276
277 if (!dns_query_candidate_is_routable(c, key->type))
278 continue;
279
280 if (c->search_domain) {
281 r = dns_resource_key_new_append_suffix(&new_key, key, c->search_domain->name);
282 if (r < 0)
283 goto fail;
284
285 qkey = new_key;
286 } else
287 qkey = key;
288
289 if (!dns_scope_good_key(c->scope, qkey))
290 continue;
291
292 r = dns_query_candidate_add_transaction(c, qkey);
293 if (r < 0)
294 goto fail;
295
296 n++;
297 }
298
299 return n;
300
301 fail:
302 dns_query_candidate_stop(c);
303 return r;
304 }
305
306 void dns_query_candidate_notify(DnsQueryCandidate *c) {
307 DnsTransactionState state;
308 int r;
309
310 assert(c);
311
312 state = dns_query_candidate_state(c);
313
314 if (DNS_TRANSACTION_IS_LIVE(state))
315 return;
316
317 if (state != DNS_TRANSACTION_SUCCESS && c->search_domain) {
318
319 r = dns_query_candidate_next_search_domain(c);
320 if (r < 0)
321 goto fail;
322
323 if (r > 0) {
324 /* OK, there's another search domain to try, let's do so. */
325
326 r = dns_query_candidate_setup_transactions(c);
327 if (r < 0)
328 goto fail;
329
330 if (r > 0) {
331 /* New transactions where queued. Start them and wait */
332
333 r = dns_query_candidate_go(c);
334 if (r < 0)
335 goto fail;
336
337 return;
338 }
339 }
340
341 }
342
343 dns_query_ready(c->query);
344 return;
345
346 fail:
347 log_warning_errno(r, "Failed to follow search domains: %m");
348 c->error_code = r;
349 dns_query_ready(c->query);
350 }
351
352 static void dns_query_stop(DnsQuery *q) {
353 DnsQueryCandidate *c;
354
355 assert(q);
356
357 q->timeout_event_source = sd_event_source_unref(q->timeout_event_source);
358
359 LIST_FOREACH(candidates_by_query, c, q->candidates)
360 dns_query_candidate_stop(c);
361 }
362
363 static void dns_query_free_candidates(DnsQuery *q) {
364 assert(q);
365
366 while (q->candidates)
367 dns_query_candidate_free(q->candidates);
368 }
369
370 static void dns_query_reset_answer(DnsQuery *q) {
371 assert(q);
372
373 q->answer = dns_answer_unref(q->answer);
374 q->answer_rcode = 0;
375 q->answer_dnssec_result = _DNSSEC_RESULT_INVALID;
376 q->answer_errno = 0;
377 q->answer_authenticated = false;
378 q->answer_protocol = _DNS_PROTOCOL_INVALID;
379 q->answer_family = AF_UNSPEC;
380 q->answer_search_domain = dns_search_domain_unref(q->answer_search_domain);
381 }
382
383 DnsQuery *dns_query_free(DnsQuery *q) {
384 if (!q)
385 return NULL;
386
387 while (q->auxiliary_queries)
388 dns_query_free(q->auxiliary_queries);
389
390 if (q->auxiliary_for) {
391 assert(q->auxiliary_for->n_auxiliary_queries > 0);
392 q->auxiliary_for->n_auxiliary_queries--;
393 LIST_REMOVE(auxiliary_queries, q->auxiliary_for->auxiliary_queries, q);
394 }
395
396 dns_query_free_candidates(q);
397
398 dns_question_unref(q->question_idna);
399 dns_question_unref(q->question_utf8);
400
401 dns_query_reset_answer(q);
402
403 sd_bus_message_unref(q->request);
404 sd_bus_track_unref(q->bus_track);
405
406 dns_packet_unref(q->request_dns_packet);
407 dns_packet_unref(q->reply_dns_packet);
408
409 if (q->request_dns_stream) {
410 /* Detach the stream from our query, in case something else keeps a reference to it. */
411 q->request_dns_stream->complete = NULL;
412 q->request_dns_stream->on_packet = NULL;
413 q->request_dns_stream->query = NULL;
414 dns_stream_unref(q->request_dns_stream);
415 }
416
417 free(q->request_address_string);
418
419 if (q->manager) {
420 LIST_REMOVE(queries, q->manager->dns_queries, q);
421 q->manager->n_dns_queries--;
422 }
423
424 return mfree(q);
425 }
426
427 int dns_query_new(
428 Manager *m,
429 DnsQuery **ret,
430 DnsQuestion *question_utf8,
431 DnsQuestion *question_idna,
432 int ifindex,
433 uint64_t flags) {
434
435 _cleanup_(dns_query_freep) DnsQuery *q = NULL;
436 DnsResourceKey *key;
437 bool good = false;
438 int r;
439 char key_str[DNS_RESOURCE_KEY_STRING_MAX];
440
441 assert(m);
442
443 if (dns_question_size(question_utf8) > 0) {
444 r = dns_question_is_valid_for_query(question_utf8);
445 if (r < 0)
446 return r;
447 if (r == 0)
448 return -EINVAL;
449
450 good = true;
451 }
452
453 /* If the IDNA and UTF8 questions are the same, merge their references */
454 r = dns_question_is_equal(question_idna, question_utf8);
455 if (r < 0)
456 return r;
457 if (r > 0)
458 question_idna = question_utf8;
459 else {
460 if (dns_question_size(question_idna) > 0) {
461 r = dns_question_is_valid_for_query(question_idna);
462 if (r < 0)
463 return r;
464 if (r == 0)
465 return -EINVAL;
466
467 good = true;
468 }
469 }
470
471 if (!good) /* don't allow empty queries */
472 return -EINVAL;
473
474 if (m->n_dns_queries >= QUERIES_MAX)
475 return -EBUSY;
476
477 q = new0(DnsQuery, 1);
478 if (!q)
479 return -ENOMEM;
480
481 q->question_utf8 = dns_question_ref(question_utf8);
482 q->question_idna = dns_question_ref(question_idna);
483 q->ifindex = ifindex;
484 q->flags = flags;
485 q->answer_dnssec_result = _DNSSEC_RESULT_INVALID;
486 q->answer_protocol = _DNS_PROTOCOL_INVALID;
487 q->answer_family = AF_UNSPEC;
488
489 /* First dump UTF8 question */
490 DNS_QUESTION_FOREACH(key, question_utf8)
491 log_debug("Looking up RR for %s.",
492 dns_resource_key_to_string(key, key_str, sizeof key_str));
493
494 /* And then dump the IDNA question, but only what hasn't been dumped already through the UTF8 question. */
495 DNS_QUESTION_FOREACH(key, question_idna) {
496 r = dns_question_contains(question_utf8, key);
497 if (r < 0)
498 return r;
499 if (r > 0)
500 continue;
501
502 log_debug("Looking up IDNA RR for %s.",
503 dns_resource_key_to_string(key, key_str, sizeof key_str));
504 }
505
506 LIST_PREPEND(queries, m->dns_queries, q);
507 m->n_dns_queries++;
508 q->manager = m;
509
510 if (ret)
511 *ret = q;
512 q = NULL;
513
514 return 0;
515 }
516
517 int dns_query_make_auxiliary(DnsQuery *q, DnsQuery *auxiliary_for) {
518 assert(q);
519 assert(auxiliary_for);
520
521 /* Ensure that the query is not auxiliary yet, and
522 * nothing else is auxiliary to it either */
523 assert(!q->auxiliary_for);
524 assert(!q->auxiliary_queries);
525
526 /* Ensure that the unit we shall be made auxiliary for isn't
527 * auxiliary itself */
528 assert(!auxiliary_for->auxiliary_for);
529
530 if (auxiliary_for->n_auxiliary_queries >= AUXILIARY_QUERIES_MAX)
531 return -EAGAIN;
532
533 LIST_PREPEND(auxiliary_queries, auxiliary_for->auxiliary_queries, q);
534 q->auxiliary_for = auxiliary_for;
535
536 auxiliary_for->n_auxiliary_queries++;
537 return 0;
538 }
539
540 static void dns_query_complete(DnsQuery *q, DnsTransactionState state) {
541 assert(q);
542 assert(!DNS_TRANSACTION_IS_LIVE(state));
543 assert(DNS_TRANSACTION_IS_LIVE(q->state));
544
545 /* Note that this call might invalidate the query. Callers
546 * should hence not attempt to access the query or transaction
547 * after calling this function. */
548
549 q->state = state;
550
551 dns_query_stop(q);
552 if (q->complete)
553 q->complete(q);
554 }
555
556 static int on_query_timeout(sd_event_source *s, usec_t usec, void *userdata) {
557 DnsQuery *q = userdata;
558
559 assert(s);
560 assert(q);
561
562 dns_query_complete(q, DNS_TRANSACTION_TIMEOUT);
563 return 0;
564 }
565
566 static int dns_query_add_candidate(DnsQuery *q, DnsScope *s) {
567 DnsQueryCandidate *c;
568 int r;
569
570 assert(q);
571 assert(s);
572
573 r = dns_query_candidate_new(&c, q, s);
574 if (r < 0)
575 return r;
576
577 /* If this a single-label domain on DNS, we might append a suitable search domain first. */
578 if ((q->flags & SD_RESOLVED_NO_SEARCH) == 0) {
579 r = dns_scope_name_needs_search_domain(s, dns_question_first_name(q->question_idna));
580 if (r < 0)
581 goto fail;
582 if (r > 0) {
583 /* OK, we need a search domain now. Let's find one for this scope */
584
585 r = dns_query_candidate_next_search_domain(c);
586 if (r <= 0) /* if there's no search domain, then we won't add any transaction. */
587 goto fail;
588 }
589 }
590
591 r = dns_query_candidate_setup_transactions(c);
592 if (r < 0)
593 goto fail;
594
595 return 0;
596
597 fail:
598 dns_query_candidate_free(c);
599 return r;
600 }
601
602 static int dns_query_synthesize_reply(DnsQuery *q, DnsTransactionState *state) {
603 _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
604 int r;
605
606 assert(q);
607 assert(state);
608
609 /* Tries to synthesize localhost RR replies (and others) where appropriate. Note that this is done *after* the
610 * the normal lookup finished. The data from the network hence takes precedence over the data we
611 * synthesize. (But note that many scopes refuse to resolve certain domain names) */
612
613 if (!IN_SET(*state,
614 DNS_TRANSACTION_RCODE_FAILURE,
615 DNS_TRANSACTION_NO_SERVERS,
616 DNS_TRANSACTION_TIMEOUT,
617 DNS_TRANSACTION_ATTEMPTS_MAX_REACHED,
618 DNS_TRANSACTION_NETWORK_DOWN,
619 DNS_TRANSACTION_NOT_FOUND))
620 return 0;
621
622 r = dns_synthesize_answer(
623 q->manager,
624 q->question_utf8,
625 q->ifindex,
626 &answer);
627 if (r == -ENXIO) {
628 /* If we get ENXIO this tells us to generate NXDOMAIN unconditionally. */
629
630 dns_query_reset_answer(q);
631 q->answer_rcode = DNS_RCODE_NXDOMAIN;
632 q->answer_protocol = dns_synthesize_protocol(q->flags);
633 q->answer_family = dns_synthesize_family(q->flags);
634 q->answer_authenticated = true;
635 *state = DNS_TRANSACTION_RCODE_FAILURE;
636
637 return 0;
638 }
639 if (r <= 0)
640 return r;
641
642 dns_query_reset_answer(q);
643
644 q->answer = answer;
645 answer = NULL;
646 q->answer_rcode = DNS_RCODE_SUCCESS;
647 q->answer_protocol = dns_synthesize_protocol(q->flags);
648 q->answer_family = dns_synthesize_family(q->flags);
649 q->answer_authenticated = true;
650
651 *state = DNS_TRANSACTION_SUCCESS;
652
653 return 1;
654 }
655
656 static int dns_query_try_etc_hosts(DnsQuery *q) {
657 _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
658 int r;
659
660 assert(q);
661
662 /* Looks in /etc/hosts for matching entries. Note that this is done *before* the normal lookup is done. The
663 * data from /etc/hosts hence takes precedence over the network. */
664
665 r = manager_etc_hosts_lookup(
666 q->manager,
667 q->question_utf8,
668 &answer);
669 if (r <= 0)
670 return r;
671
672 dns_query_reset_answer(q);
673
674 q->answer = answer;
675 answer = NULL;
676 q->answer_rcode = DNS_RCODE_SUCCESS;
677 q->answer_protocol = dns_synthesize_protocol(q->flags);
678 q->answer_family = dns_synthesize_family(q->flags);
679 q->answer_authenticated = true;
680
681 return 1;
682 }
683
684 int dns_query_go(DnsQuery *q) {
685 DnsScopeMatch found = DNS_SCOPE_NO;
686 DnsScope *s, *first = NULL;
687 DnsQueryCandidate *c;
688 int r;
689
690 assert(q);
691
692 if (q->state != DNS_TRANSACTION_NULL)
693 return 0;
694
695 r = dns_query_try_etc_hosts(q);
696 if (r < 0)
697 return r;
698 if (r > 0) {
699 dns_query_complete(q, DNS_TRANSACTION_SUCCESS);
700 return 1;
701 }
702
703 LIST_FOREACH(scopes, s, q->manager->dns_scopes) {
704 DnsScopeMatch match;
705 const char *name;
706
707 name = dns_question_first_name(dns_query_question_for_protocol(q, s->protocol));
708 if (!name)
709 continue;
710
711 match = dns_scope_good_domain(s, q->ifindex, q->flags, name);
712 if (match < 0)
713 return match;
714
715 if (match == DNS_SCOPE_NO)
716 continue;
717
718 found = match;
719
720 if (match == DNS_SCOPE_YES) {
721 first = s;
722 break;
723 } else {
724 assert(match == DNS_SCOPE_MAYBE);
725
726 if (!first)
727 first = s;
728 }
729 }
730
731 if (found == DNS_SCOPE_NO) {
732 DnsTransactionState state = DNS_TRANSACTION_NO_SERVERS;
733
734 r = dns_query_synthesize_reply(q, &state);
735 if (r < 0)
736 return r;
737
738 dns_query_complete(q, state);
739 return 1;
740 }
741
742 r = dns_query_add_candidate(q, first);
743 if (r < 0)
744 goto fail;
745
746 LIST_FOREACH(scopes, s, first->scopes_next) {
747 DnsScopeMatch match;
748 const char *name;
749
750 name = dns_question_first_name(dns_query_question_for_protocol(q, s->protocol));
751 if (!name)
752 continue;
753
754 match = dns_scope_good_domain(s, q->ifindex, q->flags, name);
755 if (match < 0)
756 goto fail;
757
758 if (match != found)
759 continue;
760
761 r = dns_query_add_candidate(q, s);
762 if (r < 0)
763 goto fail;
764 }
765
766 dns_query_reset_answer(q);
767
768 r = sd_event_add_time(
769 q->manager->event,
770 &q->timeout_event_source,
771 clock_boottime_or_monotonic(),
772 now(clock_boottime_or_monotonic()) + QUERY_TIMEOUT_USEC, 0,
773 on_query_timeout, q);
774 if (r < 0)
775 goto fail;
776
777 (void) sd_event_source_set_description(q->timeout_event_source, "query-timeout");
778
779 q->state = DNS_TRANSACTION_PENDING;
780 q->block_ready++;
781
782 /* Start the transactions */
783 LIST_FOREACH(candidates_by_query, c, q->candidates) {
784 r = dns_query_candidate_go(c);
785 if (r < 0) {
786 q->block_ready--;
787 goto fail;
788 }
789 }
790
791 q->block_ready--;
792 dns_query_ready(q);
793
794 return 1;
795
796 fail:
797 dns_query_stop(q);
798 return r;
799 }
800
801 static void dns_query_accept(DnsQuery *q, DnsQueryCandidate *c) {
802 DnsTransactionState state = DNS_TRANSACTION_NO_SERVERS;
803 bool has_authenticated = false, has_non_authenticated = false;
804 DnssecResult dnssec_result_authenticated = _DNSSEC_RESULT_INVALID, dnssec_result_non_authenticated = _DNSSEC_RESULT_INVALID;
805 DnsTransaction *t;
806 Iterator i;
807 int r;
808
809 assert(q);
810
811 if (!c) {
812 r = dns_query_synthesize_reply(q, &state);
813 if (r < 0)
814 goto fail;
815
816 dns_query_complete(q, state);
817 return;
818 }
819
820 if (c->error_code != 0) {
821 /* If the candidate had an error condition of its own, start with that. */
822 state = DNS_TRANSACTION_ERRNO;
823 q->answer = dns_answer_unref(q->answer);
824 q->answer_rcode = 0;
825 q->answer_dnssec_result = _DNSSEC_RESULT_INVALID;
826 q->answer_authenticated = false;
827 q->answer_errno = c->error_code;
828 }
829
830 SET_FOREACH(t, c->transactions, i) {
831
832 switch (t->state) {
833
834 case DNS_TRANSACTION_SUCCESS: {
835 /* We found a successfully reply, merge it into the answer */
836 r = dns_answer_extend(&q->answer, t->answer);
837 if (r < 0)
838 goto fail;
839
840 q->answer_rcode = t->answer_rcode;
841 q->answer_errno = 0;
842
843 if (t->answer_authenticated) {
844 has_authenticated = true;
845 dnssec_result_authenticated = t->answer_dnssec_result;
846 } else {
847 has_non_authenticated = true;
848 dnssec_result_non_authenticated = t->answer_dnssec_result;
849 }
850
851 state = DNS_TRANSACTION_SUCCESS;
852 break;
853 }
854
855 case DNS_TRANSACTION_NULL:
856 case DNS_TRANSACTION_PENDING:
857 case DNS_TRANSACTION_VALIDATING:
858 case DNS_TRANSACTION_ABORTED:
859 /* Ignore transactions that didn't complete */
860 continue;
861
862 default:
863 /* Any kind of failure? Store the data away, if there's nothing stored yet. */
864 if (state == DNS_TRANSACTION_SUCCESS)
865 continue;
866
867 /* If there's already an authenticated negative reply stored, then prefer that over any unauthenticated one */
868 if (q->answer_authenticated && !t->answer_authenticated)
869 continue;
870
871 q->answer = dns_answer_unref(q->answer);
872 q->answer_rcode = t->answer_rcode;
873 q->answer_dnssec_result = t->answer_dnssec_result;
874 q->answer_authenticated = t->answer_authenticated;
875 q->answer_errno = t->answer_errno;
876
877 state = t->state;
878 break;
879 }
880 }
881
882 if (state == DNS_TRANSACTION_SUCCESS) {
883 q->answer_authenticated = has_authenticated && !has_non_authenticated;
884 q->answer_dnssec_result = q->answer_authenticated ? dnssec_result_authenticated : dnssec_result_non_authenticated;
885 }
886
887 q->answer_protocol = c->scope->protocol;
888 q->answer_family = c->scope->family;
889
890 dns_search_domain_unref(q->answer_search_domain);
891 q->answer_search_domain = dns_search_domain_ref(c->search_domain);
892
893 r = dns_query_synthesize_reply(q, &state);
894 if (r < 0)
895 goto fail;
896
897 dns_query_complete(q, state);
898 return;
899
900 fail:
901 q->answer_errno = -r;
902 dns_query_complete(q, DNS_TRANSACTION_ERRNO);
903 }
904
905 void dns_query_ready(DnsQuery *q) {
906
907 DnsQueryCandidate *bad = NULL, *c;
908 bool pending = false;
909
910 assert(q);
911 assert(DNS_TRANSACTION_IS_LIVE(q->state));
912
913 /* Note that this call might invalidate the query. Callers
914 * should hence not attempt to access the query or transaction
915 * after calling this function, unless the block_ready
916 * counter was explicitly bumped before doing so. */
917
918 if (q->block_ready > 0)
919 return;
920
921 LIST_FOREACH(candidates_by_query, c, q->candidates) {
922 DnsTransactionState state;
923
924 state = dns_query_candidate_state(c);
925 switch (state) {
926
927 case DNS_TRANSACTION_SUCCESS:
928 /* One of the candidates is successful,
929 * let's use it, and copy its data out */
930 dns_query_accept(q, c);
931 return;
932
933 case DNS_TRANSACTION_NULL:
934 case DNS_TRANSACTION_PENDING:
935 case DNS_TRANSACTION_VALIDATING:
936 /* One of the candidates is still going on,
937 * let's maybe wait for it */
938 pending = true;
939 break;
940
941 default:
942 /* Any kind of failure */
943 bad = c;
944 break;
945 }
946 }
947
948 if (pending)
949 return;
950
951 dns_query_accept(q, bad);
952 }
953
954 static int dns_query_cname_redirect(DnsQuery *q, const DnsResourceRecord *cname) {
955 _cleanup_(dns_question_unrefp) DnsQuestion *nq_idna = NULL, *nq_utf8 = NULL;
956 int r, k;
957
958 assert(q);
959
960 q->n_cname_redirects++;
961 if (q->n_cname_redirects > CNAME_MAX)
962 return -ELOOP;
963
964 r = dns_question_cname_redirect(q->question_idna, cname, &nq_idna);
965 if (r < 0)
966 return r;
967 else if (r > 0)
968 log_debug("Following CNAME/DNAME %s → %s.", dns_question_first_name(q->question_idna), dns_question_first_name(nq_idna));
969
970 k = dns_question_is_equal(q->question_idna, q->question_utf8);
971 if (k < 0)
972 return r;
973 if (k > 0) {
974 /* Same question? Shortcut new question generation */
975 nq_utf8 = dns_question_ref(nq_idna);
976 k = r;
977 } else {
978 k = dns_question_cname_redirect(q->question_utf8, cname, &nq_utf8);
979 if (k < 0)
980 return k;
981 else if (k > 0)
982 log_debug("Following UTF8 CNAME/DNAME %s → %s.", dns_question_first_name(q->question_utf8), dns_question_first_name(nq_utf8));
983 }
984
985 if (r == 0 && k == 0) /* No actual cname happened? */
986 return -ELOOP;
987
988 if (q->answer_protocol == DNS_PROTOCOL_DNS) {
989 /* Don't permit CNAME redirects from unicast DNS to LLMNR or MulticastDNS, so that global resources
990 * cannot invade the local namespace. The opposite way we permit: local names may redirect to global
991 * ones. */
992
993 q->flags &= ~(SD_RESOLVED_LLMNR|SD_RESOLVED_MDNS); /* mask away the local protocols */
994 }
995
996 /* Turn off searching for the new name */
997 q->flags |= SD_RESOLVED_NO_SEARCH;
998
999 dns_question_unref(q->question_idna);
1000 q->question_idna = nq_idna;
1001 nq_idna = NULL;
1002
1003 dns_question_unref(q->question_utf8);
1004 q->question_utf8 = nq_utf8;
1005 nq_utf8 = NULL;
1006
1007 dns_query_free_candidates(q);
1008 dns_query_reset_answer(q);
1009
1010 q->state = DNS_TRANSACTION_NULL;
1011
1012 return 0;
1013 }
1014
1015 int dns_query_process_cname(DnsQuery *q) {
1016 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *cname = NULL;
1017 DnsQuestion *question;
1018 DnsResourceRecord *rr;
1019 int r;
1020
1021 assert(q);
1022
1023 if (!IN_SET(q->state, DNS_TRANSACTION_SUCCESS, DNS_TRANSACTION_NULL))
1024 return DNS_QUERY_NOMATCH;
1025
1026 question = dns_query_question_for_protocol(q, q->answer_protocol);
1027
1028 DNS_ANSWER_FOREACH(rr, q->answer) {
1029 r = dns_question_matches_rr(question, rr, DNS_SEARCH_DOMAIN_NAME(q->answer_search_domain));
1030 if (r < 0)
1031 return r;
1032 if (r > 0)
1033 return DNS_QUERY_MATCH; /* The answer matches directly, no need to follow cnames */
1034
1035 r = dns_question_matches_cname_or_dname(question, rr, DNS_SEARCH_DOMAIN_NAME(q->answer_search_domain));
1036 if (r < 0)
1037 return r;
1038 if (r > 0 && !cname)
1039 cname = dns_resource_record_ref(rr);
1040 }
1041
1042 if (!cname)
1043 return DNS_QUERY_NOMATCH; /* No match and no cname to follow */
1044
1045 if (q->flags & SD_RESOLVED_NO_CNAME)
1046 return -ELOOP;
1047
1048 if (!q->answer_authenticated)
1049 q->previous_redirect_unauthenticated = true;
1050
1051 /* OK, let's actually follow the CNAME */
1052 r = dns_query_cname_redirect(q, cname);
1053 if (r < 0)
1054 return r;
1055
1056 /* Let's see if the answer can already answer the new
1057 * redirected question */
1058 r = dns_query_process_cname(q);
1059 if (r != DNS_QUERY_NOMATCH)
1060 return r;
1061
1062 /* OK, it cannot, let's begin with the new query */
1063 r = dns_query_go(q);
1064 if (r < 0)
1065 return r;
1066
1067 return DNS_QUERY_RESTARTED; /* We restarted the query for a new cname */
1068 }
1069
1070 static int on_bus_track(sd_bus_track *t, void *userdata) {
1071 DnsQuery *q = userdata;
1072
1073 assert(t);
1074 assert(q);
1075
1076 log_debug("Client of active query vanished, aborting query.");
1077 dns_query_complete(q, DNS_TRANSACTION_ABORTED);
1078 return 0;
1079 }
1080
1081 int dns_query_bus_track(DnsQuery *q, sd_bus_message *m) {
1082 int r;
1083
1084 assert(q);
1085 assert(m);
1086
1087 if (!q->bus_track) {
1088 r = sd_bus_track_new(sd_bus_message_get_bus(m), &q->bus_track, on_bus_track, q);
1089 if (r < 0)
1090 return r;
1091 }
1092
1093 r = sd_bus_track_add_sender(q->bus_track, m);
1094 if (r < 0)
1095 return r;
1096
1097 return 0;
1098 }
1099
1100 DnsQuestion* dns_query_question_for_protocol(DnsQuery *q, DnsProtocol protocol) {
1101 assert(q);
1102
1103 switch (protocol) {
1104
1105 case DNS_PROTOCOL_DNS:
1106 return q->question_idna;
1107
1108 case DNS_PROTOCOL_MDNS:
1109 case DNS_PROTOCOL_LLMNR:
1110 return q->question_utf8;
1111
1112 default:
1113 return NULL;
1114 }
1115 }
1116
1117 const char *dns_query_string(DnsQuery *q) {
1118 const char *name;
1119 int r;
1120
1121 /* Returns a somewhat useful human-readable lookup key string for this query */
1122
1123 if (q->request_address_string)
1124 return q->request_address_string;
1125
1126 if (q->request_address_valid) {
1127 r = in_addr_to_string(q->request_family, &q->request_address, &q->request_address_string);
1128 if (r >= 0)
1129 return q->request_address_string;
1130 }
1131
1132 name = dns_question_first_name(q->question_utf8);
1133 if (name)
1134 return name;
1135
1136 return dns_question_first_name(q->question_idna);
1137 }
1138
1139 bool dns_query_fully_authenticated(DnsQuery *q) {
1140 assert(q);
1141
1142 return q->answer_authenticated && !q->previous_redirect_unauthenticated;
1143 }