1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include "alloc-util.h"
4 #include "dns-domain.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"
14 #define QUERIES_MAX 2048
15 #define AUXILIARY_QUERIES_MAX 64
17 static int dns_query_candidate_new(DnsQueryCandidate
**ret
, DnsQuery
*q
, DnsScope
*s
) {
24 c
= new(DnsQueryCandidate
, 1);
28 *c
= (DnsQueryCandidate
) {
34 LIST_PREPEND(candidates_by_query
, q
->candidates
, c
);
35 LIST_PREPEND(candidates_by_scope
, s
->query_candidates
, c
);
41 static void dns_query_candidate_stop(DnsQueryCandidate
*c
) {
46 while ((t
= set_steal_first(c
->transactions
))) {
47 set_remove(t
->notify_query_candidates
, c
);
48 set_remove(t
->notify_query_candidates_done
, c
);
49 dns_transaction_gc(t
);
53 static DnsQueryCandidate
* dns_query_candidate_free(DnsQueryCandidate
*c
) {
57 dns_query_candidate_stop(c
);
59 set_free(c
->transactions
);
60 dns_search_domain_unref(c
->search_domain
);
63 LIST_REMOVE(candidates_by_query
, c
->query
->candidates
, c
);
66 LIST_REMOVE(candidates_by_scope
, c
->scope
->query_candidates
, c
);
71 DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(DnsQueryCandidate
, dns_query_candidate
, dns_query_candidate_free
);
73 static int dns_query_candidate_next_search_domain(DnsQueryCandidate
*c
) {
74 DnsSearchDomain
*next
;
78 if (c
->search_domain
&& c
->search_domain
->linked
)
79 next
= c
->search_domain
->domains_next
;
81 next
= dns_scope_get_search_domains(c
->scope
);
84 if (!next
) /* We hit the end of the list */
87 if (!next
->route_only
)
90 /* Skip over route-only domains */
91 next
= next
->domains_next
;
94 dns_search_domain_unref(c
->search_domain
);
95 c
->search_domain
= dns_search_domain_ref(next
);
100 static int dns_query_candidate_add_transaction(
101 DnsQueryCandidate
*c
,
105 _cleanup_(dns_transaction_gcp
) DnsTransaction
*t
= NULL
;
111 /* Regular lookup with a resource key */
114 t
= dns_scope_find_transaction(c
->scope
, key
, c
->query
->flags
);
116 r
= dns_transaction_new(&t
, c
->scope
, key
, NULL
, c
->query
->flags
);
119 } else if (set_contains(c
->transactions
, t
))
122 /* "Bypass" lookup with a query packet */
125 r
= dns_transaction_new(&t
, c
->scope
, NULL
, bypass
, c
->query
->flags
);
130 r
= set_ensure_allocated(&t
->notify_query_candidates_done
, NULL
);
134 r
= set_ensure_put(&t
->notify_query_candidates
, NULL
, c
);
138 r
= set_ensure_put(&c
->transactions
, NULL
, t
);
140 (void) set_remove(t
->notify_query_candidates
, c
);
148 static int dns_query_candidate_go(DnsQueryCandidate
*c
) {
149 _cleanup_(dns_query_candidate_unrefp
) DnsQueryCandidate
*keep_c
= NULL
;
156 /* Let's keep a reference to the query while we're operating */
157 keep_c
= dns_query_candidate_ref(c
);
159 /* Start the transactions that are not started yet */
160 SET_FOREACH(t
, c
->transactions
) {
161 if (t
->state
!= DNS_TRANSACTION_NULL
)
164 r
= dns_transaction_go(t
);
171 /* If there was nothing to start, then let's proceed immediately */
173 dns_query_candidate_notify(c
);
178 static DnsTransactionState
dns_query_candidate_state(DnsQueryCandidate
*c
) {
179 DnsTransactionState state
= DNS_TRANSACTION_NO_SERVERS
;
184 if (c
->error_code
!= 0)
185 return DNS_TRANSACTION_ERRNO
;
187 SET_FOREACH(t
, c
->transactions
) {
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. */
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
;
207 case DNS_TRANSACTION_SUCCESS
:
212 if (state
!= DNS_TRANSACTION_SUCCESS
)
222 static int dns_query_candidate_setup_transactions(DnsQueryCandidate
*c
) {
223 DnsQuestion
*question
;
229 dns_query_candidate_stop(c
);
231 if (c
->query
->question_bypass
) {
232 /* If this is a bypass query, then pass the original query packet along to the transaction */
234 assert(dns_question_size(c
->query
->question_bypass
->question
) == 1);
236 if (!dns_scope_good_key(c
->scope
, c
->query
->question_bypass
->question
->keys
[0]))
239 r
= dns_query_candidate_add_transaction(c
, NULL
, c
->query
->question_bypass
);
246 question
= dns_query_question_for_protocol(c
->query
, c
->scope
->protocol
);
248 /* Create one transaction per question key */
249 DNS_QUESTION_FOREACH(key
, question
) {
250 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*new_key
= NULL
;
251 DnsResourceKey
*qkey
;
253 if (c
->search_domain
) {
254 r
= dns_resource_key_new_append_suffix(&new_key
, key
, c
->search_domain
->name
);
262 if (!dns_scope_good_key(c
->scope
, qkey
))
265 r
= dns_query_candidate_add_transaction(c
, qkey
, NULL
);
275 dns_query_candidate_stop(c
);
279 void dns_query_candidate_notify(DnsQueryCandidate
*c
) {
280 DnsTransactionState state
;
285 state
= dns_query_candidate_state(c
);
287 if (DNS_TRANSACTION_IS_LIVE(state
))
290 if (state
!= DNS_TRANSACTION_SUCCESS
&& c
->search_domain
) {
292 r
= dns_query_candidate_next_search_domain(c
);
297 /* OK, there's another search domain to try, let's do so. */
299 r
= dns_query_candidate_setup_transactions(c
);
304 /* New transactions where queued. Start them and wait */
306 r
= dns_query_candidate_go(c
);
316 dns_query_ready(c
->query
);
320 c
->error_code
= log_warning_errno(r
, "Failed to follow search domains: %m");
321 dns_query_ready(c
->query
);
324 static void dns_query_stop(DnsQuery
*q
) {
325 DnsQueryCandidate
*c
;
329 q
->timeout_event_source
= sd_event_source_unref(q
->timeout_event_source
);
331 LIST_FOREACH(candidates_by_query
, c
, q
->candidates
)
332 dns_query_candidate_stop(c
);
335 static void dns_query_unref_candidates(DnsQuery
*q
) {
338 while (q
->candidates
)
339 dns_query_candidate_unref(q
->candidates
);
342 static void dns_query_reset_answer(DnsQuery
*q
) {
345 q
->answer
= dns_answer_unref(q
->answer
);
347 q
->answer_dnssec_result
= _DNSSEC_RESULT_INVALID
;
349 q
->answer_authenticated
= false;
350 q
->answer_protocol
= _DNS_PROTOCOL_INVALID
;
351 q
->answer_family
= AF_UNSPEC
;
352 q
->answer_search_domain
= dns_search_domain_unref(q
->answer_search_domain
);
353 q
->answer_full_packet
= dns_packet_unref(q
->answer_full_packet
);
356 DnsQuery
*dns_query_free(DnsQuery
*q
) {
360 while (q
->auxiliary_queries
)
361 dns_query_free(q
->auxiliary_queries
);
363 if (q
->auxiliary_for
) {
364 assert(q
->auxiliary_for
->n_auxiliary_queries
> 0);
365 q
->auxiliary_for
->n_auxiliary_queries
--;
366 LIST_REMOVE(auxiliary_queries
, q
->auxiliary_for
->auxiliary_queries
, q
);
369 dns_query_unref_candidates(q
);
371 dns_question_unref(q
->question_idna
);
372 dns_question_unref(q
->question_utf8
);
373 dns_packet_unref(q
->question_bypass
);
375 dns_query_reset_answer(q
);
377 sd_bus_message_unref(q
->bus_request
);
378 sd_bus_track_unref(q
->bus_track
);
380 if (q
->varlink_request
) {
381 varlink_set_userdata(q
->varlink_request
, NULL
);
382 varlink_unref(q
->varlink_request
);
385 if (q
->request_packet
)
386 hashmap_remove_value(q
->stub_listener_extra
?
387 q
->stub_listener_extra
->queries_by_packet
:
388 q
->manager
->stub_queries_by_packet
,
392 dns_packet_unref(q
->request_packet
);
393 dns_answer_unref(q
->reply_answer
);
394 dns_answer_unref(q
->reply_authoritative
);
395 dns_answer_unref(q
->reply_additional
);
397 if (q
->request_stream
) {
398 /* Detach the stream from our query, in case something else keeps a reference to it. */
399 (void) set_remove(q
->request_stream
->queries
, q
);
400 q
->request_stream
= dns_stream_unref(q
->request_stream
);
403 free(q
->request_address_string
);
406 LIST_REMOVE(queries
, q
->manager
->dns_queries
, q
);
407 q
->manager
->n_dns_queries
--;
416 DnsQuestion
*question_utf8
,
417 DnsQuestion
*question_idna
,
418 DnsPacket
*question_bypass
,
422 _cleanup_(dns_query_freep
) DnsQuery
*q
= NULL
;
423 char key_str
[DNS_RESOURCE_KEY_STRING_MAX
];
429 if (question_bypass
) {
430 /* It's either a "bypass" query, or a regular one, but can't be both. */
431 if (question_utf8
|| question_idna
)
437 if (dns_question_size(question_utf8
) > 0) {
438 r
= dns_question_is_valid_for_query(question_utf8
);
447 /* If the IDNA and UTF8 questions are the same, merge their references */
448 r
= dns_question_is_equal(question_idna
, question_utf8
);
452 question_idna
= question_utf8
;
454 if (dns_question_size(question_idna
) > 0) {
455 r
= dns_question_is_valid_for_query(question_idna
);
465 if (!good
) /* don't allow empty queries */
469 if (m
->n_dns_queries
>= QUERIES_MAX
)
472 q
= new(DnsQuery
, 1);
477 .question_utf8
= dns_question_ref(question_utf8
),
478 .question_idna
= dns_question_ref(question_idna
),
479 .question_bypass
= dns_packet_ref(question_bypass
),
482 .answer_dnssec_result
= _DNSSEC_RESULT_INVALID
,
483 .answer_protocol
= _DNS_PROTOCOL_INVALID
,
484 .answer_family
= AF_UNSPEC
,
487 if (question_bypass
) {
488 DNS_QUESTION_FOREACH(key
, question_bypass
->question
)
489 log_debug("Looking up bypass packet for %s.",
490 dns_resource_key_to_string(key
, key_str
, sizeof key_str
));
492 /* First dump UTF8 question */
493 DNS_QUESTION_FOREACH(key
, question_utf8
)
494 log_debug("Looking up RR for %s.",
495 dns_resource_key_to_string(key
, key_str
, sizeof key_str
));
497 /* And then dump the IDNA question, but only what hasn't been dumped already through the UTF8 question. */
498 DNS_QUESTION_FOREACH(key
, question_idna
) {
499 r
= dns_question_contains(question_utf8
, key
);
505 log_debug("Looking up IDNA RR for %s.",
506 dns_resource_key_to_string(key
, key_str
, sizeof key_str
));
510 LIST_PREPEND(queries
, m
->dns_queries
, q
);
521 int dns_query_make_auxiliary(DnsQuery
*q
, DnsQuery
*auxiliary_for
) {
523 assert(auxiliary_for
);
525 /* Ensure that the query is not auxiliary yet, and
526 * nothing else is auxiliary to it either */
527 assert(!q
->auxiliary_for
);
528 assert(!q
->auxiliary_queries
);
530 /* Ensure that the unit we shall be made auxiliary for isn't
531 * auxiliary itself */
532 assert(!auxiliary_for
->auxiliary_for
);
534 if (auxiliary_for
->n_auxiliary_queries
>= AUXILIARY_QUERIES_MAX
)
537 LIST_PREPEND(auxiliary_queries
, auxiliary_for
->auxiliary_queries
, q
);
538 q
->auxiliary_for
= auxiliary_for
;
540 auxiliary_for
->n_auxiliary_queries
++;
544 void dns_query_complete(DnsQuery
*q
, DnsTransactionState state
) {
546 assert(!DNS_TRANSACTION_IS_LIVE(state
));
547 assert(DNS_TRANSACTION_IS_LIVE(q
->state
));
549 /* Note that this call might invalidate the query. Callers should hence not attempt to access the
550 * query or transaction after calling this function. */
559 static int on_query_timeout(sd_event_source
*s
, usec_t usec
, void *userdata
) {
560 DnsQuery
*q
= userdata
;
565 dns_query_complete(q
, DNS_TRANSACTION_TIMEOUT
);
569 static int dns_query_add_candidate(DnsQuery
*q
, DnsScope
*s
) {
570 _cleanup_(dns_query_candidate_unrefp
) DnsQueryCandidate
*c
= NULL
;
576 r
= dns_query_candidate_new(&c
, q
, s
);
580 /* If this a single-label domain on DNS, we might append a suitable search domain first. */
581 if (!FLAGS_SET(q
->flags
, SD_RESOLVED_NO_SEARCH
) &&
582 dns_scope_name_wants_search_domain(s
, dns_question_first_name(q
->question_idna
))) {
583 /* OK, we want a search domain now. Let's find one for this scope */
585 r
= dns_query_candidate_next_search_domain(c
);
590 r
= dns_query_candidate_setup_transactions(c
);
598 static int dns_query_synthesize_reply(DnsQuery
*q
, DnsTransactionState
*state
) {
599 _cleanup_(dns_answer_unrefp
) DnsAnswer
*answer
= NULL
;
605 /* Tries to synthesize localhost RR replies (and others) where appropriate. Note that this is done *after* the
606 * the normal lookup finished. The data from the network hence takes precedence over the data we
607 * synthesize. (But note that many scopes refuse to resolve certain domain names) */
610 DNS_TRANSACTION_RCODE_FAILURE
,
611 DNS_TRANSACTION_NO_SERVERS
,
612 DNS_TRANSACTION_TIMEOUT
,
613 DNS_TRANSACTION_ATTEMPTS_MAX_REACHED
,
614 DNS_TRANSACTION_NETWORK_DOWN
,
615 DNS_TRANSACTION_NOT_FOUND
))
618 if (FLAGS_SET(q
->flags
, SD_RESOLVED_NO_SYNTHESIZE
))
621 r
= dns_synthesize_answer(
623 q
->question_bypass
? q
->question_bypass
->question
: q
->question_utf8
,
627 /* If we get ENXIO this tells us to generate NXDOMAIN unconditionally. */
629 dns_query_reset_answer(q
);
630 q
->answer_rcode
= DNS_RCODE_NXDOMAIN
;
631 q
->answer_protocol
= dns_synthesize_protocol(q
->flags
);
632 q
->answer_family
= dns_synthesize_family(q
->flags
);
633 q
->answer_authenticated
= true;
634 *state
= DNS_TRANSACTION_RCODE_FAILURE
;
641 dns_query_reset_answer(q
);
643 q
->answer
= TAKE_PTR(answer
);
644 q
->answer_rcode
= DNS_RCODE_SUCCESS
;
645 q
->answer_protocol
= dns_synthesize_protocol(q
->flags
);
646 q
->answer_family
= dns_synthesize_family(q
->flags
);
647 q
->answer_authenticated
= true;
649 *state
= DNS_TRANSACTION_SUCCESS
;
654 static int dns_query_try_etc_hosts(DnsQuery
*q
) {
655 _cleanup_(dns_answer_unrefp
) DnsAnswer
*answer
= NULL
;
660 /* Looks in /etc/hosts for matching entries. Note that this is done *before* the normal lookup is
661 * done. The data from /etc/hosts hence takes precedence over the network. */
663 if (FLAGS_SET(q
->flags
, SD_RESOLVED_NO_SYNTHESIZE
))
666 r
= manager_etc_hosts_lookup(
668 q
->question_bypass
? q
->question_bypass
->question
: q
->question_utf8
,
673 dns_query_reset_answer(q
);
675 q
->answer
= TAKE_PTR(answer
);
676 q
->answer_rcode
= DNS_RCODE_SUCCESS
;
677 q
->answer_protocol
= dns_synthesize_protocol(q
->flags
);
678 q
->answer_family
= dns_synthesize_family(q
->flags
);
679 q
->answer_authenticated
= true;
684 int dns_query_go(DnsQuery
*q
) {
685 DnsScopeMatch found
= DNS_SCOPE_NO
;
686 DnsScope
*s
, *first
= NULL
;
687 DnsQueryCandidate
*c
;
692 if (q
->state
!= DNS_TRANSACTION_NULL
)
695 r
= dns_query_try_etc_hosts(q
);
699 dns_query_complete(q
, DNS_TRANSACTION_SUCCESS
);
703 LIST_FOREACH(scopes
, s
, q
->manager
->dns_scopes
) {
707 name
= dns_question_first_name(dns_query_question_for_protocol(q
, s
->protocol
));
711 match
= dns_scope_good_domain(s
, q
->ifindex
, q
->flags
, name
);
713 log_debug("Couldn't check if '%s' matches against scope, ignoring.", name
);
717 if (match
> found
) { /* Does this match better? If so, remember how well it matched, and the first one
718 * that matches this well */
724 if (found
== DNS_SCOPE_NO
) {
725 DnsTransactionState state
= DNS_TRANSACTION_NO_SERVERS
;
727 r
= dns_query_synthesize_reply(q
, &state
);
731 dns_query_complete(q
, state
);
735 r
= dns_query_add_candidate(q
, first
);
739 LIST_FOREACH(scopes
, s
, first
->scopes_next
) {
743 name
= dns_question_first_name(dns_query_question_for_protocol(q
, s
->protocol
));
747 match
= dns_scope_good_domain(s
, q
->ifindex
, q
->flags
, name
);
749 log_debug("Couldn't check if '%s' matches against scope, ignoring.", name
);
756 r
= dns_query_add_candidate(q
, s
);
761 dns_query_reset_answer(q
);
763 r
= sd_event_add_time_relative(
765 &q
->timeout_event_source
,
766 clock_boottime_or_monotonic(),
767 SD_RESOLVED_QUERY_TIMEOUT_USEC
,
768 0, on_query_timeout
, q
);
772 (void) sd_event_source_set_description(q
->timeout_event_source
, "query-timeout");
774 q
->state
= DNS_TRANSACTION_PENDING
;
777 /* Start the transactions */
778 LIST_FOREACH(candidates_by_query
, c
, q
->candidates
) {
779 r
= dns_query_candidate_go(c
);
796 static void dns_query_accept(DnsQuery
*q
, DnsQueryCandidate
*c
) {
797 DnsTransactionState state
= DNS_TRANSACTION_NO_SERVERS
;
798 bool has_authenticated
= false, has_non_authenticated
= false;
799 DnssecResult dnssec_result_authenticated
= _DNSSEC_RESULT_INVALID
, dnssec_result_non_authenticated
= _DNSSEC_RESULT_INVALID
;
806 r
= dns_query_synthesize_reply(q
, &state
);
810 dns_query_complete(q
, state
);
814 if (c
->error_code
!= 0) {
815 /* If the candidate had an error condition of its own, start with that. */
816 state
= DNS_TRANSACTION_ERRNO
;
817 q
->answer
= dns_answer_unref(q
->answer
);
819 q
->answer_dnssec_result
= _DNSSEC_RESULT_INVALID
;
820 q
->answer_authenticated
= false;
821 q
->answer_errno
= c
->error_code
;
822 q
->answer_full_packet
= dns_packet_unref(q
->answer_full_packet
);
825 SET_FOREACH(t
, c
->transactions
) {
829 case DNS_TRANSACTION_SUCCESS
: {
830 /* We found a successful reply, merge it into the answer */
832 if (state
== DNS_TRANSACTION_SUCCESS
) {
833 r
= dns_answer_extend(&q
->answer
, t
->answer
);
837 /* Override non-successful previous answers */
838 dns_answer_unref(q
->answer
);
839 q
->answer
= dns_answer_ref(t
->answer
);
842 q
->answer_rcode
= t
->answer_rcode
;
845 dns_packet_unref(q
->answer_full_packet
);
846 q
->answer_full_packet
= dns_packet_ref(t
->received
);
848 if (t
->answer_authenticated
) {
849 has_authenticated
= true;
850 dnssec_result_authenticated
= t
->answer_dnssec_result
;
852 has_non_authenticated
= true;
853 dnssec_result_non_authenticated
= t
->answer_dnssec_result
;
856 state
= DNS_TRANSACTION_SUCCESS
;
860 case DNS_TRANSACTION_NULL
:
861 case DNS_TRANSACTION_PENDING
:
862 case DNS_TRANSACTION_VALIDATING
:
863 case DNS_TRANSACTION_ABORTED
:
864 /* Ignore transactions that didn't complete */
868 /* Any kind of failure? Store the data away, if there's nothing stored yet. */
869 if (state
== DNS_TRANSACTION_SUCCESS
)
872 /* If there's already an authenticated negative reply stored, then prefer that over any unauthenticated one */
873 if (q
->answer_authenticated
&& !t
->answer_authenticated
)
876 dns_answer_unref(q
->answer
);
877 q
->answer
= dns_answer_ref(t
->answer
);
878 q
->answer_rcode
= t
->answer_rcode
;
879 q
->answer_dnssec_result
= t
->answer_dnssec_result
;
880 q
->answer_authenticated
= t
->answer_authenticated
;
881 q
->answer_errno
= t
->answer_errno
;
882 dns_packet_unref(q
->answer_full_packet
);
883 q
->answer_full_packet
= dns_packet_ref(t
->received
);
890 if (state
== DNS_TRANSACTION_SUCCESS
) {
891 q
->answer_authenticated
= has_authenticated
&& !has_non_authenticated
;
892 q
->answer_dnssec_result
= q
->answer_authenticated
? dnssec_result_authenticated
: dnssec_result_non_authenticated
;
895 q
->answer_protocol
= c
->scope
->protocol
;
896 q
->answer_family
= c
->scope
->family
;
898 dns_search_domain_unref(q
->answer_search_domain
);
899 q
->answer_search_domain
= dns_search_domain_ref(c
->search_domain
);
901 r
= dns_query_synthesize_reply(q
, &state
);
905 dns_query_complete(q
, state
);
909 q
->answer_errno
= -r
;
910 dns_query_complete(q
, DNS_TRANSACTION_ERRNO
);
913 void dns_query_ready(DnsQuery
*q
) {
915 DnsQueryCandidate
*bad
= NULL
, *c
;
916 bool pending
= false;
919 assert(DNS_TRANSACTION_IS_LIVE(q
->state
));
921 /* Note that this call might invalidate the query. Callers
922 * should hence not attempt to access the query or transaction
923 * after calling this function, unless the block_ready
924 * counter was explicitly bumped before doing so. */
926 if (q
->block_ready
> 0)
929 LIST_FOREACH(candidates_by_query
, c
, q
->candidates
) {
930 DnsTransactionState state
;
932 state
= dns_query_candidate_state(c
);
935 case DNS_TRANSACTION_SUCCESS
:
936 /* One of the candidates is successful,
937 * let's use it, and copy its data out */
938 dns_query_accept(q
, c
);
941 case DNS_TRANSACTION_NULL
:
942 case DNS_TRANSACTION_PENDING
:
943 case DNS_TRANSACTION_VALIDATING
:
944 /* One of the candidates is still going on,
945 * let's maybe wait for it */
950 /* Any kind of failure */
959 dns_query_accept(q
, bad
);
962 static int dns_query_cname_redirect(DnsQuery
*q
, const DnsResourceRecord
*cname
) {
963 _cleanup_(dns_question_unrefp
) DnsQuestion
*nq_idna
= NULL
, *nq_utf8
= NULL
;
968 q
->n_cname_redirects
++;
969 if (q
->n_cname_redirects
> CNAME_MAX
)
972 r
= dns_question_cname_redirect(q
->question_idna
, cname
, &nq_idna
);
976 log_debug("Following CNAME/DNAME %s → %s.", dns_question_first_name(q
->question_idna
), dns_question_first_name(nq_idna
));
978 k
= dns_question_is_equal(q
->question_idna
, q
->question_utf8
);
982 /* Same question? Shortcut new question generation */
983 nq_utf8
= dns_question_ref(nq_idna
);
986 k
= dns_question_cname_redirect(q
->question_utf8
, cname
, &nq_utf8
);
990 log_debug("Following UTF8 CNAME/DNAME %s → %s.", dns_question_first_name(q
->question_utf8
), dns_question_first_name(nq_utf8
));
993 if (r
== 0 && k
== 0) /* No actual cname happened? */
996 if (q
->answer_protocol
== DNS_PROTOCOL_DNS
)
997 /* Don't permit CNAME redirects from unicast DNS to LLMNR or MulticastDNS, so that global resources
998 * cannot invade the local namespace. The opposite way we permit: local names may redirect to global
1000 q
->flags
&= ~(SD_RESOLVED_LLMNR
|SD_RESOLVED_MDNS
); /* mask away the local protocols */
1002 /* Turn off searching for the new name */
1003 q
->flags
|= SD_RESOLVED_NO_SEARCH
;
1005 dns_question_unref(q
->question_idna
);
1006 q
->question_idna
= TAKE_PTR(nq_idna
);
1008 dns_question_unref(q
->question_utf8
);
1009 q
->question_utf8
= TAKE_PTR(nq_utf8
);
1011 dns_query_unref_candidates(q
);
1012 dns_query_reset_answer(q
);
1014 q
->state
= DNS_TRANSACTION_NULL
;
1019 int dns_query_process_cname(DnsQuery
*q
) {
1020 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*cname
= NULL
;
1021 DnsQuestion
*question
;
1022 DnsResourceRecord
*rr
;
1027 if (!IN_SET(q
->state
, DNS_TRANSACTION_SUCCESS
, DNS_TRANSACTION_NULL
))
1028 return DNS_QUERY_NOMATCH
;
1030 question
= dns_query_question_for_protocol(q
, q
->answer_protocol
);
1032 DNS_ANSWER_FOREACH(rr
, q
->answer
) {
1033 r
= dns_question_matches_rr(question
, rr
, DNS_SEARCH_DOMAIN_NAME(q
->answer_search_domain
));
1037 return DNS_QUERY_MATCH
; /* The answer matches directly, no need to follow cnames */
1039 r
= dns_question_matches_cname_or_dname(question
, rr
, DNS_SEARCH_DOMAIN_NAME(q
->answer_search_domain
));
1042 if (r
> 0 && !cname
)
1043 cname
= dns_resource_record_ref(rr
);
1047 return DNS_QUERY_NOMATCH
; /* No match and no cname to follow */
1049 if (q
->flags
& SD_RESOLVED_NO_CNAME
)
1052 if (!q
->answer_authenticated
)
1053 q
->previous_redirect_unauthenticated
= true;
1055 /* OK, let's actually follow the CNAME */
1056 r
= dns_query_cname_redirect(q
, cname
);
1060 /* Let's see if the answer can already answer the new
1061 * redirected question */
1062 r
= dns_query_process_cname(q
);
1063 if (r
!= DNS_QUERY_NOMATCH
)
1066 /* OK, it cannot, let's begin with the new query */
1067 r
= dns_query_go(q
);
1071 return DNS_QUERY_RESTARTED
; /* We restarted the query for a new cname */
1074 DnsQuestion
* dns_query_question_for_protocol(DnsQuery
*q
, DnsProtocol protocol
) {
1077 if (q
->question_bypass
)
1078 return q
->question_bypass
->question
;
1082 case DNS_PROTOCOL_DNS
:
1083 return q
->question_idna
;
1085 case DNS_PROTOCOL_MDNS
:
1086 case DNS_PROTOCOL_LLMNR
:
1087 return q
->question_utf8
;
1094 const char *dns_query_string(DnsQuery
*q
) {
1098 /* Returns a somewhat useful human-readable lookup key string for this query */
1100 if (q
->question_bypass
)
1101 return dns_question_first_name(q
->question_bypass
->question
);
1103 if (q
->request_address_string
)
1104 return q
->request_address_string
;
1106 if (q
->request_address_valid
) {
1107 r
= in_addr_to_string(q
->request_family
, &q
->request_address
, &q
->request_address_string
);
1109 return q
->request_address_string
;
1112 name
= dns_question_first_name(q
->question_utf8
);
1116 return dns_question_first_name(q
->question_idna
);
1119 bool dns_query_fully_authenticated(DnsQuery
*q
) {
1122 return q
->answer_authenticated
&& !q
->previous_redirect_unauthenticated
;