]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/resolve/resolved-dns-query.c
resolved: make counter for redirects smaller
[thirdparty/systemd.git] / src / resolve / resolved-dns-query.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include "alloc-util.h"
4 #include "dns-domain.h"
5 #include "dns-type.h"
6 #include "hostname-util.h"
7 #include "local-addresses.h"
8 #include "resolved-dns-query.h"
9 #include "resolved-dns-synthesize.h"
10 #include "resolved-etc-hosts.h"
11 #include "string-util.h"
12
13 #define QUERIES_MAX 2048
14 #define AUXILIARY_QUERIES_MAX 64
15 #define CNAME_REDIRECTS_MAX 16
16
17 assert_cc(AUXILIARY_QUERIES_MAX < UINT8_MAX);
18 assert_cc(CNAME_REDIRECTS_MAX < UINT8_MAX);
19
20 static int dns_query_candidate_new(DnsQueryCandidate **ret, DnsQuery *q, DnsScope *s) {
21 DnsQueryCandidate *c;
22
23 assert(ret);
24 assert(q);
25 assert(s);
26
27 c = new(DnsQueryCandidate, 1);
28 if (!c)
29 return -ENOMEM;
30
31 *c = (DnsQueryCandidate) {
32 .n_ref = 1,
33 .query = q,
34 .scope = s,
35 };
36
37 LIST_PREPEND(candidates_by_query, q->candidates, c);
38 LIST_PREPEND(candidates_by_scope, s->query_candidates, c);
39
40 *ret = c;
41 return 0;
42 }
43
44 static void dns_query_candidate_stop(DnsQueryCandidate *c) {
45 DnsTransaction *t;
46
47 assert(c);
48
49 while ((t = set_steal_first(c->transactions))) {
50 set_remove(t->notify_query_candidates, c);
51 set_remove(t->notify_query_candidates_done, c);
52 dns_transaction_gc(t);
53 }
54 }
55
56 static DnsQueryCandidate* dns_query_candidate_free(DnsQueryCandidate *c) {
57 if (!c)
58 return NULL;
59
60 dns_query_candidate_stop(c);
61
62 set_free(c->transactions);
63 dns_search_domain_unref(c->search_domain);
64
65 if (c->query)
66 LIST_REMOVE(candidates_by_query, c->query->candidates, c);
67
68 if (c->scope)
69 LIST_REMOVE(candidates_by_scope, c->scope->query_candidates, c);
70
71 return mfree(c);
72 }
73
74 DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(DnsQueryCandidate, dns_query_candidate, dns_query_candidate_free);
75
76 static int dns_query_candidate_next_search_domain(DnsQueryCandidate *c) {
77 DnsSearchDomain *next;
78
79 assert(c);
80
81 if (c->search_domain && c->search_domain->linked)
82 next = c->search_domain->domains_next;
83 else
84 next = dns_scope_get_search_domains(c->scope);
85
86 for (;;) {
87 if (!next) /* We hit the end of the list */
88 return 0;
89
90 if (!next->route_only)
91 break;
92
93 /* Skip over route-only domains */
94 next = next->domains_next;
95 }
96
97 dns_search_domain_unref(c->search_domain);
98 c->search_domain = dns_search_domain_ref(next);
99
100 return 1;
101 }
102
103 static int dns_query_candidate_add_transaction(
104 DnsQueryCandidate *c,
105 DnsResourceKey *key,
106 DnsPacket *bypass) {
107
108 _cleanup_(dns_transaction_gcp) DnsTransaction *t = NULL;
109 int r;
110
111 assert(c);
112
113 if (key) {
114 /* Regular lookup with a resource key */
115 assert(!bypass);
116
117 t = dns_scope_find_transaction(c->scope, key, c->query->flags);
118 if (!t) {
119 r = dns_transaction_new(&t, c->scope, key, NULL, c->query->flags);
120 if (r < 0)
121 return r;
122 } else if (set_contains(c->transactions, t))
123 return 0;
124 } else {
125 /* "Bypass" lookup with a query packet */
126 assert(bypass);
127
128 r = dns_transaction_new(&t, c->scope, NULL, bypass, c->query->flags);
129 if (r < 0)
130 return r;
131 }
132
133 r = set_ensure_allocated(&t->notify_query_candidates_done, NULL);
134 if (r < 0)
135 return r;
136
137 r = set_ensure_put(&t->notify_query_candidates, NULL, c);
138 if (r < 0)
139 return r;
140
141 r = set_ensure_put(&c->transactions, NULL, t);
142 if (r < 0) {
143 (void) set_remove(t->notify_query_candidates, c);
144 return r;
145 }
146
147 TAKE_PTR(t);
148 return 1;
149 }
150
151 static int dns_query_candidate_go(DnsQueryCandidate *c) {
152 _cleanup_(dns_query_candidate_unrefp) DnsQueryCandidate *keep_c = NULL;
153 DnsTransaction *t;
154 int r;
155 unsigned n = 0;
156
157 assert(c);
158
159 /* Let's keep a reference to the query while we're operating */
160 keep_c = dns_query_candidate_ref(c);
161
162 /* Start the transactions that are not started yet */
163 SET_FOREACH(t, c->transactions) {
164 if (t->state != DNS_TRANSACTION_NULL)
165 continue;
166
167 r = dns_transaction_go(t);
168 if (r < 0)
169 return r;
170
171 n++;
172 }
173
174 /* If there was nothing to start, then let's proceed immediately */
175 if (n == 0)
176 dns_query_candidate_notify(c);
177
178 return 0;
179 }
180
181 static DnsTransactionState dns_query_candidate_state(DnsQueryCandidate *c) {
182 DnsTransactionState state = DNS_TRANSACTION_NO_SERVERS;
183 DnsTransaction *t;
184
185 assert(c);
186
187 if (c->error_code != 0)
188 return DNS_TRANSACTION_ERRNO;
189
190 SET_FOREACH(t, c->transactions)
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 return state;
222 }
223
224 static int dns_query_candidate_setup_transactions(DnsQueryCandidate *c) {
225 DnsQuestion *question;
226 DnsResourceKey *key;
227 int n = 0, r;
228
229 assert(c);
230
231 dns_query_candidate_stop(c);
232
233 if (c->query->question_bypass) {
234 /* If this is a bypass query, then pass the original query packet along to the transaction */
235
236 assert(dns_question_size(c->query->question_bypass->question) == 1);
237
238 if (!dns_scope_good_key(c->scope, dns_question_first_key(c->query->question_bypass->question)))
239 return 0;
240
241 r = dns_query_candidate_add_transaction(c, NULL, c->query->question_bypass);
242 if (r < 0)
243 goto fail;
244
245 return 1;
246 }
247
248 question = dns_query_question_for_protocol(c->query, c->scope->protocol);
249
250 /* Create one transaction per question key */
251 DNS_QUESTION_FOREACH(key, question) {
252 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *new_key = NULL;
253 DnsResourceKey *qkey;
254
255 if (c->search_domain) {
256 r = dns_resource_key_new_append_suffix(&new_key, key, c->search_domain->name);
257 if (r < 0)
258 goto fail;
259
260 qkey = new_key;
261 } else
262 qkey = key;
263
264 if (!dns_scope_good_key(c->scope, qkey))
265 continue;
266
267 r = dns_query_candidate_add_transaction(c, qkey, NULL);
268 if (r < 0)
269 goto fail;
270
271 n++;
272 }
273
274 return n;
275
276 fail:
277 dns_query_candidate_stop(c);
278 return r;
279 }
280
281 void dns_query_candidate_notify(DnsQueryCandidate *c) {
282 DnsTransactionState state;
283 int r;
284
285 assert(c);
286
287 state = dns_query_candidate_state(c);
288
289 if (DNS_TRANSACTION_IS_LIVE(state))
290 return;
291
292 if (state != DNS_TRANSACTION_SUCCESS && c->search_domain) {
293
294 r = dns_query_candidate_next_search_domain(c);
295 if (r < 0)
296 goto fail;
297
298 if (r > 0) {
299 /* OK, there's another search domain to try, let's do so. */
300
301 r = dns_query_candidate_setup_transactions(c);
302 if (r < 0)
303 goto fail;
304
305 if (r > 0) {
306 /* New transactions where queued. Start them and wait */
307
308 r = dns_query_candidate_go(c);
309 if (r < 0)
310 goto fail;
311
312 return;
313 }
314 }
315
316 }
317
318 dns_query_ready(c->query);
319 return;
320
321 fail:
322 c->error_code = log_warning_errno(r, "Failed to follow search domains: %m");
323 dns_query_ready(c->query);
324 }
325
326 static void dns_query_stop(DnsQuery *q) {
327 DnsQueryCandidate *c;
328
329 assert(q);
330
331 q->timeout_event_source = sd_event_source_disable_unref(q->timeout_event_source);
332
333 LIST_FOREACH(candidates_by_query, c, q->candidates)
334 dns_query_candidate_stop(c);
335 }
336
337 static void dns_query_unref_candidates(DnsQuery *q) {
338 assert(q);
339
340 while (q->candidates)
341 dns_query_candidate_unref(q->candidates);
342 }
343
344 static void dns_query_reset_answer(DnsQuery *q) {
345 assert(q);
346
347 q->answer = dns_answer_unref(q->answer);
348 q->answer_rcode = 0;
349 q->answer_dnssec_result = _DNSSEC_RESULT_INVALID;
350 q->answer_errno = 0;
351 q->answer_query_flags = 0;
352 q->answer_protocol = _DNS_PROTOCOL_INVALID;
353 q->answer_family = AF_UNSPEC;
354 q->answer_search_domain = dns_search_domain_unref(q->answer_search_domain);
355 q->answer_full_packet = dns_packet_unref(q->answer_full_packet);
356 }
357
358 DnsQuery *dns_query_free(DnsQuery *q) {
359 if (!q)
360 return NULL;
361
362 while (q->auxiliary_queries)
363 dns_query_free(q->auxiliary_queries);
364
365 if (q->auxiliary_for) {
366 assert(q->auxiliary_for->n_auxiliary_queries > 0);
367 q->auxiliary_for->n_auxiliary_queries--;
368 LIST_REMOVE(auxiliary_queries, q->auxiliary_for->auxiliary_queries, q);
369 }
370
371 dns_query_unref_candidates(q);
372
373 dns_question_unref(q->question_idna);
374 dns_question_unref(q->question_utf8);
375 dns_packet_unref(q->question_bypass);
376
377 dns_query_reset_answer(q);
378
379 sd_bus_message_unref(q->bus_request);
380 sd_bus_track_unref(q->bus_track);
381
382 if (q->varlink_request) {
383 varlink_set_userdata(q->varlink_request, NULL);
384 varlink_unref(q->varlink_request);
385 }
386
387 if (q->request_packet)
388 hashmap_remove_value(q->stub_listener_extra ?
389 q->stub_listener_extra->queries_by_packet :
390 q->manager->stub_queries_by_packet,
391 q->request_packet,
392 q);
393
394 dns_packet_unref(q->request_packet);
395 dns_answer_unref(q->reply_answer);
396 dns_answer_unref(q->reply_authoritative);
397 dns_answer_unref(q->reply_additional);
398
399 if (q->request_stream) {
400 /* Detach the stream from our query, in case something else keeps a reference to it. */
401 (void) set_remove(q->request_stream->queries, q);
402 q->request_stream = dns_stream_unref(q->request_stream);
403 }
404
405 free(q->request_address_string);
406
407 if (q->manager) {
408 LIST_REMOVE(queries, q->manager->dns_queries, q);
409 q->manager->n_dns_queries--;
410 }
411
412 return mfree(q);
413 }
414
415 int dns_query_new(
416 Manager *m,
417 DnsQuery **ret,
418 DnsQuestion *question_utf8,
419 DnsQuestion *question_idna,
420 DnsPacket *question_bypass,
421 int ifindex,
422 uint64_t flags) {
423
424 _cleanup_(dns_query_freep) DnsQuery *q = NULL;
425 char key_str[DNS_RESOURCE_KEY_STRING_MAX];
426 DnsResourceKey *key;
427 int r;
428
429 assert(m);
430
431 if (question_bypass) {
432 /* It's either a "bypass" query, or a regular one, but can't be both. */
433 if (question_utf8 || question_idna)
434 return -EINVAL;
435
436 } else {
437 bool good = false;
438
439 /* This (primarily) checks two things:
440 *
441 * 1. That the question is not empty
442 * 2. That all RR keys in the question objects are for the same domain
443 *
444 * Or in other words, a single DnsQuery object may be used to look up A+AAAA combination for
445 * the same domain name, or SRV+TXT (for DNS-SD services), but not for unrelated lookups. */
446
447 if (dns_question_size(question_utf8) > 0) {
448 r = dns_question_is_valid_for_query(question_utf8);
449 if (r < 0)
450 return r;
451 if (r == 0)
452 return -EINVAL;
453
454 good = true;
455 }
456
457 /* If the IDNA and UTF8 questions are the same, merge their references */
458 r = dns_question_is_equal(question_idna, question_utf8);
459 if (r < 0)
460 return r;
461 if (r > 0)
462 question_idna = question_utf8;
463 else {
464 if (dns_question_size(question_idna) > 0) {
465 r = dns_question_is_valid_for_query(question_idna);
466 if (r < 0)
467 return r;
468 if (r == 0)
469 return -EINVAL;
470
471 good = true;
472 }
473 }
474
475 if (!good) /* don't allow empty queries */
476 return -EINVAL;
477 }
478
479 if (m->n_dns_queries >= QUERIES_MAX)
480 return -EBUSY;
481
482 q = new(DnsQuery, 1);
483 if (!q)
484 return -ENOMEM;
485
486 *q = (DnsQuery) {
487 .question_utf8 = dns_question_ref(question_utf8),
488 .question_idna = dns_question_ref(question_idna),
489 .question_bypass = dns_packet_ref(question_bypass),
490 .ifindex = ifindex,
491 .flags = flags,
492 .answer_dnssec_result = _DNSSEC_RESULT_INVALID,
493 .answer_protocol = _DNS_PROTOCOL_INVALID,
494 .answer_family = AF_UNSPEC,
495 };
496
497 if (question_bypass) {
498 DNS_QUESTION_FOREACH(key, question_bypass->question)
499 log_debug("Looking up bypass packet for %s.",
500 dns_resource_key_to_string(key, key_str, sizeof key_str));
501 } else {
502 /* First dump UTF8 question */
503 DNS_QUESTION_FOREACH(key, question_utf8)
504 log_debug("Looking up RR for %s.",
505 dns_resource_key_to_string(key, key_str, sizeof key_str));
506
507 /* And then dump the IDNA question, but only what hasn't been dumped already through the UTF8 question. */
508 DNS_QUESTION_FOREACH(key, question_idna) {
509 r = dns_question_contains_key(question_utf8, key);
510 if (r < 0)
511 return r;
512 if (r > 0)
513 continue;
514
515 log_debug("Looking up IDNA RR for %s.",
516 dns_resource_key_to_string(key, key_str, sizeof key_str));
517 }
518 }
519
520 LIST_PREPEND(queries, m->dns_queries, q);
521 m->n_dns_queries++;
522 q->manager = m;
523
524 if (ret)
525 *ret = q;
526
527 TAKE_PTR(q);
528 return 0;
529 }
530
531 int dns_query_make_auxiliary(DnsQuery *q, DnsQuery *auxiliary_for) {
532 assert(q);
533 assert(auxiliary_for);
534
535 /* Ensure that the query is not auxiliary yet, and
536 * nothing else is auxiliary to it either */
537 assert(!q->auxiliary_for);
538 assert(!q->auxiliary_queries);
539
540 /* Ensure that the unit we shall be made auxiliary for isn't
541 * auxiliary itself */
542 assert(!auxiliary_for->auxiliary_for);
543
544 if (auxiliary_for->n_auxiliary_queries >= AUXILIARY_QUERIES_MAX)
545 return -EAGAIN;
546
547 LIST_PREPEND(auxiliary_queries, auxiliary_for->auxiliary_queries, q);
548 q->auxiliary_for = auxiliary_for;
549
550 auxiliary_for->n_auxiliary_queries++;
551 return 0;
552 }
553
554 void dns_query_complete(DnsQuery *q, DnsTransactionState state) {
555 assert(q);
556 assert(!DNS_TRANSACTION_IS_LIVE(state));
557 assert(DNS_TRANSACTION_IS_LIVE(q->state));
558
559 /* Note that this call might invalidate the query. Callers should hence not attempt to access the
560 * query or transaction after calling this function. */
561
562 q->state = state;
563
564 dns_query_stop(q);
565 if (q->complete)
566 q->complete(q);
567 }
568
569 static int on_query_timeout(sd_event_source *s, usec_t usec, void *userdata) {
570 DnsQuery *q = userdata;
571
572 assert(s);
573 assert(q);
574
575 dns_query_complete(q, DNS_TRANSACTION_TIMEOUT);
576 return 0;
577 }
578
579 static int dns_query_add_candidate(DnsQuery *q, DnsScope *s) {
580 _cleanup_(dns_query_candidate_unrefp) DnsQueryCandidate *c = NULL;
581 int r;
582
583 assert(q);
584 assert(s);
585
586 r = dns_query_candidate_new(&c, q, s);
587 if (r < 0)
588 return r;
589
590 /* If this a single-label domain on DNS, we might append a suitable search domain first. */
591 if (!FLAGS_SET(q->flags, SD_RESOLVED_NO_SEARCH) &&
592 dns_scope_name_wants_search_domain(s, dns_question_first_name(q->question_idna))) {
593 /* OK, we want a search domain now. Let's find one for this scope */
594
595 r = dns_query_candidate_next_search_domain(c);
596 if (r < 0)
597 return r;
598 }
599
600 r = dns_query_candidate_setup_transactions(c);
601 if (r < 0)
602 return r;
603
604 TAKE_PTR(c);
605 return 0;
606 }
607
608 static int dns_query_synthesize_reply(DnsQuery *q, DnsTransactionState *state) {
609 _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
610 int r;
611
612 assert(q);
613 assert(state);
614
615 /* Tries to synthesize localhost RR replies (and others) where appropriate. Note that this is done *after* the
616 * the normal lookup finished. The data from the network hence takes precedence over the data we
617 * synthesize. (But note that many scopes refuse to resolve certain domain names) */
618
619 if (!IN_SET(*state,
620 DNS_TRANSACTION_RCODE_FAILURE,
621 DNS_TRANSACTION_NO_SERVERS,
622 DNS_TRANSACTION_TIMEOUT,
623 DNS_TRANSACTION_ATTEMPTS_MAX_REACHED,
624 DNS_TRANSACTION_NETWORK_DOWN,
625 DNS_TRANSACTION_NOT_FOUND))
626 return 0;
627
628 if (FLAGS_SET(q->flags, SD_RESOLVED_NO_SYNTHESIZE))
629 return 0;
630
631 r = dns_synthesize_answer(
632 q->manager,
633 q->question_bypass ? q->question_bypass->question : q->question_utf8,
634 q->ifindex,
635 &answer);
636 if (r == -ENXIO) {
637 /* If we get ENXIO this tells us to generate NXDOMAIN unconditionally. */
638
639 dns_query_reset_answer(q);
640 q->answer_rcode = DNS_RCODE_NXDOMAIN;
641 q->answer_protocol = dns_synthesize_protocol(q->flags);
642 q->answer_family = dns_synthesize_family(q->flags);
643 q->answer_query_flags = SD_RESOLVED_AUTHENTICATED|SD_RESOLVED_CONFIDENTIAL|SD_RESOLVED_SYNTHETIC;
644 *state = DNS_TRANSACTION_RCODE_FAILURE;
645
646 return 0;
647 }
648 if (r <= 0)
649 return r;
650
651 dns_query_reset_answer(q);
652
653 q->answer = TAKE_PTR(answer);
654 q->answer_rcode = DNS_RCODE_SUCCESS;
655 q->answer_protocol = dns_synthesize_protocol(q->flags);
656 q->answer_family = dns_synthesize_family(q->flags);
657 q->answer_query_flags = SD_RESOLVED_AUTHENTICATED|SD_RESOLVED_CONFIDENTIAL|SD_RESOLVED_SYNTHETIC;
658
659 *state = DNS_TRANSACTION_SUCCESS;
660
661 return 1;
662 }
663
664 static int dns_query_try_etc_hosts(DnsQuery *q) {
665 _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
666 int r;
667
668 assert(q);
669
670 /* Looks in /etc/hosts for matching entries. Note that this is done *before* the normal lookup is
671 * done. The data from /etc/hosts hence takes precedence over the network. */
672
673 if (FLAGS_SET(q->flags, SD_RESOLVED_NO_SYNTHESIZE))
674 return 0;
675
676 r = manager_etc_hosts_lookup(
677 q->manager,
678 q->question_bypass ? q->question_bypass->question : q->question_utf8,
679 &answer);
680 if (r <= 0)
681 return r;
682
683 dns_query_reset_answer(q);
684
685 q->answer = TAKE_PTR(answer);
686 q->answer_rcode = DNS_RCODE_SUCCESS;
687 q->answer_protocol = dns_synthesize_protocol(q->flags);
688 q->answer_family = dns_synthesize_family(q->flags);
689 q->answer_query_flags = SD_RESOLVED_AUTHENTICATED|SD_RESOLVED_CONFIDENTIAL|SD_RESOLVED_SYNTHETIC;
690
691 return 1;
692 }
693
694 int dns_query_go(DnsQuery *q) {
695 DnsScopeMatch found = DNS_SCOPE_NO;
696 DnsScope *s, *first = NULL;
697 DnsQueryCandidate *c;
698 int r;
699
700 assert(q);
701
702 if (q->state != DNS_TRANSACTION_NULL)
703 return 0;
704
705 r = dns_query_try_etc_hosts(q);
706 if (r < 0)
707 return r;
708 if (r > 0) {
709 dns_query_complete(q, DNS_TRANSACTION_SUCCESS);
710 return 1;
711 }
712
713 LIST_FOREACH(scopes, s, q->manager->dns_scopes) {
714 DnsScopeMatch match;
715 const char *name;
716
717 name = dns_question_first_name(dns_query_question_for_protocol(q, s->protocol));
718 if (!name)
719 continue;
720
721 match = dns_scope_good_domain(s, q->ifindex, q->flags, name);
722 if (match < 0) {
723 log_debug("Couldn't check if '%s' matches against scope, ignoring.", name);
724 continue;
725 }
726
727 if (match > found) { /* Does this match better? If so, remember how well it matched, and the first one
728 * that matches this well */
729 found = match;
730 first = s;
731 }
732 }
733
734 if (found == DNS_SCOPE_NO) {
735 DnsTransactionState state = DNS_TRANSACTION_NO_SERVERS;
736
737 r = dns_query_synthesize_reply(q, &state);
738 if (r < 0)
739 return r;
740
741 dns_query_complete(q, state);
742 return 1;
743 }
744
745 r = dns_query_add_candidate(q, first);
746 if (r < 0)
747 goto fail;
748
749 LIST_FOREACH(scopes, s, first->scopes_next) {
750 DnsScopeMatch match;
751 const char *name;
752
753 name = dns_question_first_name(dns_query_question_for_protocol(q, s->protocol));
754 if (!name)
755 continue;
756
757 match = dns_scope_good_domain(s, q->ifindex, q->flags, name);
758 if (match < 0) {
759 log_debug("Couldn't check if '%s' matches against scope, ignoring.", name);
760 continue;
761 }
762
763 if (match < found)
764 continue;
765
766 r = dns_query_add_candidate(q, s);
767 if (r < 0)
768 goto fail;
769 }
770
771 dns_query_reset_answer(q);
772
773 r = sd_event_add_time_relative(
774 q->manager->event,
775 &q->timeout_event_source,
776 clock_boottime_or_monotonic(),
777 SD_RESOLVED_QUERY_TIMEOUT_USEC,
778 0, on_query_timeout, q);
779 if (r < 0)
780 goto fail;
781
782 (void) sd_event_source_set_description(q->timeout_event_source, "query-timeout");
783
784 q->state = DNS_TRANSACTION_PENDING;
785 q->block_ready++;
786
787 /* Start the transactions */
788 LIST_FOREACH(candidates_by_query, c, q->candidates) {
789 r = dns_query_candidate_go(c);
790 if (r < 0) {
791 q->block_ready--;
792 goto fail;
793 }
794 }
795
796 q->block_ready--;
797 dns_query_ready(q);
798
799 return 1;
800
801 fail:
802 dns_query_stop(q);
803 return r;
804 }
805
806 static void dns_query_accept(DnsQuery *q, DnsQueryCandidate *c) {
807 DnsTransactionState state = DNS_TRANSACTION_NO_SERVERS;
808 bool has_authenticated = false, has_non_authenticated = false, has_confidential = false, has_non_confidential = false;
809 DnssecResult dnssec_result_authenticated = _DNSSEC_RESULT_INVALID, dnssec_result_non_authenticated = _DNSSEC_RESULT_INVALID;
810 DnsTransaction *t;
811 int r;
812
813 assert(q);
814
815 if (!c) {
816 r = dns_query_synthesize_reply(q, &state);
817 if (r < 0)
818 goto fail;
819
820 dns_query_complete(q, state);
821 return;
822 }
823
824 if (c->error_code != 0) {
825 /* If the candidate had an error condition of its own, start with that. */
826 state = DNS_TRANSACTION_ERRNO;
827 q->answer = dns_answer_unref(q->answer);
828 q->answer_rcode = 0;
829 q->answer_dnssec_result = _DNSSEC_RESULT_INVALID;
830 q->answer_query_flags = 0;
831 q->answer_errno = c->error_code;
832 q->answer_full_packet = dns_packet_unref(q->answer_full_packet);
833 }
834
835 SET_FOREACH(t, c->transactions) {
836
837 switch (t->state) {
838
839 case DNS_TRANSACTION_SUCCESS: {
840 /* We found a successful reply, merge it into the answer */
841
842 if (state == DNS_TRANSACTION_SUCCESS) {
843 r = dns_answer_extend(&q->answer, t->answer);
844 if (r < 0)
845 goto fail;
846
847 q->answer_query_flags |= dns_transaction_source_to_query_flags(t->answer_source);
848 } else {
849 /* Override non-successful previous answers */
850 dns_answer_unref(q->answer);
851 q->answer = dns_answer_ref(t->answer);
852
853 q->answer_query_flags = dns_transaction_source_to_query_flags(t->answer_source);
854 }
855
856 q->answer_rcode = t->answer_rcode;
857 q->answer_errno = 0;
858
859 dns_packet_unref(q->answer_full_packet);
860 q->answer_full_packet = dns_packet_ref(t->received);
861
862 if (FLAGS_SET(t->answer_query_flags, SD_RESOLVED_AUTHENTICATED)) {
863 has_authenticated = true;
864 dnssec_result_authenticated = t->answer_dnssec_result;
865 } else {
866 has_non_authenticated = true;
867 dnssec_result_non_authenticated = t->answer_dnssec_result;
868 }
869
870 if (FLAGS_SET(t->answer_query_flags, SD_RESOLVED_CONFIDENTIAL))
871 has_confidential = true;
872 else
873 has_non_confidential = true;
874
875 state = DNS_TRANSACTION_SUCCESS;
876 break;
877 }
878
879 case DNS_TRANSACTION_NULL:
880 case DNS_TRANSACTION_PENDING:
881 case DNS_TRANSACTION_VALIDATING:
882 case DNS_TRANSACTION_ABORTED:
883 /* Ignore transactions that didn't complete */
884 continue;
885
886 default:
887 /* Any kind of failure? Store the data away, if there's nothing stored yet. */
888 if (state == DNS_TRANSACTION_SUCCESS)
889 continue;
890
891 /* If there's already an authenticated negative reply stored, then prefer that over any unauthenticated one */
892 if (FLAGS_SET(q->answer_query_flags, SD_RESOLVED_AUTHENTICATED) &&
893 !FLAGS_SET(t->answer_query_flags, SD_RESOLVED_AUTHENTICATED))
894 continue;
895
896 dns_answer_unref(q->answer);
897 q->answer = dns_answer_ref(t->answer);
898 q->answer_rcode = t->answer_rcode;
899 q->answer_dnssec_result = t->answer_dnssec_result;
900 q->answer_query_flags = t->answer_query_flags | dns_transaction_source_to_query_flags(t->answer_source);
901 q->answer_errno = t->answer_errno;
902 dns_packet_unref(q->answer_full_packet);
903 q->answer_full_packet = dns_packet_ref(t->received);
904
905 state = t->state;
906 break;
907 }
908 }
909
910 if (state == DNS_TRANSACTION_SUCCESS) {
911 SET_FLAG(q->answer_query_flags, SD_RESOLVED_AUTHENTICATED, has_authenticated && !has_non_authenticated);
912 SET_FLAG(q->answer_query_flags, SD_RESOLVED_CONFIDENTIAL, has_confidential && !has_non_confidential);
913 q->answer_dnssec_result = FLAGS_SET(q->answer_query_flags, SD_RESOLVED_AUTHENTICATED) ? dnssec_result_authenticated : dnssec_result_non_authenticated;
914 }
915
916 q->answer_protocol = c->scope->protocol;
917 q->answer_family = c->scope->family;
918
919 dns_search_domain_unref(q->answer_search_domain);
920 q->answer_search_domain = dns_search_domain_ref(c->search_domain);
921
922 r = dns_query_synthesize_reply(q, &state);
923 if (r < 0)
924 goto fail;
925
926 dns_query_complete(q, state);
927 return;
928
929 fail:
930 q->answer_errno = -r;
931 dns_query_complete(q, DNS_TRANSACTION_ERRNO);
932 }
933
934 void dns_query_ready(DnsQuery *q) {
935
936 DnsQueryCandidate *bad = NULL, *c;
937 bool pending = false;
938
939 assert(q);
940 assert(DNS_TRANSACTION_IS_LIVE(q->state));
941
942 /* Note that this call might invalidate the query. Callers
943 * should hence not attempt to access the query or transaction
944 * after calling this function, unless the block_ready
945 * counter was explicitly bumped before doing so. */
946
947 if (q->block_ready > 0)
948 return;
949
950 LIST_FOREACH(candidates_by_query, c, q->candidates) {
951 DnsTransactionState state;
952
953 state = dns_query_candidate_state(c);
954 switch (state) {
955
956 case DNS_TRANSACTION_SUCCESS:
957 /* One of the candidates is successful,
958 * let's use it, and copy its data out */
959 dns_query_accept(q, c);
960 return;
961
962 case DNS_TRANSACTION_NULL:
963 case DNS_TRANSACTION_PENDING:
964 case DNS_TRANSACTION_VALIDATING:
965 /* One of the candidates is still going on,
966 * let's maybe wait for it */
967 pending = true;
968 break;
969
970 default:
971 /* Any kind of failure */
972 bad = c;
973 break;
974 }
975 }
976
977 if (pending)
978 return;
979
980 dns_query_accept(q, bad);
981 }
982
983 static int dns_query_cname_redirect(DnsQuery *q, const DnsResourceRecord *cname) {
984 _cleanup_(dns_question_unrefp) DnsQuestion *nq_idna = NULL, *nq_utf8 = NULL;
985 int r, k;
986
987 assert(q);
988
989 if (q->n_cname_redirects >= CNAME_REDIRECTS_MAX)
990 return -ELOOP;
991 q->n_cname_redirects++;
992
993 r = dns_question_cname_redirect(q->question_idna, cname, &nq_idna);
994 if (r < 0)
995 return r;
996 if (r > 0)
997 log_debug("Following CNAME/DNAME %s → %s.", dns_question_first_name(q->question_idna), dns_question_first_name(nq_idna));
998
999 k = dns_question_is_equal(q->question_idna, q->question_utf8);
1000 if (k < 0)
1001 return k;
1002 if (k > 0) {
1003 /* Same question? Shortcut new question generation */
1004 nq_utf8 = dns_question_ref(nq_idna);
1005 k = r;
1006 } else {
1007 k = dns_question_cname_redirect(q->question_utf8, cname, &nq_utf8);
1008 if (k < 0)
1009 return k;
1010 if (k > 0)
1011 log_debug("Following UTF8 CNAME/DNAME %s → %s.", dns_question_first_name(q->question_utf8), dns_question_first_name(nq_utf8));
1012 }
1013
1014 if (r == 0 && k == 0) /* No actual cname happened? */
1015 return -ELOOP;
1016
1017 if (q->answer_protocol == DNS_PROTOCOL_DNS)
1018 /* Don't permit CNAME redirects from unicast DNS to LLMNR or MulticastDNS, so that global resources
1019 * cannot invade the local namespace. The opposite way we permit: local names may redirect to global
1020 * ones. */
1021 q->flags &= ~(SD_RESOLVED_LLMNR|SD_RESOLVED_MDNS); /* mask away the local protocols */
1022
1023 /* Turn off searching for the new name */
1024 q->flags |= SD_RESOLVED_NO_SEARCH;
1025
1026 dns_question_unref(q->question_idna);
1027 q->question_idna = TAKE_PTR(nq_idna);
1028
1029 dns_question_unref(q->question_utf8);
1030 q->question_utf8 = TAKE_PTR(nq_utf8);
1031
1032 dns_query_unref_candidates(q);
1033
1034 /* Note that we do *not* reset the answer here, because the answer we previously got might already
1035 * include everything we need, let's check that first */
1036
1037 q->state = DNS_TRANSACTION_NULL;
1038
1039 return 0;
1040 }
1041
1042 int dns_query_process_cname_one(DnsQuery *q) {
1043 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *cname = NULL;
1044 DnsQuestion *question;
1045 DnsResourceRecord *rr;
1046 bool full_match = true;
1047 DnsResourceKey *k;
1048 int r;
1049
1050 assert(q);
1051
1052 /* Processes a CNAME redirect if there's one. Returns one of three values:
1053 *
1054 * CNAME_QUERY_MATCH → direct RR match, caller should just use the RRs in this answer (and not
1055 * bother with any CNAME/DNAME stuff)
1056 *
1057 * CNAME_QUERY_NOMATCH → no match at all, neither direct nor CNAME/DNAME, caller might decide to
1058 * restart query or take things as NODATA reply.
1059 *
1060 * CNAME_QUERY_CNAME → no direct RR match, but a CNAME/DNAME match that we now followed for one step.
1061 *
1062 * The function might also return a failure, in particular -ELOOP if we encountered too many
1063 * CNAMEs/DNAMEs in a chain or if following CNAMEs/DNAMEs was turned off.
1064 *
1065 * Note that this function doesn't actually restart the query. The caller can decide to do that in
1066 * case of CNAME_QUERY_CNAME, though. */
1067
1068 if (!IN_SET(q->state, DNS_TRANSACTION_SUCCESS, DNS_TRANSACTION_NULL))
1069 return DNS_QUERY_NOMATCH;
1070
1071 question = dns_query_question_for_protocol(q, q->answer_protocol);
1072
1073 /* Small reminder: our question will consist of one or more RR keys that match in name, but not in
1074 * record type. Specifically, when we do an address lookup the question will typically consist of one
1075 * A and one AAAA key lookup for the same domain name. When we get a response from a server we need
1076 * to check if the answer answers all our questions to use it. Note that a response of CNAME/DNAME
1077 * can answer both an A and the AAAA question for us, but an A/AAAA response only the relevant
1078 * type.
1079 *
1080 * Hence we first check of the answers we collected are sufficient to answer all our questions
1081 * directly. If one question wasn't answered we go on, waiting for more replies. However, if there's
1082 * a CNAME/DNAME response we use it, and redirect to it, regardless if it was a response to the A or
1083 * the AAAA query.*/
1084
1085 DNS_QUESTION_FOREACH(k, question) {
1086 bool match = false;
1087
1088 DNS_ANSWER_FOREACH(rr, q->answer) {
1089 r = dns_resource_key_match_rr(k, rr, DNS_SEARCH_DOMAIN_NAME(q->answer_search_domain));
1090 if (r < 0)
1091 return r;
1092 if (r > 0) {
1093 match = true; /* Yay, we found an RR that matches the key we are looking for */
1094 break;
1095 }
1096 }
1097
1098 if (!match) {
1099 /* Hmm. :-( there's no response for this key. This doesn't match. */
1100 full_match = false;
1101 break;
1102 }
1103 }
1104
1105 if (full_match)
1106 return DNS_QUERY_MATCH; /* The answer can answer our question in full, no need to follow CNAMEs/DNAMEs */
1107
1108 /* Let's see if there is a CNAME/DNAME to match. This case is simpler: we accept the CNAME/DNAME that
1109 * matches any of our questions. */
1110 DNS_ANSWER_FOREACH(rr, q->answer) {
1111 r = dns_question_matches_cname_or_dname(question, rr, DNS_SEARCH_DOMAIN_NAME(q->answer_search_domain));
1112 if (r < 0)
1113 return r;
1114 if (r > 0 && !cname)
1115 cname = dns_resource_record_ref(rr);
1116 }
1117
1118 if (!cname)
1119 return DNS_QUERY_NOMATCH; /* No match and no CNAME/DNAME to follow */
1120
1121 if (q->flags & SD_RESOLVED_NO_CNAME)
1122 return -ELOOP;
1123
1124 if (!FLAGS_SET(q->answer_query_flags, SD_RESOLVED_AUTHENTICATED))
1125 q->previous_redirect_unauthenticated = true;
1126 if (!FLAGS_SET(q->answer_query_flags, SD_RESOLVED_CONFIDENTIAL))
1127 q->previous_redirect_non_confidential = true;
1128 if (!FLAGS_SET(q->answer_query_flags, SD_RESOLVED_SYNTHETIC))
1129 q->previous_redirect_non_synthetic = true;
1130
1131 /* OK, let's actually follow the CNAME */
1132 r = dns_query_cname_redirect(q, cname);
1133 if (r < 0)
1134 return r;
1135
1136 return DNS_QUERY_CNAME; /* Tell caller that we did a single CNAME/DNAME redirection step */
1137 }
1138
1139 int dns_query_process_cname_many(DnsQuery *q) {
1140 int r;
1141
1142 assert(q);
1143
1144 /* Follows CNAMEs through the current packet: as long as the current packet can fulfill our
1145 * redirected CNAME queries we keep going, and restart the query once the current packet isn't good
1146 * enough anymore. It's a wrapper around dns_query_process_cname_one() and returns the same values,
1147 * but with extended semantics. Specifically:
1148 *
1149 * DNS_QUERY_MATCH → as above
1150 *
1151 * DNS_QUERY_CNAME → we ran into a CNAME/DNAME redirect that we could not answer from the current
1152 * message, and thus restarted the query to resolve it.
1153 *
1154 * DNS_QUERY_NOMATCH → we reached the end of CNAME/DNAME chain, and there are no direct matches nor a
1155 * CNAME/DNAME match. i.e. this is a NODATA case.
1156 *
1157 * Note that this function will restart the query for the caller if needed, and that's the case
1158 * DNS_QUERY_CNAME is returned.
1159 */
1160
1161 r = dns_query_process_cname_one(q);
1162 if (r != DNS_QUERY_CNAME)
1163 return r; /* The first redirect is special: if it doesn't answer the question that's no
1164 * reason to restart the query, we just accept this as a NODATA answer. */
1165
1166 for (;;) {
1167 r = dns_query_process_cname_one(q);
1168 if (r < 0 || r == DNS_QUERY_MATCH)
1169 return r;
1170 if (r == DNS_QUERY_NOMATCH) {
1171 /* OK, so we followed one or more CNAME/DNAME RR but the existing packet can't answer
1172 * this. Let's restart the query hence, with the new question. Why the different
1173 * handling than the first chain element? Because if the server answers a direct
1174 * question with an empty answer then this is a NODATA response. But if it responds
1175 * with a CNAME chain that ultimately is incomplete (i.e. a non-empty but truncated
1176 * CNAME chain) then we better follow up ourselves and ask for the rest of the
1177 * chain. This is particular relevant since our cache will store CNAME/DNAME
1178 * redirects that we learnt about for lookups of certain DNS types, but later on we
1179 * can reuse this data even for other DNS types, but in that case need to follow up
1180 * with the final lookup of the chain ourselves with the RR type we ourselves are
1181 * interested in. */
1182 r = dns_query_go(q);
1183 if (r < 0)
1184 return r;
1185
1186 return DNS_QUERY_CNAME;
1187 }
1188
1189 /* So we found a CNAME that the existing packet already answers, again via a CNAME, let's
1190 * continue going then. */
1191 assert(r == DNS_QUERY_CNAME);
1192 }
1193 }
1194
1195 DnsQuestion* dns_query_question_for_protocol(DnsQuery *q, DnsProtocol protocol) {
1196 assert(q);
1197
1198 if (q->question_bypass)
1199 return q->question_bypass->question;
1200
1201 switch (protocol) {
1202
1203 case DNS_PROTOCOL_DNS:
1204 return q->question_idna;
1205
1206 case DNS_PROTOCOL_MDNS:
1207 case DNS_PROTOCOL_LLMNR:
1208 return q->question_utf8;
1209
1210 default:
1211 return NULL;
1212 }
1213 }
1214
1215 const char *dns_query_string(DnsQuery *q) {
1216 const char *name;
1217 int r;
1218
1219 /* Returns a somewhat useful human-readable lookup key string for this query */
1220
1221 if (q->question_bypass)
1222 return dns_question_first_name(q->question_bypass->question);
1223
1224 if (q->request_address_string)
1225 return q->request_address_string;
1226
1227 if (q->request_address_valid) {
1228 r = in_addr_to_string(q->request_family, &q->request_address, &q->request_address_string);
1229 if (r >= 0)
1230 return q->request_address_string;
1231 }
1232
1233 name = dns_question_first_name(q->question_utf8);
1234 if (name)
1235 return name;
1236
1237 return dns_question_first_name(q->question_idna);
1238 }
1239
1240 bool dns_query_fully_authenticated(DnsQuery *q) {
1241 assert(q);
1242
1243 return FLAGS_SET(q->answer_query_flags, SD_RESOLVED_AUTHENTICATED) && !q->previous_redirect_unauthenticated;
1244 }
1245
1246 bool dns_query_fully_confidential(DnsQuery *q) {
1247 assert(q);
1248
1249 return FLAGS_SET(q->answer_query_flags, SD_RESOLVED_CONFIDENTIAL) && !q->previous_redirect_non_confidential;
1250 }
1251
1252 bool dns_query_fully_authoritative(DnsQuery *q) {
1253 assert(q);
1254
1255 /* We are authoritative for everything synthetic (except if a previous CNAME/DNAME) wasn't
1256 * synthetic. (Note: SD_RESOLVED_SYNTHETIC is reset on each CNAME/DNAME, hence the explicit check for
1257 * previous synthetic DNAME/CNAME redirections.)*/
1258 if ((q->answer_query_flags & SD_RESOLVED_SYNTHETIC) && !q->previous_redirect_non_synthetic)
1259 return true;
1260
1261 /* We are also authoritative for everything coming only from the trust anchor and the local
1262 * zones. (Note: the SD_RESOLVED_FROM_xyz flags we merge on each redirect, hence no need to
1263 * explicitly check previous redirects here.)*/
1264 return (q->answer_query_flags & SD_RESOLVED_FROM_MASK & ~(SD_RESOLVED_FROM_TRUST_ANCHOR | SD_RESOLVED_FROM_ZONE)) == 0;
1265 }