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