1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2014 Lennart Poettering
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
21 #include "alloc-util.h"
22 #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"
32 #define QUERIES_MAX 2048
33 #define AUXILIARY_QUERIES_MAX 64
35 static int dns_query_candidate_new(DnsQueryCandidate
**ret
, DnsQuery
*q
, DnsScope
*s
) {
42 c
= new0(DnsQueryCandidate
, 1);
49 LIST_PREPEND(candidates_by_query
, q
->candidates
, c
);
50 LIST_PREPEND(candidates_by_scope
, s
->query_candidates
, c
);
56 static void dns_query_candidate_stop(DnsQueryCandidate
*c
) {
61 while ((t
= set_steal_first(c
->transactions
))) {
62 set_remove(t
->notify_query_candidates
, c
);
63 set_remove(t
->notify_query_candidates_done
, c
);
64 dns_transaction_gc(t
);
68 DnsQueryCandidate
* dns_query_candidate_free(DnsQueryCandidate
*c
) {
73 dns_query_candidate_stop(c
);
75 set_free(c
->transactions
);
76 dns_search_domain_unref(c
->search_domain
);
79 LIST_REMOVE(candidates_by_query
, c
->query
->candidates
, c
);
82 LIST_REMOVE(candidates_by_scope
, c
->scope
->query_candidates
, c
);
87 static int dns_query_candidate_next_search_domain(DnsQueryCandidate
*c
) {
88 DnsSearchDomain
*next
= NULL
;
92 if (c
->search_domain
&& c
->search_domain
->linked
)
93 next
= c
->search_domain
->domains_next
;
95 next
= dns_scope_get_search_domains(c
->scope
);
98 if (!next
) /* We hit the end of the list */
101 if (!next
->route_only
)
104 /* Skip over route-only domains */
105 next
= next
->domains_next
;
108 dns_search_domain_unref(c
->search_domain
);
109 c
->search_domain
= dns_search_domain_ref(next
);
114 static int dns_query_candidate_add_transaction(DnsQueryCandidate
*c
, DnsResourceKey
*key
) {
121 t
= dns_scope_find_transaction(c
->scope
, key
, true);
123 r
= dns_transaction_new(&t
, c
->scope
, key
);
127 if (set_contains(c
->transactions
, t
))
131 r
= set_ensure_allocated(&c
->transactions
, NULL
);
135 r
= set_ensure_allocated(&t
->notify_query_candidates
, NULL
);
139 r
= set_ensure_allocated(&t
->notify_query_candidates_done
, NULL
);
143 r
= set_put(t
->notify_query_candidates
, c
);
147 r
= set_put(c
->transactions
, t
);
149 (void) set_remove(t
->notify_query_candidates
, c
);
153 t
->clamp_ttl
= c
->query
->clamp_ttl
;
157 dns_transaction_gc(t
);
161 static int dns_query_candidate_go(DnsQueryCandidate
*c
) {
169 /* Start the transactions that are not started yet */
170 SET_FOREACH(t
, c
->transactions
, i
) {
171 if (t
->state
!= DNS_TRANSACTION_NULL
)
174 r
= dns_transaction_go(t
);
181 /* If there was nothing to start, then let's proceed immediately */
183 dns_query_candidate_notify(c
);
188 static DnsTransactionState
dns_query_candidate_state(DnsQueryCandidate
*c
) {
189 DnsTransactionState state
= DNS_TRANSACTION_NO_SERVERS
;
195 if (c
->error_code
!= 0)
196 return DNS_TRANSACTION_ERRNO
;
198 SET_FOREACH(t
, c
->transactions
, i
) {
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. */
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
;
218 case DNS_TRANSACTION_SUCCESS
:
223 if (state
!= DNS_TRANSACTION_SUCCESS
)
233 static bool dns_query_candidate_is_routable(DnsQueryCandidate
*c
, uint16_t type
) {
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. */
242 if (!c
->query
->suppress_unroutable_family
)
245 if (c
->scope
->protocol
!= DNS_PROTOCOL_DNS
)
248 family
= dns_type_to_af(type
);
253 return link_relevant(c
->scope
->link
, family
, false);
255 return manager_routable(c
->scope
->manager
, family
);
258 static int dns_query_candidate_setup_transactions(DnsQueryCandidate
*c
) {
259 DnsQuestion
*question
;
265 dns_query_candidate_stop(c
);
267 question
= dns_query_question_for_protocol(c
->query
, c
->scope
->protocol
);
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
;
274 if (!dns_query_candidate_is_routable(c
, key
->type
))
277 if (c
->search_domain
) {
278 r
= dns_resource_key_new_append_suffix(&new_key
, key
, c
->search_domain
->name
);
286 if (!dns_scope_good_key(c
->scope
, qkey
))
289 r
= dns_query_candidate_add_transaction(c
, qkey
);
299 dns_query_candidate_stop(c
);
303 void dns_query_candidate_notify(DnsQueryCandidate
*c
) {
304 DnsTransactionState state
;
309 state
= dns_query_candidate_state(c
);
311 if (DNS_TRANSACTION_IS_LIVE(state
))
314 if (state
!= DNS_TRANSACTION_SUCCESS
&& c
->search_domain
) {
316 r
= dns_query_candidate_next_search_domain(c
);
321 /* OK, there's another search domain to try, let's do so. */
323 r
= dns_query_candidate_setup_transactions(c
);
328 /* New transactions where queued. Start them and wait */
330 r
= dns_query_candidate_go(c
);
340 dns_query_ready(c
->query
);
344 log_warning_errno(r
, "Failed to follow search domains: %m");
346 dns_query_ready(c
->query
);
349 static void dns_query_stop(DnsQuery
*q
) {
350 DnsQueryCandidate
*c
;
354 q
->timeout_event_source
= sd_event_source_unref(q
->timeout_event_source
);
356 LIST_FOREACH(candidates_by_query
, c
, q
->candidates
)
357 dns_query_candidate_stop(c
);
360 static void dns_query_free_candidates(DnsQuery
*q
) {
363 while (q
->candidates
)
364 dns_query_candidate_free(q
->candidates
);
367 static void dns_query_reset_answer(DnsQuery
*q
) {
370 q
->answer
= dns_answer_unref(q
->answer
);
372 q
->answer_dnssec_result
= _DNSSEC_RESULT_INVALID
;
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
);
380 DnsQuery
*dns_query_free(DnsQuery
*q
) {
384 while (q
->auxiliary_queries
)
385 dns_query_free(q
->auxiliary_queries
);
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
);
393 dns_query_free_candidates(q
);
395 dns_question_unref(q
->question_idna
);
396 dns_question_unref(q
->question_utf8
);
398 dns_query_reset_answer(q
);
400 sd_bus_message_unref(q
->request
);
401 sd_bus_track_unref(q
->bus_track
);
403 dns_packet_unref(q
->request_dns_packet
);
404 dns_packet_unref(q
->reply_dns_packet
);
406 if (q
->request_dns_stream
) {
407 /* Detach the stream from our query, in case something else keeps a reference to it. */
408 q
->request_dns_stream
->complete
= NULL
;
409 q
->request_dns_stream
->on_packet
= NULL
;
410 q
->request_dns_stream
->query
= NULL
;
411 dns_stream_unref(q
->request_dns_stream
);
414 free(q
->request_address_string
);
417 LIST_REMOVE(queries
, q
->manager
->dns_queries
, q
);
418 q
->manager
->n_dns_queries
--;
427 DnsQuestion
*question_utf8
,
428 DnsQuestion
*question_idna
,
432 _cleanup_(dns_query_freep
) DnsQuery
*q
= NULL
;
436 char key_str
[DNS_RESOURCE_KEY_STRING_MAX
];
440 if (dns_question_size(question_utf8
) > 0) {
441 r
= dns_question_is_valid_for_query(question_utf8
);
450 /* If the IDNA and UTF8 questions are the same, merge their references */
451 r
= dns_question_is_equal(question_idna
, question_utf8
);
455 question_idna
= question_utf8
;
457 if (dns_question_size(question_idna
) > 0) {
458 r
= dns_question_is_valid_for_query(question_idna
);
468 if (!good
) /* don't allow empty queries */
471 if (m
->n_dns_queries
>= QUERIES_MAX
)
474 q
= new0(DnsQuery
, 1);
478 q
->question_utf8
= dns_question_ref(question_utf8
);
479 q
->question_idna
= dns_question_ref(question_idna
);
480 q
->ifindex
= ifindex
;
482 q
->answer_dnssec_result
= _DNSSEC_RESULT_INVALID
;
483 q
->answer_protocol
= _DNS_PROTOCOL_INVALID
;
484 q
->answer_family
= AF_UNSPEC
;
486 /* First dump UTF8 question */
487 DNS_QUESTION_FOREACH(key
, question_utf8
)
488 log_debug("Looking up RR for %s.",
489 dns_resource_key_to_string(key
, key_str
, sizeof key_str
));
491 /* And then dump the IDNA question, but only what hasn't been dumped already through the UTF8 question. */
492 DNS_QUESTION_FOREACH(key
, question_idna
) {
493 r
= dns_question_contains(question_utf8
, key
);
499 log_debug("Looking up IDNA RR for %s.",
500 dns_resource_key_to_string(key
, key_str
, sizeof key_str
));
503 LIST_PREPEND(queries
, m
->dns_queries
, q
);
514 int dns_query_make_auxiliary(DnsQuery
*q
, DnsQuery
*auxiliary_for
) {
516 assert(auxiliary_for
);
518 /* Ensure 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
);
523 /* Ensure that the unit we shall be made auxiliary for isn't
524 * auxiliary itself */
525 assert(!auxiliary_for
->auxiliary_for
);
527 if (auxiliary_for
->n_auxiliary_queries
>= AUXILIARY_QUERIES_MAX
)
530 LIST_PREPEND(auxiliary_queries
, auxiliary_for
->auxiliary_queries
, q
);
531 q
->auxiliary_for
= auxiliary_for
;
533 auxiliary_for
->n_auxiliary_queries
++;
537 static void dns_query_complete(DnsQuery
*q
, DnsTransactionState state
) {
539 assert(!DNS_TRANSACTION_IS_LIVE(state
));
540 assert(DNS_TRANSACTION_IS_LIVE(q
->state
));
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. */
553 static int on_query_timeout(sd_event_source
*s
, usec_t usec
, void *userdata
) {
554 DnsQuery
*q
= userdata
;
559 dns_query_complete(q
, DNS_TRANSACTION_TIMEOUT
);
563 static int dns_query_add_candidate(DnsQuery
*q
, DnsScope
*s
) {
564 DnsQueryCandidate
*c
;
570 r
= dns_query_candidate_new(&c
, q
, s
);
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
));
580 /* OK, we need a search domain now. Let's find one for this scope */
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. */
588 r
= dns_query_candidate_setup_transactions(c
);
595 dns_query_candidate_free(c
);
599 static int dns_query_synthesize_reply(DnsQuery
*q
, DnsTransactionState
*state
) {
600 _cleanup_(dns_answer_unrefp
) DnsAnswer
*answer
= NULL
;
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) */
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
))
619 r
= dns_synthesize_answer(
625 /* If we get ENXIO this tells us to generate NXDOMAIN unconditionally. */
627 dns_query_reset_answer(q
);
628 q
->answer_rcode
= DNS_RCODE_NXDOMAIN
;
629 q
->answer_protocol
= dns_synthesize_protocol(q
->flags
);
630 q
->answer_family
= dns_synthesize_family(q
->flags
);
631 q
->answer_authenticated
= true;
632 *state
= DNS_TRANSACTION_RCODE_FAILURE
;
639 dns_query_reset_answer(q
);
643 q
->answer_rcode
= DNS_RCODE_SUCCESS
;
644 q
->answer_protocol
= dns_synthesize_protocol(q
->flags
);
645 q
->answer_family
= dns_synthesize_family(q
->flags
);
646 q
->answer_authenticated
= true;
648 *state
= DNS_TRANSACTION_SUCCESS
;
653 static int dns_query_try_etc_hosts(DnsQuery
*q
) {
654 _cleanup_(dns_answer_unrefp
) DnsAnswer
*answer
= NULL
;
659 /* Looks in /etc/hosts for matching entries. Note that this is done *before* the normal lookup is done. The
660 * data from /etc/hosts hence takes precedence over the network. */
662 r
= manager_etc_hosts_lookup(
669 dns_query_reset_answer(q
);
673 q
->answer_rcode
= DNS_RCODE_SUCCESS
;
674 q
->answer_protocol
= dns_synthesize_protocol(q
->flags
);
675 q
->answer_family
= dns_synthesize_family(q
->flags
);
676 q
->answer_authenticated
= true;
681 int dns_query_go(DnsQuery
*q
) {
682 DnsScopeMatch found
= DNS_SCOPE_NO
;
683 DnsScope
*s
, *first
= NULL
;
684 DnsQueryCandidate
*c
;
689 if (q
->state
!= DNS_TRANSACTION_NULL
)
692 r
= dns_query_try_etc_hosts(q
);
696 dns_query_complete(q
, DNS_TRANSACTION_SUCCESS
);
700 LIST_FOREACH(scopes
, s
, q
->manager
->dns_scopes
) {
704 name
= dns_question_first_name(dns_query_question_for_protocol(q
, s
->protocol
));
708 match
= dns_scope_good_domain(s
, q
->ifindex
, q
->flags
, name
);
712 if (match
== DNS_SCOPE_NO
)
717 if (match
== DNS_SCOPE_YES
) {
721 assert(match
== DNS_SCOPE_MAYBE
);
728 if (found
== DNS_SCOPE_NO
) {
729 DnsTransactionState state
= DNS_TRANSACTION_NO_SERVERS
;
731 r
= dns_query_synthesize_reply(q
, &state
);
735 dns_query_complete(q
, state
);
739 r
= dns_query_add_candidate(q
, first
);
743 LIST_FOREACH(scopes
, s
, first
->scopes_next
) {
747 name
= dns_question_first_name(dns_query_question_for_protocol(q
, s
->protocol
));
751 match
= dns_scope_good_domain(s
, q
->ifindex
, q
->flags
, name
);
758 r
= dns_query_add_candidate(q
, s
);
763 dns_query_reset_answer(q
);
765 r
= sd_event_add_time(
767 &q
->timeout_event_source
,
768 clock_boottime_or_monotonic(),
769 now(clock_boottime_or_monotonic()) + SD_RESOLVED_QUERY_TIMEOUT_USEC
,
770 0, on_query_timeout
, q
);
774 (void) sd_event_source_set_description(q
->timeout_event_source
, "query-timeout");
776 q
->state
= DNS_TRANSACTION_PENDING
;
779 /* Start the transactions */
780 LIST_FOREACH(candidates_by_query
, c
, q
->candidates
) {
781 r
= dns_query_candidate_go(c
);
798 static void dns_query_accept(DnsQuery
*q
, DnsQueryCandidate
*c
) {
799 DnsTransactionState state
= DNS_TRANSACTION_NO_SERVERS
;
800 bool has_authenticated
= false, has_non_authenticated
= false;
801 DnssecResult dnssec_result_authenticated
= _DNSSEC_RESULT_INVALID
, dnssec_result_non_authenticated
= _DNSSEC_RESULT_INVALID
;
809 r
= dns_query_synthesize_reply(q
, &state
);
813 dns_query_complete(q
, state
);
817 if (c
->error_code
!= 0) {
818 /* If the candidate had an error condition of its own, start with that. */
819 state
= DNS_TRANSACTION_ERRNO
;
820 q
->answer
= dns_answer_unref(q
->answer
);
822 q
->answer_dnssec_result
= _DNSSEC_RESULT_INVALID
;
823 q
->answer_authenticated
= false;
824 q
->answer_errno
= c
->error_code
;
827 SET_FOREACH(t
, c
->transactions
, i
) {
831 case DNS_TRANSACTION_SUCCESS
: {
832 /* We found a successfully reply, merge it into the answer */
833 r
= dns_answer_extend(&q
->answer
, t
->answer
);
837 q
->answer_rcode
= t
->answer_rcode
;
840 if (t
->answer_authenticated
) {
841 has_authenticated
= true;
842 dnssec_result_authenticated
= t
->answer_dnssec_result
;
844 has_non_authenticated
= true;
845 dnssec_result_non_authenticated
= t
->answer_dnssec_result
;
848 state
= DNS_TRANSACTION_SUCCESS
;
852 case DNS_TRANSACTION_NULL
:
853 case DNS_TRANSACTION_PENDING
:
854 case DNS_TRANSACTION_VALIDATING
:
855 case DNS_TRANSACTION_ABORTED
:
856 /* Ignore transactions that didn't complete */
860 /* Any kind of failure? Store the data away, if there's nothing stored yet. */
861 if (state
== DNS_TRANSACTION_SUCCESS
)
864 /* If there's already an authenticated negative reply stored, then prefer that over any unauthenticated one */
865 if (q
->answer_authenticated
&& !t
->answer_authenticated
)
868 q
->answer
= dns_answer_unref(q
->answer
);
869 q
->answer_rcode
= t
->answer_rcode
;
870 q
->answer_dnssec_result
= t
->answer_dnssec_result
;
871 q
->answer_authenticated
= t
->answer_authenticated
;
872 q
->answer_errno
= t
->answer_errno
;
879 if (state
== DNS_TRANSACTION_SUCCESS
) {
880 q
->answer_authenticated
= has_authenticated
&& !has_non_authenticated
;
881 q
->answer_dnssec_result
= q
->answer_authenticated
? dnssec_result_authenticated
: dnssec_result_non_authenticated
;
884 q
->answer_protocol
= c
->scope
->protocol
;
885 q
->answer_family
= c
->scope
->family
;
887 dns_search_domain_unref(q
->answer_search_domain
);
888 q
->answer_search_domain
= dns_search_domain_ref(c
->search_domain
);
890 r
= dns_query_synthesize_reply(q
, &state
);
894 dns_query_complete(q
, state
);
898 q
->answer_errno
= -r
;
899 dns_query_complete(q
, DNS_TRANSACTION_ERRNO
);
902 void dns_query_ready(DnsQuery
*q
) {
904 DnsQueryCandidate
*bad
= NULL
, *c
;
905 bool pending
= false;
908 assert(DNS_TRANSACTION_IS_LIVE(q
->state
));
910 /* Note that this call might invalidate the query. Callers
911 * should hence not attempt to access the query or transaction
912 * after calling this function, unless the block_ready
913 * counter was explicitly bumped before doing so. */
915 if (q
->block_ready
> 0)
918 LIST_FOREACH(candidates_by_query
, c
, q
->candidates
) {
919 DnsTransactionState state
;
921 state
= dns_query_candidate_state(c
);
924 case DNS_TRANSACTION_SUCCESS
:
925 /* One of the candidates is successful,
926 * let's use it, and copy its data out */
927 dns_query_accept(q
, c
);
930 case DNS_TRANSACTION_NULL
:
931 case DNS_TRANSACTION_PENDING
:
932 case DNS_TRANSACTION_VALIDATING
:
933 /* One of the candidates is still going on,
934 * let's maybe wait for it */
939 /* Any kind of failure */
948 dns_query_accept(q
, bad
);
951 static int dns_query_cname_redirect(DnsQuery
*q
, const DnsResourceRecord
*cname
) {
952 _cleanup_(dns_question_unrefp
) DnsQuestion
*nq_idna
= NULL
, *nq_utf8
= NULL
;
957 q
->n_cname_redirects
++;
958 if (q
->n_cname_redirects
> CNAME_MAX
)
961 r
= dns_question_cname_redirect(q
->question_idna
, cname
, &nq_idna
);
965 log_debug("Following CNAME/DNAME %s → %s.", dns_question_first_name(q
->question_idna
), dns_question_first_name(nq_idna
));
967 k
= dns_question_is_equal(q
->question_idna
, q
->question_utf8
);
971 /* Same question? Shortcut new question generation */
972 nq_utf8
= dns_question_ref(nq_idna
);
975 k
= dns_question_cname_redirect(q
->question_utf8
, cname
, &nq_utf8
);
979 log_debug("Following UTF8 CNAME/DNAME %s → %s.", dns_question_first_name(q
->question_utf8
), dns_question_first_name(nq_utf8
));
982 if (r
== 0 && k
== 0) /* No actual cname happened? */
985 if (q
->answer_protocol
== DNS_PROTOCOL_DNS
) {
986 /* Don't permit CNAME redirects from unicast DNS to LLMNR or MulticastDNS, so that global resources
987 * cannot invade the local namespace. The opposite way we permit: local names may redirect to global
990 q
->flags
&= ~(SD_RESOLVED_LLMNR
|SD_RESOLVED_MDNS
); /* mask away the local protocols */
993 /* Turn off searching for the new name */
994 q
->flags
|= SD_RESOLVED_NO_SEARCH
;
996 dns_question_unref(q
->question_idna
);
997 q
->question_idna
= nq_idna
;
1000 dns_question_unref(q
->question_utf8
);
1001 q
->question_utf8
= nq_utf8
;
1004 dns_query_free_candidates(q
);
1005 dns_query_reset_answer(q
);
1007 q
->state
= DNS_TRANSACTION_NULL
;
1012 int dns_query_process_cname(DnsQuery
*q
) {
1013 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*cname
= NULL
;
1014 DnsQuestion
*question
;
1015 DnsResourceRecord
*rr
;
1020 if (!IN_SET(q
->state
, DNS_TRANSACTION_SUCCESS
, DNS_TRANSACTION_NULL
))
1021 return DNS_QUERY_NOMATCH
;
1023 question
= dns_query_question_for_protocol(q
, q
->answer_protocol
);
1025 DNS_ANSWER_FOREACH(rr
, q
->answer
) {
1026 r
= dns_question_matches_rr(question
, rr
, DNS_SEARCH_DOMAIN_NAME(q
->answer_search_domain
));
1030 return DNS_QUERY_MATCH
; /* The answer matches directly, no need to follow cnames */
1032 r
= dns_question_matches_cname_or_dname(question
, rr
, DNS_SEARCH_DOMAIN_NAME(q
->answer_search_domain
));
1035 if (r
> 0 && !cname
)
1036 cname
= dns_resource_record_ref(rr
);
1040 return DNS_QUERY_NOMATCH
; /* No match and no cname to follow */
1042 if (q
->flags
& SD_RESOLVED_NO_CNAME
)
1045 if (!q
->answer_authenticated
)
1046 q
->previous_redirect_unauthenticated
= true;
1048 /* OK, let's actually follow the CNAME */
1049 r
= dns_query_cname_redirect(q
, cname
);
1053 /* Let's see if the answer can already answer the new
1054 * redirected question */
1055 r
= dns_query_process_cname(q
);
1056 if (r
!= DNS_QUERY_NOMATCH
)
1059 /* OK, it cannot, let's begin with the new query */
1060 r
= dns_query_go(q
);
1064 return DNS_QUERY_RESTARTED
; /* We restarted the query for a new cname */
1067 static int on_bus_track(sd_bus_track
*t
, void *userdata
) {
1068 DnsQuery
*q
= userdata
;
1073 log_debug("Client of active query vanished, aborting query.");
1074 dns_query_complete(q
, DNS_TRANSACTION_ABORTED
);
1078 int dns_query_bus_track(DnsQuery
*q
, sd_bus_message
*m
) {
1084 if (!q
->bus_track
) {
1085 r
= sd_bus_track_new(sd_bus_message_get_bus(m
), &q
->bus_track
, on_bus_track
, q
);
1090 r
= sd_bus_track_add_sender(q
->bus_track
, m
);
1097 DnsQuestion
* dns_query_question_for_protocol(DnsQuery
*q
, DnsProtocol protocol
) {
1102 case DNS_PROTOCOL_DNS
:
1103 return q
->question_idna
;
1105 case DNS_PROTOCOL_MDNS
:
1106 case DNS_PROTOCOL_LLMNR
:
1107 return q
->question_utf8
;
1114 const char *dns_query_string(DnsQuery
*q
) {
1118 /* Returns a somewhat useful human-readable lookup key string for this query */
1120 if (q
->request_address_string
)
1121 return q
->request_address_string
;
1123 if (q
->request_address_valid
) {
1124 r
= in_addr_to_string(q
->request_family
, &q
->request_address
, &q
->request_address_string
);
1126 return q
->request_address_string
;
1129 name
= dns_question_first_name(q
->question_utf8
);
1133 return dns_question_first_name(q
->question_idna
);
1136 bool dns_query_fully_authenticated(DnsQuery
*q
) {
1139 return q
->answer_authenticated
&& !q
->previous_redirect_unauthenticated
;