1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2014 Lennart Poettering
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.
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.
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/>.
22 #include "alloc-util.h"
23 #include "dns-domain.h"
24 #include "hostname-util.h"
25 #include "local-addresses.h"
26 #include "resolved-dns-query.h"
28 /* How long to wait for the query in total */
29 #define QUERY_TIMEOUT_USEC (30 * USEC_PER_SEC)
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 dns_transaction_gc(t
);
67 DnsQueryCandidate
* dns_query_candidate_free(DnsQueryCandidate
*c
) {
72 dns_query_candidate_stop(c
);
74 set_free(c
->transactions
);
75 dns_search_domain_unref(c
->search_domain
);
78 LIST_REMOVE(candidates_by_query
, c
->query
->candidates
, c
);
81 LIST_REMOVE(candidates_by_scope
, c
->scope
->query_candidates
, c
);
88 static int dns_query_candidate_next_search_domain(DnsQueryCandidate
*c
) {
89 DnsSearchDomain
*next
= NULL
;
93 if (c
->search_domain
&& c
->search_domain
->linked
) {
94 next
= c
->search_domain
->domains_next
;
96 if (!next
) /* We hit the end of the list */
100 next
= dns_scope_get_search_domains(c
->scope
);
102 if (!next
) /* OK, there's nothing. */
106 dns_search_domain_unref(c
->search_domain
);
107 c
->search_domain
= dns_search_domain_ref(next
);
112 static int dns_query_candidate_add_transaction(DnsQueryCandidate
*c
, DnsResourceKey
*key
) {
119 t
= dns_scope_find_transaction(c
->scope
, key
, true);
121 r
= dns_transaction_new(&t
, c
->scope
, key
);
125 if (set_contains(c
->transactions
, t
))
129 r
= set_ensure_allocated(&c
->transactions
, NULL
);
133 r
= set_ensure_allocated(&t
->notify_query_candidates
, NULL
);
137 r
= set_put(t
->notify_query_candidates
, c
);
141 r
= set_put(c
->transactions
, t
);
143 (void) set_remove(t
->notify_query_candidates
, c
);
150 dns_transaction_gc(t
);
154 static int dns_query_candidate_go(DnsQueryCandidate
*c
) {
161 /* Start the transactions that are not started yet */
162 SET_FOREACH(t
, c
->transactions
, i
) {
163 if (t
->state
!= DNS_TRANSACTION_NULL
)
166 r
= dns_transaction_go(t
);
174 static DnsTransactionState
dns_query_candidate_state(DnsQueryCandidate
*c
) {
175 DnsTransactionState state
= DNS_TRANSACTION_NO_SERVERS
;
181 if (c
->error_code
!= 0)
182 return DNS_TRANSACTION_RESOURCES
;
184 SET_FOREACH(t
, c
->transactions
, i
) {
188 case DNS_TRANSACTION_NULL
:
189 /* If there's a NULL transaction pending, then
190 * this means not all transactions where
191 * started yet, and we were called from within
192 * the stackframe that is supposed to start
193 * remaining transactions. In this case,
194 * simply claim the candidate is pending. */
196 case DNS_TRANSACTION_PENDING
:
197 case DNS_TRANSACTION_VALIDATING
:
198 /* If there's one transaction currently in
199 * VALIDATING state, then this means there's
200 * also one in PENDING state, hence we can
201 * return PENDING immediately. */
202 return DNS_TRANSACTION_PENDING
;
204 case DNS_TRANSACTION_SUCCESS
:
209 if (state
!= DNS_TRANSACTION_SUCCESS
)
219 static int dns_query_candidate_setup_transactions(DnsQueryCandidate
*c
) {
225 dns_query_candidate_stop(c
);
227 /* Create one transaction per question key */
228 DNS_QUESTION_FOREACH(key
, c
->query
->question
) {
229 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*new_key
= NULL
;
231 if (c
->search_domain
) {
232 r
= dns_resource_key_new_append_suffix(&new_key
, key
, c
->search_domain
->name
);
237 r
= dns_query_candidate_add_transaction(c
, new_key
?: key
);
247 dns_query_candidate_stop(c
);
251 void dns_query_candidate_notify(DnsQueryCandidate
*c
) {
252 DnsTransactionState state
;
257 state
= dns_query_candidate_state(c
);
259 if (DNS_TRANSACTION_IS_LIVE(state
))
262 if (state
!= DNS_TRANSACTION_SUCCESS
&& c
->search_domain
) {
264 r
= dns_query_candidate_next_search_domain(c
);
269 /* OK, there's another search domain to try, let's do so. */
271 r
= dns_query_candidate_setup_transactions(c
);
276 /* New transactions where queued. Start them and wait */
278 r
= dns_query_candidate_go(c
);
288 dns_query_ready(c
->query
);
292 log_warning_errno(r
, "Failed to follow search domains: %m");
294 dns_query_ready(c
->query
);
297 static void dns_query_stop(DnsQuery
*q
) {
298 DnsQueryCandidate
*c
;
302 q
->timeout_event_source
= sd_event_source_unref(q
->timeout_event_source
);
304 LIST_FOREACH(candidates_by_query
, c
, q
->candidates
)
305 dns_query_candidate_stop(c
);
308 DnsQuery
*dns_query_free(DnsQuery
*q
) {
312 while (q
->auxiliary_queries
)
313 dns_query_free(q
->auxiliary_queries
);
315 if (q
->auxiliary_for
) {
316 assert(q
->auxiliary_for
->n_auxiliary_queries
> 0);
317 q
->auxiliary_for
->n_auxiliary_queries
--;
318 LIST_REMOVE(auxiliary_queries
, q
->auxiliary_for
->auxiliary_queries
, q
);
321 while (q
->candidates
)
322 dns_query_candidate_free(q
->candidates
);
324 dns_question_unref(q
->question
);
325 dns_answer_unref(q
->answer
);
326 dns_search_domain_unref(q
->answer_search_domain
);
328 sd_bus_message_unref(q
->request
);
329 sd_bus_track_unref(q
->bus_track
);
332 LIST_REMOVE(queries
, q
->manager
->dns_queries
, q
);
333 q
->manager
->n_dns_queries
--;
341 int dns_query_new(Manager
*m
, DnsQuery
**ret
, DnsQuestion
*question
, int ifindex
, uint64_t flags
) {
342 _cleanup_(dns_query_freep
) DnsQuery
*q
= NULL
;
349 r
= dns_question_is_valid_for_query(question
);
353 if (m
->n_dns_queries
>= QUERIES_MAX
)
356 q
= new0(DnsQuery
, 1);
360 q
->question
= dns_question_ref(question
);
361 q
->ifindex
= ifindex
;
363 q
->answer_family
= AF_UNSPEC
;
364 q
->answer_protocol
= _DNS_PROTOCOL_INVALID
;
366 for (i
= 0; i
< question
->n_keys
; i
++) {
367 _cleanup_free_
char *p
;
369 r
= dns_resource_key_to_string(question
->keys
[i
], &p
);
373 log_debug("Looking up RR for %s", p
);
376 LIST_PREPEND(queries
, m
->dns_queries
, q
);
387 int dns_query_make_auxiliary(DnsQuery
*q
, DnsQuery
*auxiliary_for
) {
389 assert(auxiliary_for
);
391 /* Ensure that that the query is not auxiliary yet, and
392 * nothing else is auxiliary to it either */
393 assert(!q
->auxiliary_for
);
394 assert(!q
->auxiliary_queries
);
396 /* Ensure that the unit we shall be made auxiliary for isn't
397 * auxiliary itself */
398 assert(!auxiliary_for
->auxiliary_for
);
400 if (auxiliary_for
->n_auxiliary_queries
>= AUXILIARY_QUERIES_MAX
)
403 LIST_PREPEND(auxiliary_queries
, auxiliary_for
->auxiliary_queries
, q
);
404 q
->auxiliary_for
= auxiliary_for
;
406 auxiliary_for
->n_auxiliary_queries
++;
410 static void dns_query_complete(DnsQuery
*q
, DnsTransactionState state
) {
412 assert(!DNS_TRANSACTION_IS_LIVE(state
));
413 assert(DNS_TRANSACTION_IS_LIVE(q
->state
));
415 /* Note that this call might invalidate the query. Callers
416 * should hence not attempt to access the query or transaction
417 * after calling this function. */
426 static int on_query_timeout(sd_event_source
*s
, usec_t usec
, void *userdata
) {
427 DnsQuery
*q
= userdata
;
432 dns_query_complete(q
, DNS_TRANSACTION_TIMEOUT
);
436 static int dns_query_add_candidate(DnsQuery
*q
, DnsScope
*s
) {
437 DnsQueryCandidate
*c
;
443 r
= dns_query_candidate_new(&c
, q
, s
);
447 /* If this a single-label domain on DNS, we might append a suitable search domain first. */
448 if ((q
->flags
& SD_RESOLVED_NO_SEARCH
) == 0) {
449 r
= dns_scope_name_needs_search_domain(s
, dns_question_first_name(q
->question
));
453 /* OK, we need a search domain now. Let's find one for this scope */
455 r
= dns_query_candidate_next_search_domain(c
);
456 if (r
<= 0) /* if there's no search domain, then we won't add any transaction. */
461 r
= dns_query_candidate_setup_transactions(c
);
468 dns_query_candidate_free(c
);
472 static int SYNTHESIZE_IFINDEX(int ifindex
) {
474 /* When the caller asked for resolving on a specific
475 * interface, we synthesize the answer for that
476 * interface. However, if nothing specific was claimed and we
477 * only return localhost RRs, we synthesize the answer for
483 return LOOPBACK_IFINDEX
;
486 static int SYNTHESIZE_FAMILY(uint64_t flags
) {
488 /* Picks an address family depending on set flags. This is
489 * purely for synthesized answers, where the family we return
490 * for the reply should match what was requested in the
491 * question, even though we are synthesizing the answer
494 if (!(flags
& SD_RESOLVED_DNS
)) {
495 if (flags
& SD_RESOLVED_LLMNR_IPV4
)
497 if (flags
& SD_RESOLVED_LLMNR_IPV6
)
504 static DnsProtocol
SYNTHESIZE_PROTOCOL(uint64_t flags
) {
506 /* Similar as SYNTHESIZE_FAMILY() but does this for the
507 * protocol. If resolving via DNS was requested, we claim it
508 * was DNS. Similar, if nothing specific was
509 * requested. However, if only resolving via LLMNR was
510 * requested we return that. */
512 if (flags
& SD_RESOLVED_DNS
)
513 return DNS_PROTOCOL_DNS
;
514 if (flags
& SD_RESOLVED_LLMNR
)
515 return DNS_PROTOCOL_LLMNR
;
517 return DNS_PROTOCOL_DNS
;
520 static int dns_type_to_af(uint16_t t
) {
537 static int synthesize_localhost_rr(DnsQuery
*q
, DnsResourceKey
*key
, DnsAnswer
**answer
) {
544 r
= dns_answer_reserve(answer
, 2);
548 if (IN_SET(key
->type
, DNS_TYPE_A
, DNS_TYPE_ANY
)) {
549 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*rr
= NULL
;
551 rr
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_A
, DNS_RESOURCE_KEY_NAME(key
));
555 rr
->a
.in_addr
.s_addr
= htobe32(INADDR_LOOPBACK
);
557 r
= dns_answer_add(*answer
, rr
, SYNTHESIZE_IFINDEX(q
->ifindex
), DNS_ANSWER_AUTHENTICATED
);
562 if (IN_SET(key
->type
, DNS_TYPE_AAAA
, DNS_TYPE_ANY
)) {
563 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*rr
= NULL
;
565 rr
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_AAAA
, DNS_RESOURCE_KEY_NAME(key
));
569 rr
->aaaa
.in6_addr
= in6addr_loopback
;
571 r
= dns_answer_add(*answer
, rr
, SYNTHESIZE_IFINDEX(q
->ifindex
), DNS_ANSWER_AUTHENTICATED
);
579 static int answer_add_ptr(DnsAnswer
**answer
, const char *from
, const char *to
, int ifindex
, DnsAnswerFlags flags
) {
580 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*rr
= NULL
;
582 rr
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_PTR
, from
);
586 rr
->ptr
.name
= strdup(to
);
590 return dns_answer_add(*answer
, rr
, ifindex
, flags
);
593 static int synthesize_localhost_ptr(DnsQuery
*q
, DnsResourceKey
*key
, DnsAnswer
**answer
) {
600 if (IN_SET(key
->type
, DNS_TYPE_PTR
, DNS_TYPE_ANY
)) {
601 r
= dns_answer_reserve(answer
, 1);
605 r
= answer_add_ptr(answer
, DNS_RESOURCE_KEY_NAME(key
), "localhost", SYNTHESIZE_IFINDEX(q
->ifindex
), DNS_ANSWER_AUTHENTICATED
);
613 static int answer_add_addresses_rr(
616 struct local_address
*addresses
,
617 unsigned n_addresses
) {
625 r
= dns_answer_reserve(answer
, n_addresses
);
629 for (j
= 0; j
< n_addresses
; j
++) {
630 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*rr
= NULL
;
632 r
= dns_resource_record_new_address(&rr
, addresses
[j
].family
, &addresses
[j
].address
, name
);
636 r
= dns_answer_add(*answer
, rr
, addresses
[j
].ifindex
, DNS_ANSWER_AUTHENTICATED
);
644 static int answer_add_addresses_ptr(
647 struct local_address
*addresses
,
648 unsigned n_addresses
,
649 int af
, const union in_addr_union
*match
) {
657 for (j
= 0; j
< n_addresses
; j
++) {
658 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*rr
= NULL
;
660 if (af
!= AF_UNSPEC
) {
662 if (addresses
[j
].family
!= af
)
665 if (match
&& !in_addr_equal(af
, match
, &addresses
[j
].address
))
669 r
= dns_answer_reserve(answer
, 1);
673 r
= dns_resource_record_new_reverse(&rr
, addresses
[j
].family
, &addresses
[j
].address
, name
);
677 r
= dns_answer_add(*answer
, rr
, addresses
[j
].ifindex
, DNS_ANSWER_AUTHENTICATED
);
685 static int synthesize_system_hostname_rr(DnsQuery
*q
, DnsResourceKey
*key
, DnsAnswer
**answer
) {
686 _cleanup_free_
struct local_address
*addresses
= NULL
;
693 af
= dns_type_to_af(key
->type
);
695 n
= local_addresses(q
->manager
->rtnl
, q
->ifindex
, af
, &addresses
);
700 struct local_address buffer
[2];
702 /* If we have no local addresses then use ::1
703 * and 127.0.0.2 as local ones. */
705 if (af
== AF_INET
|| af
== AF_UNSPEC
)
706 buffer
[n
++] = (struct local_address
) {
708 .ifindex
= SYNTHESIZE_IFINDEX(q
->ifindex
),
709 .address
.in
.s_addr
= htobe32(0x7F000002),
712 if (af
== AF_INET6
|| af
== AF_UNSPEC
)
713 buffer
[n
++] = (struct local_address
) {
715 .ifindex
= SYNTHESIZE_IFINDEX(q
->ifindex
),
716 .address
.in6
= in6addr_loopback
,
719 return answer_add_addresses_rr(answer
, DNS_RESOURCE_KEY_NAME(key
), buffer
, n
);
723 return answer_add_addresses_rr(answer
, DNS_RESOURCE_KEY_NAME(key
), addresses
, n
);
726 static int synthesize_system_hostname_ptr(DnsQuery
*q
, int af
, const union in_addr_union
*address
, DnsAnswer
**answer
) {
727 _cleanup_free_
struct local_address
*addresses
= NULL
;
734 if (af
== AF_INET
&& address
->in
.s_addr
== htobe32(0x7F000002)) {
736 /* Always map the IPv4 address 127.0.0.2 to the local
737 * hostname, in addition to "localhost": */
739 r
= dns_answer_reserve(answer
, 3);
743 r
= answer_add_ptr(answer
, "2.0.0.127.in-addr.arpa", q
->manager
->llmnr_hostname
, SYNTHESIZE_IFINDEX(q
->ifindex
), DNS_ANSWER_AUTHENTICATED
);
747 r
= answer_add_ptr(answer
, "2.0.0.127.in-addr.arpa", q
->manager
->mdns_hostname
, SYNTHESIZE_IFINDEX(q
->ifindex
), DNS_ANSWER_AUTHENTICATED
);
751 r
= answer_add_ptr(answer
, "2.0.0.127.in-addr.arpa", "localhost", SYNTHESIZE_IFINDEX(q
->ifindex
), DNS_ANSWER_AUTHENTICATED
);
758 n
= local_addresses(q
->manager
->rtnl
, q
->ifindex
, af
, &addresses
);
762 r
= answer_add_addresses_ptr(answer
, q
->manager
->llmnr_hostname
, addresses
, n
, af
, address
);
766 return answer_add_addresses_ptr(answer
, q
->manager
->mdns_hostname
, addresses
, n
, af
, address
);
769 static int synthesize_gateway_rr(DnsQuery
*q
, DnsResourceKey
*key
, DnsAnswer
**answer
) {
770 _cleanup_free_
struct local_address
*addresses
= NULL
;
777 af
= dns_type_to_af(key
->type
);
779 n
= local_gateways(q
->manager
->rtnl
, q
->ifindex
, af
, &addresses
);
784 return answer_add_addresses_rr(answer
, DNS_RESOURCE_KEY_NAME(key
), addresses
, n
);
787 static int synthesize_gateway_ptr(DnsQuery
*q
, int af
, const union in_addr_union
*address
, DnsAnswer
**answer
) {
788 _cleanup_free_
struct local_address
*addresses
= NULL
;
795 n
= local_gateways(q
->manager
->rtnl
, q
->ifindex
, af
, &addresses
);
799 return answer_add_addresses_ptr(answer
, "gateway", addresses
, n
, af
, address
);
802 static int dns_query_synthesize_reply(DnsQuery
*q
, DnsTransactionState
*state
) {
803 _cleanup_(dns_answer_unrefp
) DnsAnswer
*answer
= NULL
;
810 /* Tries to synthesize localhost RR replies where appropriate */
813 DNS_TRANSACTION_RCODE_FAILURE
,
814 DNS_TRANSACTION_NO_SERVERS
,
815 DNS_TRANSACTION_TIMEOUT
,
816 DNS_TRANSACTION_ATTEMPTS_MAX_REACHED
))
819 for (i
= 0; i
< q
->question
->n_keys
; i
++) {
820 union in_addr_union address
;
824 if (q
->question
->keys
[i
]->class != DNS_CLASS_IN
&&
825 q
->question
->keys
[i
]->class != DNS_CLASS_ANY
)
828 name
= DNS_RESOURCE_KEY_NAME(q
->question
->keys
[i
]);
830 if (is_localhost(name
)) {
832 r
= synthesize_localhost_rr(q
, q
->question
->keys
[i
], &answer
);
834 return log_error_errno(r
, "Failed to synthesize localhost RRs: %m");
836 } else if (manager_is_own_hostname(q
->manager
, name
)) {
838 r
= synthesize_system_hostname_rr(q
, q
->question
->keys
[i
], &answer
);
840 return log_error_errno(r
, "Failed to synthesize system hostname RRs: %m");
842 } else if (is_gateway_hostname(name
)) {
844 r
= synthesize_gateway_rr(q
, q
->question
->keys
[i
], &answer
);
846 return log_error_errno(r
, "Failed to synthesize gateway RRs: %m");
848 } else if ((dns_name_endswith(name
, "127.in-addr.arpa") > 0 && dns_name_equal(name
, "2.0.0.127.in-addr.arpa") == 0) ||
849 dns_name_equal(name
, "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa") > 0) {
851 r
= synthesize_localhost_ptr(q
, q
->question
->keys
[i
], &answer
);
853 return log_error_errno(r
, "Failed to synthesize localhost PTR RRs: %m");
855 } else if (dns_name_address(name
, &af
, &address
) > 0) {
857 r
= synthesize_system_hostname_ptr(q
, af
, &address
, &answer
);
859 return log_error_errno(r
, "Failed to synthesize system hostname PTR RR: %m");
861 r
= synthesize_gateway_ptr(q
, af
, &address
, &answer
);
863 return log_error_errno(r
, "Failed to synthesize gateway hostname PTR RR: %m");
870 dns_answer_unref(q
->answer
);
874 q
->answer_rcode
= DNS_RCODE_SUCCESS
;
875 q
->answer_protocol
= SYNTHESIZE_PROTOCOL(q
->flags
);
876 q
->answer_family
= SYNTHESIZE_FAMILY(q
->flags
);
878 *state
= DNS_TRANSACTION_SUCCESS
;
883 int dns_query_go(DnsQuery
*q
) {
884 DnsScopeMatch found
= DNS_SCOPE_NO
;
885 DnsScope
*s
, *first
= NULL
;
886 DnsQueryCandidate
*c
;
892 if (q
->state
!= DNS_TRANSACTION_NULL
)
896 assert(q
->question
->n_keys
> 0);
898 name
= dns_question_first_name(q
->question
);
900 LIST_FOREACH(scopes
, s
, q
->manager
->dns_scopes
) {
903 match
= dns_scope_good_domain(s
, q
->ifindex
, q
->flags
, name
);
907 if (match
== DNS_SCOPE_NO
)
912 if (match
== DNS_SCOPE_YES
) {
916 assert(match
== DNS_SCOPE_MAYBE
);
923 if (found
== DNS_SCOPE_NO
) {
924 DnsTransactionState state
= DNS_TRANSACTION_NO_SERVERS
;
926 dns_query_synthesize_reply(q
, &state
);
927 dns_query_complete(q
, state
);
931 r
= dns_query_add_candidate(q
, first
);
935 LIST_FOREACH(scopes
, s
, first
->scopes_next
) {
938 match
= dns_scope_good_domain(s
, q
->ifindex
, q
->flags
, name
);
945 r
= dns_query_add_candidate(q
, s
);
950 q
->answer
= dns_answer_unref(q
->answer
);
952 q
->answer_family
= AF_UNSPEC
;
953 q
->answer_protocol
= _DNS_PROTOCOL_INVALID
;
955 r
= sd_event_add_time(
957 &q
->timeout_event_source
,
958 clock_boottime_or_monotonic(),
959 now(clock_boottime_or_monotonic()) + QUERY_TIMEOUT_USEC
, 0,
960 on_query_timeout
, q
);
964 (void) sd_event_source_set_description(q
->timeout_event_source
, "query-timeout");
966 q
->state
= DNS_TRANSACTION_PENDING
;
969 /* Start the transactions */
970 LIST_FOREACH(candidates_by_query
, c
, q
->candidates
) {
971 r
= dns_query_candidate_go(c
);
988 static void dns_query_accept(DnsQuery
*q
, DnsQueryCandidate
*c
) {
989 DnsTransactionState state
= DNS_TRANSACTION_NO_SERVERS
;
990 bool has_authenticated
= false, has_non_authenticated
= false;
991 DnssecResult dnssec_result_authenticated
= _DNSSEC_RESULT_INVALID
, dnssec_result_non_authenticated
= _DNSSEC_RESULT_INVALID
;
999 dns_query_synthesize_reply(q
, &state
);
1000 dns_query_complete(q
, state
);
1004 SET_FOREACH(t
, c
->transactions
, i
) {
1008 case DNS_TRANSACTION_SUCCESS
: {
1009 /* We found a successfuly reply, merge it into the answer */
1010 r
= dns_answer_extend(&q
->answer
, t
->answer
);
1012 dns_query_complete(q
, DNS_TRANSACTION_RESOURCES
);
1016 q
->answer_rcode
= t
->answer_rcode
;
1018 if (t
->answer_authenticated
) {
1019 has_authenticated
= true;
1020 dnssec_result_authenticated
= t
->answer_dnssec_result
;
1022 has_non_authenticated
= true;
1023 dnssec_result_non_authenticated
= t
->answer_dnssec_result
;
1026 state
= DNS_TRANSACTION_SUCCESS
;
1030 case DNS_TRANSACTION_NULL
:
1031 case DNS_TRANSACTION_PENDING
:
1032 case DNS_TRANSACTION_VALIDATING
:
1033 case DNS_TRANSACTION_ABORTED
:
1034 /* Ignore transactions that didn't complete */
1038 /* Any kind of failure? Store the data away,
1039 * if there's nothing stored yet. */
1041 if (state
== DNS_TRANSACTION_SUCCESS
)
1044 q
->answer
= dns_answer_unref(q
->answer
);
1045 q
->answer_rcode
= t
->answer_rcode
;
1046 q
->answer_dnssec_result
= t
->answer_dnssec_result
;
1053 if (state
== DNS_TRANSACTION_SUCCESS
) {
1054 q
->answer_authenticated
= has_authenticated
&& !has_non_authenticated
;
1055 q
->answer_dnssec_result
= q
->answer_authenticated
? dnssec_result_authenticated
: dnssec_result_non_authenticated
;
1058 q
->answer_protocol
= c
->scope
->protocol
;
1059 q
->answer_family
= c
->scope
->family
;
1061 dns_search_domain_unref(q
->answer_search_domain
);
1062 q
->answer_search_domain
= dns_search_domain_ref(c
->search_domain
);
1064 dns_query_synthesize_reply(q
, &state
);
1065 dns_query_complete(q
, state
);
1068 void dns_query_ready(DnsQuery
*q
) {
1070 DnsQueryCandidate
*bad
= NULL
, *c
;
1071 bool pending
= false;
1074 assert(DNS_TRANSACTION_IS_LIVE(q
->state
));
1076 /* Note that this call might invalidate the query. Callers
1077 * should hence not attempt to access the query or transaction
1078 * after calling this function, unless the block_ready
1079 * counter was explicitly bumped before doing so. */
1081 if (q
->block_ready
> 0)
1084 LIST_FOREACH(candidates_by_query
, c
, q
->candidates
) {
1085 DnsTransactionState state
;
1087 state
= dns_query_candidate_state(c
);
1090 case DNS_TRANSACTION_SUCCESS
:
1091 /* One of the candidates is successful,
1092 * let's use it, and copy its data out */
1093 dns_query_accept(q
, c
);
1096 case DNS_TRANSACTION_NULL
:
1097 case DNS_TRANSACTION_PENDING
:
1098 case DNS_TRANSACTION_VALIDATING
:
1099 /* One of the candidates is still going on,
1100 * let's maybe wait for it */
1105 /* Any kind of failure */
1114 dns_query_accept(q
, bad
);
1117 static int dns_query_cname_redirect(DnsQuery
*q
, const DnsResourceRecord
*cname
) {
1118 _cleanup_(dns_question_unrefp
) DnsQuestion
*nq
= NULL
;
1123 q
->n_cname_redirects
++;
1124 if (q
->n_cname_redirects
> CNAME_MAX
)
1127 r
= dns_question_cname_redirect(q
->question
, cname
, &nq
);
1131 log_debug("Following CNAME/DNAME %s → %s", dns_question_first_name(q
->question
), dns_question_first_name(nq
));
1133 dns_question_unref(q
->question
);
1138 q
->state
= DNS_TRANSACTION_NULL
;
1143 int dns_query_process_cname(DnsQuery
*q
) {
1144 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*cname
= NULL
;
1145 DnsResourceRecord
*rr
;
1150 if (!IN_SET(q
->state
, DNS_TRANSACTION_SUCCESS
, DNS_TRANSACTION_NULL
))
1151 return DNS_QUERY_NOMATCH
;
1153 DNS_ANSWER_FOREACH(rr
, q
->answer
) {
1155 r
= dns_question_matches_rr(q
->question
, rr
, DNS_SEARCH_DOMAIN_NAME(q
->answer_search_domain
));
1159 return DNS_QUERY_MATCH
; /* The answer matches directly, no need to follow cnames */
1161 r
= dns_question_matches_cname(q
->question
, rr
, DNS_SEARCH_DOMAIN_NAME(q
->answer_search_domain
));
1164 if (r
> 0 && !cname
)
1165 cname
= dns_resource_record_ref(rr
);
1169 return DNS_QUERY_NOMATCH
; /* No match and no cname to follow */
1171 if (q
->flags
& SD_RESOLVED_NO_CNAME
)
1174 /* OK, let's actually follow the CNAME */
1175 r
= dns_query_cname_redirect(q
, cname
);
1179 /* Let's see if the answer can already answer the new
1180 * redirected question */
1181 r
= dns_query_process_cname(q
);
1182 if (r
!= DNS_QUERY_NOMATCH
)
1185 /* OK, it cannot, let's begin with the new query */
1186 r
= dns_query_go(q
);
1190 return DNS_QUERY_RESTARTED
; /* We restarted the query for a new cname */
1193 static int on_bus_track(sd_bus_track
*t
, void *userdata
) {
1194 DnsQuery
*q
= userdata
;
1199 log_debug("Client of active query vanished, aborting query.");
1200 dns_query_complete(q
, DNS_TRANSACTION_ABORTED
);
1204 int dns_query_bus_track(DnsQuery
*q
, sd_bus_message
*m
) {
1210 if (!q
->bus_track
) {
1211 r
= sd_bus_track_new(sd_bus_message_get_bus(m
), &q
->bus_track
, on_bus_track
, q
);
1216 r
= sd_bus_track_add_sender(q
->bus_track
, m
);