]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/resolve/resolved-dns-query.c
Merge pull request #2525 from chaloulo/journal-remote-microhttp-max-memory-usage
[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 "dns-type.h"
25 #include "hostname-util.h"
26 #include "local-addresses.h"
27 #include "resolved-dns-query.h"
28 #include "resolved-dns-synthesize.h"
29 #include "resolved-etc-hosts.h"
30 #include "string-util.h"
31
32 /* How long to wait for the query in total */
33 #define QUERY_TIMEOUT_USEC (30 * USEC_PER_SEC)
34
35 #define CNAME_MAX 8
36 #define QUERIES_MAX 2048
37 #define AUXILIARY_QUERIES_MAX 64
38
39 static int dns_query_candidate_new(DnsQueryCandidate **ret, DnsQuery *q, DnsScope *s) {
40 DnsQueryCandidate *c;
41
42 assert(ret);
43 assert(q);
44 assert(s);
45
46 c = new0(DnsQueryCandidate, 1);
47 if (!c)
48 return -ENOMEM;
49
50 c->query = q;
51 c->scope = s;
52
53 LIST_PREPEND(candidates_by_query, q->candidates, c);
54 LIST_PREPEND(candidates_by_scope, s->query_candidates, c);
55
56 *ret = c;
57 return 0;
58 }
59
60 static void dns_query_candidate_stop(DnsQueryCandidate *c) {
61 DnsTransaction *t;
62
63 assert(c);
64
65 while ((t = set_steal_first(c->transactions))) {
66 set_remove(t->notify_query_candidates, 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 free(c);
88
89 return NULL;
90 }
91
92 static int dns_query_candidate_next_search_domain(DnsQueryCandidate *c) {
93 DnsSearchDomain *next = NULL;
94
95 assert(c);
96
97 if (c->search_domain && c->search_domain->linked)
98 next = c->search_domain->domains_next;
99 else
100 next = dns_scope_get_search_domains(c->scope);
101
102 for (;;) {
103 if (!next) /* We hit the end of the list */
104 return 0;
105
106 if (!next->route_only)
107 break;
108
109 /* Skip over route-only domains */
110 next = next->domains_next;
111 }
112
113 dns_search_domain_unref(c->search_domain);
114 c->search_domain = dns_search_domain_ref(next);
115
116 return 1;
117 }
118
119 static int dns_query_candidate_add_transaction(DnsQueryCandidate *c, DnsResourceKey *key) {
120 DnsTransaction *t;
121 int r;
122
123 assert(c);
124 assert(key);
125
126 t = dns_scope_find_transaction(c->scope, key, true);
127 if (!t) {
128 r = dns_transaction_new(&t, c->scope, key);
129 if (r < 0)
130 return r;
131 } else {
132 if (set_contains(c->transactions, t))
133 return 0;
134 }
135
136 r = set_ensure_allocated(&c->transactions, NULL);
137 if (r < 0)
138 goto gc;
139
140 r = set_ensure_allocated(&t->notify_query_candidates, NULL);
141 if (r < 0)
142 goto gc;
143
144 r = set_put(t->notify_query_candidates, c);
145 if (r < 0)
146 goto gc;
147
148 r = set_put(c->transactions, t);
149 if (r < 0) {
150 (void) set_remove(t->notify_query_candidates, c);
151 goto gc;
152 }
153
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 free(q->request_address_string);
404
405 if (q->manager) {
406 LIST_REMOVE(queries, q->manager->dns_queries, q);
407 q->manager->n_dns_queries--;
408 }
409
410 free(q);
411
412 return NULL;
413 }
414
415 int dns_query_new(
416 Manager *m,
417 DnsQuery **ret,
418 DnsQuestion *question_utf8,
419 DnsQuestion *question_idna,
420 int ifindex, uint64_t flags) {
421
422 _cleanup_(dns_query_freep) DnsQuery *q = NULL;
423 DnsResourceKey *key;
424 bool good = false;
425 int r;
426
427 assert(m);
428
429 if (dns_question_size(question_utf8) > 0) {
430 r = dns_question_is_valid_for_query(question_utf8);
431 if (r < 0)
432 return r;
433 if (r == 0)
434 return -EINVAL;
435
436 good = true;
437 }
438
439 /* If the IDNA and UTF8 questions are the same, merge their references */
440 r = dns_question_is_equal(question_idna, question_utf8);
441 if (r < 0)
442 return r;
443 if (r > 0)
444 question_idna = question_utf8;
445 else {
446 if (dns_question_size(question_idna) > 0) {
447 r = dns_question_is_valid_for_query(question_idna);
448 if (r < 0)
449 return r;
450 if (r == 0)
451 return -EINVAL;
452
453 good = true;
454 }
455 }
456
457 if (!good) /* don't allow empty queries */
458 return -EINVAL;
459
460 if (m->n_dns_queries >= QUERIES_MAX)
461 return -EBUSY;
462
463 q = new0(DnsQuery, 1);
464 if (!q)
465 return -ENOMEM;
466
467 q->question_utf8 = dns_question_ref(question_utf8);
468 q->question_idna = dns_question_ref(question_idna);
469 q->ifindex = ifindex;
470 q->flags = flags;
471 q->answer_dnssec_result = _DNSSEC_RESULT_INVALID;
472 q->answer_protocol = _DNS_PROTOCOL_INVALID;
473 q->answer_family = AF_UNSPEC;
474
475 /* First dump UTF8 question */
476 DNS_QUESTION_FOREACH(key, question_utf8) {
477 _cleanup_free_ char *p = NULL;
478
479 r = dns_resource_key_to_string(key, &p);
480 if (r < 0)
481 return r;
482
483 log_debug("Looking up RR for %s.", strstrip(p));
484 }
485
486 /* And then dump the IDNA question, but only what hasn't been dumped already through the UTF8 question. */
487 DNS_QUESTION_FOREACH(key, question_idna) {
488 _cleanup_free_ char *p = NULL;
489
490 r = dns_question_contains(question_utf8, key);
491 if (r < 0)
492 return r;
493 if (r > 0)
494 continue;
495
496 r = dns_resource_key_to_string(key, &p);
497 if (r < 0)
498 return r;
499
500 log_debug("Looking up IDNA RR for %s.", strstrip(p));
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 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
625 if (r <= 0)
626 return r;
627
628 dns_query_reset_answer(q);
629
630 q->answer = answer;
631 answer = NULL;
632 q->answer_rcode = DNS_RCODE_SUCCESS;
633 q->answer_protocol = dns_synthesize_protocol(q->flags);
634 q->answer_family = dns_synthesize_family(q->flags);
635 q->answer_authenticated = true;
636
637 *state = DNS_TRANSACTION_SUCCESS;
638
639 return 1;
640 }
641
642 static int dns_query_try_etc_hosts(DnsQuery *q) {
643 _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
644 int r;
645
646 assert(q);
647
648 /* Looks in /etc/hosts for matching entries. Note that this is done *before* the normal lookup is done. The
649 * data from /etc/hosts hence takes precedence over the network. */
650
651 r = manager_etc_hosts_lookup(
652 q->manager,
653 q->question_utf8,
654 &answer);
655 if (r <= 0)
656 return r;
657
658 dns_query_reset_answer(q);
659
660 q->answer = answer;
661 answer = NULL;
662 q->answer_rcode = DNS_RCODE_SUCCESS;
663 q->answer_protocol = dns_synthesize_protocol(q->flags);
664 q->answer_family = dns_synthesize_family(q->flags);
665 q->answer_authenticated = true;
666
667 return 1;
668 }
669
670 int dns_query_go(DnsQuery *q) {
671 DnsScopeMatch found = DNS_SCOPE_NO;
672 DnsScope *s, *first = NULL;
673 DnsQueryCandidate *c;
674 int r;
675
676 assert(q);
677
678 if (q->state != DNS_TRANSACTION_NULL)
679 return 0;
680
681 r = dns_query_try_etc_hosts(q);
682 if (r < 0)
683 return r;
684 if (r > 0) {
685 dns_query_complete(q, DNS_TRANSACTION_SUCCESS);
686 return 1;
687 }
688
689 LIST_FOREACH(scopes, s, q->manager->dns_scopes) {
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 return match;
700
701 if (match == DNS_SCOPE_NO)
702 continue;
703
704 found = match;
705
706 if (match == DNS_SCOPE_YES) {
707 first = s;
708 break;
709 } else {
710 assert(match == DNS_SCOPE_MAYBE);
711
712 if (!first)
713 first = s;
714 }
715 }
716
717 if (found == DNS_SCOPE_NO) {
718 DnsTransactionState state = DNS_TRANSACTION_NO_SERVERS;
719
720 r = dns_query_synthesize_reply(q, &state);
721 if (r < 0)
722 return r;
723
724 dns_query_complete(q, state);
725 return 1;
726 }
727
728 r = dns_query_add_candidate(q, first);
729 if (r < 0)
730 goto fail;
731
732 LIST_FOREACH(scopes, s, first->scopes_next) {
733 DnsScopeMatch match;
734 const char *name;
735
736 name = dns_question_first_name(dns_query_question_for_protocol(q, s->protocol));
737 if (!name)
738 continue;
739
740 match = dns_scope_good_domain(s, q->ifindex, q->flags, name);
741 if (match < 0)
742 goto fail;
743
744 if (match != found)
745 continue;
746
747 r = dns_query_add_candidate(q, s);
748 if (r < 0)
749 goto fail;
750 }
751
752 dns_query_reset_answer(q);
753
754 r = sd_event_add_time(
755 q->manager->event,
756 &q->timeout_event_source,
757 clock_boottime_or_monotonic(),
758 now(clock_boottime_or_monotonic()) + QUERY_TIMEOUT_USEC, 0,
759 on_query_timeout, q);
760 if (r < 0)
761 goto fail;
762
763 (void) sd_event_source_set_description(q->timeout_event_source, "query-timeout");
764
765 q->state = DNS_TRANSACTION_PENDING;
766 q->block_ready++;
767
768 /* Start the transactions */
769 LIST_FOREACH(candidates_by_query, c, q->candidates) {
770 r = dns_query_candidate_go(c);
771 if (r < 0) {
772 q->block_ready--;
773 goto fail;
774 }
775 }
776
777 q->block_ready--;
778 dns_query_ready(q);
779
780 return 1;
781
782 fail:
783 dns_query_stop(q);
784 return r;
785 }
786
787 static void dns_query_accept(DnsQuery *q, DnsQueryCandidate *c) {
788 DnsTransactionState state = DNS_TRANSACTION_NO_SERVERS;
789 bool has_authenticated = false, has_non_authenticated = false;
790 DnssecResult dnssec_result_authenticated = _DNSSEC_RESULT_INVALID, dnssec_result_non_authenticated = _DNSSEC_RESULT_INVALID;
791 DnsTransaction *t;
792 Iterator i;
793 int r;
794
795 assert(q);
796
797 if (!c) {
798 r = dns_query_synthesize_reply(q, &state);
799 if (r < 0)
800 goto fail;
801
802 dns_query_complete(q, state);
803 return;
804 }
805
806 if (c->error_code != 0) {
807 /* If the candidate had an error condition of its own, start with that. */
808 state = DNS_TRANSACTION_ERRNO;
809 q->answer = dns_answer_unref(q->answer);
810 q->answer_rcode = 0;
811 q->answer_dnssec_result = _DNSSEC_RESULT_INVALID;
812 q->answer_errno = c->error_code;
813 }
814
815 SET_FOREACH(t, c->transactions, i) {
816
817 switch (t->state) {
818
819 case DNS_TRANSACTION_SUCCESS: {
820 /* We found a successfuly reply, merge it into the answer */
821 r = dns_answer_extend(&q->answer, t->answer);
822 if (r < 0)
823 goto fail;
824
825 q->answer_rcode = t->answer_rcode;
826 q->answer_errno = 0;
827
828 if (t->answer_authenticated) {
829 has_authenticated = true;
830 dnssec_result_authenticated = t->answer_dnssec_result;
831 } else {
832 has_non_authenticated = true;
833 dnssec_result_non_authenticated = t->answer_dnssec_result;
834 }
835
836 state = DNS_TRANSACTION_SUCCESS;
837 break;
838 }
839
840 case DNS_TRANSACTION_NULL:
841 case DNS_TRANSACTION_PENDING:
842 case DNS_TRANSACTION_VALIDATING:
843 case DNS_TRANSACTION_ABORTED:
844 /* Ignore transactions that didn't complete */
845 continue;
846
847 default:
848 /* Any kind of failure? Store the data away,
849 * if there's nothing stored yet. */
850
851 if (state == DNS_TRANSACTION_SUCCESS)
852 continue;
853
854 q->answer = dns_answer_unref(q->answer);
855 q->answer_rcode = t->answer_rcode;
856 q->answer_dnssec_result = t->answer_dnssec_result;
857 q->answer_errno = t->answer_errno;
858
859 state = t->state;
860 break;
861 }
862 }
863
864 if (state == DNS_TRANSACTION_SUCCESS) {
865 q->answer_authenticated = has_authenticated && !has_non_authenticated;
866 q->answer_dnssec_result = q->answer_authenticated ? dnssec_result_authenticated : dnssec_result_non_authenticated;
867 }
868
869 q->answer_protocol = c->scope->protocol;
870 q->answer_family = c->scope->family;
871
872 dns_search_domain_unref(q->answer_search_domain);
873 q->answer_search_domain = dns_search_domain_ref(c->search_domain);
874
875 r = dns_query_synthesize_reply(q, &state);
876 if (r < 0)
877 goto fail;
878
879 dns_query_complete(q, state);
880 return;
881
882 fail:
883 q->answer_errno = -r;
884 dns_query_complete(q, DNS_TRANSACTION_ERRNO);
885 }
886
887 void dns_query_ready(DnsQuery *q) {
888
889 DnsQueryCandidate *bad = NULL, *c;
890 bool pending = false;
891
892 assert(q);
893 assert(DNS_TRANSACTION_IS_LIVE(q->state));
894
895 /* Note that this call might invalidate the query. Callers
896 * should hence not attempt to access the query or transaction
897 * after calling this function, unless the block_ready
898 * counter was explicitly bumped before doing so. */
899
900 if (q->block_ready > 0)
901 return;
902
903 LIST_FOREACH(candidates_by_query, c, q->candidates) {
904 DnsTransactionState state;
905
906 state = dns_query_candidate_state(c);
907 switch (state) {
908
909 case DNS_TRANSACTION_SUCCESS:
910 /* One of the candidates is successful,
911 * let's use it, and copy its data out */
912 dns_query_accept(q, c);
913 return;
914
915 case DNS_TRANSACTION_NULL:
916 case DNS_TRANSACTION_PENDING:
917 case DNS_TRANSACTION_VALIDATING:
918 /* One of the candidates is still going on,
919 * let's maybe wait for it */
920 pending = true;
921 break;
922
923 default:
924 /* Any kind of failure */
925 bad = c;
926 break;
927 }
928 }
929
930 if (pending)
931 return;
932
933 dns_query_accept(q, bad);
934 }
935
936 static int dns_query_cname_redirect(DnsQuery *q, const DnsResourceRecord *cname) {
937 _cleanup_(dns_question_unrefp) DnsQuestion *nq_idna = NULL, *nq_utf8 = NULL;
938 int r, k;
939
940 assert(q);
941
942 q->n_cname_redirects ++;
943 if (q->n_cname_redirects > CNAME_MAX)
944 return -ELOOP;
945
946 r = dns_question_cname_redirect(q->question_idna, cname, &nq_idna);
947 if (r < 0)
948 return r;
949 else if (r > 0)
950 log_debug("Following CNAME/DNAME %s → %s.", dns_question_first_name(q->question_idna), dns_question_first_name(nq_idna));
951
952 k = dns_question_is_equal(q->question_idna, q->question_utf8);
953 if (k < 0)
954 return r;
955 if (k > 0) {
956 /* Same question? Shortcut new question generation */
957 nq_utf8 = dns_question_ref(nq_idna);
958 k = r;
959 } else {
960 k = dns_question_cname_redirect(q->question_utf8, cname, &nq_utf8);
961 if (k < 0)
962 return k;
963 else if (k > 0)
964 log_debug("Following UTF8 CNAME/DNAME %s → %s.", dns_question_first_name(q->question_utf8), dns_question_first_name(nq_utf8));
965 }
966
967 if (r == 0 && k == 0) /* No actual cname happened? */
968 return -ELOOP;
969
970 if (q->answer_protocol == DNS_PROTOCOL_DNS) {
971 /* Don't permit CNAME redirects from unicast DNS to LLMNR or MulticastDNS, so that global resources
972 * cannot invade the local namespace. The opposite way we permit: local names may redirect to global
973 * ones. */
974
975 q->flags &= ~(SD_RESOLVED_LLMNR|SD_RESOLVED_MDNS); /* mask away the local protocols */
976 }
977
978 /* Turn off searching for the new name */
979 q->flags |= SD_RESOLVED_NO_SEARCH;
980
981 dns_question_unref(q->question_idna);
982 q->question_idna = nq_idna;
983 nq_idna = NULL;
984
985 dns_question_unref(q->question_utf8);
986 q->question_utf8 = nq_utf8;
987 nq_utf8 = NULL;
988
989 dns_query_free_candidates(q);
990 dns_query_reset_answer(q);
991
992 q->state = DNS_TRANSACTION_NULL;
993
994 return 0;
995 }
996
997 int dns_query_process_cname(DnsQuery *q) {
998 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *cname = NULL;
999 DnsQuestion *question;
1000 DnsResourceRecord *rr;
1001 int r;
1002
1003 assert(q);
1004
1005 if (!IN_SET(q->state, DNS_TRANSACTION_SUCCESS, DNS_TRANSACTION_NULL))
1006 return DNS_QUERY_NOMATCH;
1007
1008 question = dns_query_question_for_protocol(q, q->answer_protocol);
1009
1010 DNS_ANSWER_FOREACH(rr, q->answer) {
1011 r = dns_question_matches_rr(question, rr, DNS_SEARCH_DOMAIN_NAME(q->answer_search_domain));
1012 if (r < 0)
1013 return r;
1014 if (r > 0)
1015 return DNS_QUERY_MATCH; /* The answer matches directly, no need to follow cnames */
1016
1017 r = dns_question_matches_cname_or_dname(question, rr, DNS_SEARCH_DOMAIN_NAME(q->answer_search_domain));
1018 if (r < 0)
1019 return r;
1020 if (r > 0 && !cname)
1021 cname = dns_resource_record_ref(rr);
1022 }
1023
1024 if (!cname)
1025 return DNS_QUERY_NOMATCH; /* No match and no cname to follow */
1026
1027 if (q->flags & SD_RESOLVED_NO_CNAME)
1028 return -ELOOP;
1029
1030 /* OK, let's actually follow the CNAME */
1031 r = dns_query_cname_redirect(q, cname);
1032 if (r < 0)
1033 return r;
1034
1035 /* Let's see if the answer can already answer the new
1036 * redirected question */
1037 r = dns_query_process_cname(q);
1038 if (r != DNS_QUERY_NOMATCH)
1039 return r;
1040
1041 /* OK, it cannot, let's begin with the new query */
1042 r = dns_query_go(q);
1043 if (r < 0)
1044 return r;
1045
1046 return DNS_QUERY_RESTARTED; /* We restarted the query for a new cname */
1047 }
1048
1049 static int on_bus_track(sd_bus_track *t, void *userdata) {
1050 DnsQuery *q = userdata;
1051
1052 assert(t);
1053 assert(q);
1054
1055 log_debug("Client of active query vanished, aborting query.");
1056 dns_query_complete(q, DNS_TRANSACTION_ABORTED);
1057 return 0;
1058 }
1059
1060 int dns_query_bus_track(DnsQuery *q, sd_bus_message *m) {
1061 int r;
1062
1063 assert(q);
1064 assert(m);
1065
1066 if (!q->bus_track) {
1067 r = sd_bus_track_new(sd_bus_message_get_bus(m), &q->bus_track, on_bus_track, q);
1068 if (r < 0)
1069 return r;
1070 }
1071
1072 r = sd_bus_track_add_sender(q->bus_track, m);
1073 if (r < 0)
1074 return r;
1075
1076 return 0;
1077 }
1078
1079 DnsQuestion* dns_query_question_for_protocol(DnsQuery *q, DnsProtocol protocol) {
1080 assert(q);
1081
1082 switch (protocol) {
1083
1084 case DNS_PROTOCOL_DNS:
1085 return q->question_idna;
1086
1087 case DNS_PROTOCOL_MDNS:
1088 case DNS_PROTOCOL_LLMNR:
1089 return q->question_utf8;
1090
1091 default:
1092 return NULL;
1093 }
1094 }
1095
1096 const char *dns_query_string(DnsQuery *q) {
1097 const char *name;
1098 int r;
1099
1100 /* Returns a somewhat useful human-readable lookup key string for this query */
1101
1102 if (q->request_address_string)
1103 return q->request_address_string;
1104
1105 if (q->request_address_valid) {
1106 r = in_addr_to_string(q->request_family, &q->request_address, &q->request_address_string);
1107 if (r >= 0)
1108 return q->request_address_string;
1109 }
1110
1111 name = dns_question_first_name(q->question_utf8);
1112 if (name)
1113 return name;
1114
1115 return dns_question_first_name(q->question_idna);
1116 }