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