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