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"
27 #include "resolved-dns-synthesize.h"
28 #include "string-util.h"
30 /* How long to wait for the query in total */
31 #define QUERY_TIMEOUT_USEC (30 * USEC_PER_SEC)
34 #define QUERIES_MAX 2048
35 #define AUXILIARY_QUERIES_MAX 64
37 static int dns_query_candidate_new(DnsQueryCandidate
**ret
, DnsQuery
*q
, DnsScope
*s
) {
44 c
= new0(DnsQueryCandidate
, 1);
51 LIST_PREPEND(candidates_by_query
, q
->candidates
, c
);
52 LIST_PREPEND(candidates_by_scope
, s
->query_candidates
, c
);
58 static void dns_query_candidate_stop(DnsQueryCandidate
*c
) {
63 while ((t
= set_steal_first(c
->transactions
))) {
64 set_remove(t
->notify_query_candidates
, c
);
65 dns_transaction_gc(t
);
69 DnsQueryCandidate
* dns_query_candidate_free(DnsQueryCandidate
*c
) {
74 dns_query_candidate_stop(c
);
76 set_free(c
->transactions
);
77 dns_search_domain_unref(c
->search_domain
);
80 LIST_REMOVE(candidates_by_query
, c
->query
->candidates
, c
);
83 LIST_REMOVE(candidates_by_scope
, c
->scope
->query_candidates
, c
);
90 static int dns_query_candidate_next_search_domain(DnsQueryCandidate
*c
) {
91 DnsSearchDomain
*next
= NULL
;
95 if (c
->search_domain
&& c
->search_domain
->linked
) {
96 next
= c
->search_domain
->domains_next
;
98 if (!next
) /* We hit the end of the list */
102 next
= dns_scope_get_search_domains(c
->scope
);
104 if (!next
) /* OK, there's nothing. */
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_put(t
->notify_query_candidates
, c
);
143 r
= set_put(c
->transactions
, t
);
145 (void) set_remove(t
->notify_query_candidates
, c
);
152 dns_transaction_gc(t
);
156 static int dns_query_candidate_go(DnsQueryCandidate
*c
) {
163 /* Start the transactions that are not started yet */
164 SET_FOREACH(t
, c
->transactions
, i
) {
165 if (t
->state
!= DNS_TRANSACTION_NULL
)
168 r
= dns_transaction_go(t
);
176 static DnsTransactionState
dns_query_candidate_state(DnsQueryCandidate
*c
) {
177 DnsTransactionState state
= DNS_TRANSACTION_NO_SERVERS
;
183 if (c
->error_code
!= 0)
184 return DNS_TRANSACTION_RESOURCES
;
186 SET_FOREACH(t
, c
->transactions
, i
) {
190 case DNS_TRANSACTION_NULL
:
191 /* If there's a NULL transaction pending, then
192 * this means not all transactions where
193 * started yet, and we were called from within
194 * the stackframe that is supposed to start
195 * remaining transactions. In this case,
196 * simply claim the candidate is pending. */
198 case DNS_TRANSACTION_PENDING
:
199 case DNS_TRANSACTION_VALIDATING
:
200 /* If there's one transaction currently in
201 * VALIDATING state, then this means there's
202 * also one in PENDING state, hence we can
203 * return PENDING immediately. */
204 return DNS_TRANSACTION_PENDING
;
206 case DNS_TRANSACTION_SUCCESS
:
211 if (state
!= DNS_TRANSACTION_SUCCESS
)
221 static int dns_query_candidate_setup_transactions(DnsQueryCandidate
*c
) {
222 DnsQuestion
*question
;
228 dns_query_candidate_stop(c
);
230 question
= dns_query_question_for_protocol(c
->query
, c
->scope
->protocol
);
232 /* Create one transaction per question key */
233 DNS_QUESTION_FOREACH(key
, question
) {
234 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*new_key
= NULL
;
236 if (c
->search_domain
) {
237 r
= dns_resource_key_new_append_suffix(&new_key
, key
, c
->search_domain
->name
);
242 r
= dns_query_candidate_add_transaction(c
, new_key
?: key
);
252 dns_query_candidate_stop(c
);
256 void dns_query_candidate_notify(DnsQueryCandidate
*c
) {
257 DnsTransactionState state
;
262 state
= dns_query_candidate_state(c
);
264 if (DNS_TRANSACTION_IS_LIVE(state
))
267 if (state
!= DNS_TRANSACTION_SUCCESS
&& c
->search_domain
) {
269 r
= dns_query_candidate_next_search_domain(c
);
274 /* OK, there's another search domain to try, let's do so. */
276 r
= dns_query_candidate_setup_transactions(c
);
281 /* New transactions where queued. Start them and wait */
283 r
= dns_query_candidate_go(c
);
293 dns_query_ready(c
->query
);
297 log_warning_errno(r
, "Failed to follow search domains: %m");
299 dns_query_ready(c
->query
);
302 static void dns_query_stop(DnsQuery
*q
) {
303 DnsQueryCandidate
*c
;
307 q
->timeout_event_source
= sd_event_source_unref(q
->timeout_event_source
);
309 LIST_FOREACH(candidates_by_query
, c
, q
->candidates
)
310 dns_query_candidate_stop(c
);
313 static void dns_query_free_candidates(DnsQuery
*q
) {
316 while (q
->candidates
)
317 dns_query_candidate_free(q
->candidates
);
320 static void dns_query_reset_answer(DnsQuery
*q
) {
323 q
->answer
= dns_answer_unref(q
->answer
);
325 q
->answer_dnssec_result
= _DNSSEC_RESULT_INVALID
;
326 q
->answer_authenticated
= false;
327 q
->answer_protocol
= _DNS_PROTOCOL_INVALID
;
328 q
->answer_family
= AF_UNSPEC
;
329 q
->answer_search_domain
= dns_search_domain_unref(q
->answer_search_domain
);
332 DnsQuery
*dns_query_free(DnsQuery
*q
) {
336 while (q
->auxiliary_queries
)
337 dns_query_free(q
->auxiliary_queries
);
339 if (q
->auxiliary_for
) {
340 assert(q
->auxiliary_for
->n_auxiliary_queries
> 0);
341 q
->auxiliary_for
->n_auxiliary_queries
--;
342 LIST_REMOVE(auxiliary_queries
, q
->auxiliary_for
->auxiliary_queries
, q
);
345 dns_query_free_candidates(q
);
347 dns_question_unref(q
->question_idna
);
348 dns_question_unref(q
->question_utf8
);
350 dns_query_reset_answer(q
);
352 sd_bus_message_unref(q
->request
);
353 sd_bus_track_unref(q
->bus_track
);
355 free(q
->request_address_string
);
358 LIST_REMOVE(queries
, q
->manager
->dns_queries
, q
);
359 q
->manager
->n_dns_queries
--;
370 DnsQuestion
*question_utf8
,
371 DnsQuestion
*question_idna
,
372 int ifindex
, uint64_t flags
) {
374 _cleanup_(dns_query_freep
) DnsQuery
*q
= NULL
;
381 if (dns_question_size(question_utf8
) > 0) {
382 r
= dns_question_is_valid_for_query(question_utf8
);
391 /* If the IDNA and UTF8 questions are the same, merge their references */
392 r
= dns_question_is_equal(question_idna
, question_utf8
);
396 question_idna
= question_utf8
;
398 if (dns_question_size(question_idna
) > 0) {
399 r
= dns_question_is_valid_for_query(question_idna
);
409 if (!good
) /* don't allow empty queries */
412 if (m
->n_dns_queries
>= QUERIES_MAX
)
415 q
= new0(DnsQuery
, 1);
419 q
->question_utf8
= dns_question_ref(question_utf8
);
420 q
->question_idna
= dns_question_ref(question_idna
);
421 q
->ifindex
= ifindex
;
423 q
->answer_dnssec_result
= _DNSSEC_RESULT_INVALID
;
424 q
->answer_protocol
= _DNS_PROTOCOL_INVALID
;
425 q
->answer_family
= AF_UNSPEC
;
427 /* First dump UTF8 question */
428 DNS_QUESTION_FOREACH(key
, question_utf8
) {
429 _cleanup_free_
char *p
= NULL
;
431 r
= dns_resource_key_to_string(key
, &p
);
435 log_debug("Looking up RR for %s.", strstrip(p
));
438 /* And then dump the IDNA question, but only what hasn't been dumped already through the UTF8 question. */
439 DNS_QUESTION_FOREACH(key
, question_idna
) {
440 _cleanup_free_
char *p
= NULL
;
442 r
= dns_question_contains(question_utf8
, key
);
448 r
= dns_resource_key_to_string(key
, &p
);
452 log_debug("Looking up IDNA RR for %s.", strstrip(p
));
455 LIST_PREPEND(queries
, m
->dns_queries
, q
);
466 int dns_query_make_auxiliary(DnsQuery
*q
, DnsQuery
*auxiliary_for
) {
468 assert(auxiliary_for
);
470 /* Ensure that that the query is not auxiliary yet, and
471 * nothing else is auxiliary to it either */
472 assert(!q
->auxiliary_for
);
473 assert(!q
->auxiliary_queries
);
475 /* Ensure that the unit we shall be made auxiliary for isn't
476 * auxiliary itself */
477 assert(!auxiliary_for
->auxiliary_for
);
479 if (auxiliary_for
->n_auxiliary_queries
>= AUXILIARY_QUERIES_MAX
)
482 LIST_PREPEND(auxiliary_queries
, auxiliary_for
->auxiliary_queries
, q
);
483 q
->auxiliary_for
= auxiliary_for
;
485 auxiliary_for
->n_auxiliary_queries
++;
489 static void dns_query_complete(DnsQuery
*q
, DnsTransactionState state
) {
491 assert(!DNS_TRANSACTION_IS_LIVE(state
));
492 assert(DNS_TRANSACTION_IS_LIVE(q
->state
));
494 /* Note that this call might invalidate the query. Callers
495 * should hence not attempt to access the query or transaction
496 * after calling this function. */
505 static int on_query_timeout(sd_event_source
*s
, usec_t usec
, void *userdata
) {
506 DnsQuery
*q
= userdata
;
511 dns_query_complete(q
, DNS_TRANSACTION_TIMEOUT
);
515 static int dns_query_add_candidate(DnsQuery
*q
, DnsScope
*s
) {
516 DnsQueryCandidate
*c
;
522 r
= dns_query_candidate_new(&c
, q
, s
);
526 /* If this a single-label domain on DNS, we might append a suitable search domain first. */
527 if ((q
->flags
& SD_RESOLVED_NO_SEARCH
) == 0) {
528 r
= dns_scope_name_needs_search_domain(s
, dns_question_first_name(q
->question_idna
));
532 /* OK, we need a search domain now. Let's find one for this scope */
534 r
= dns_query_candidate_next_search_domain(c
);
535 if (r
<= 0) /* if there's no search domain, then we won't add any transaction. */
540 r
= dns_query_candidate_setup_transactions(c
);
547 dns_query_candidate_free(c
);
551 static int dns_query_synthesize_reply(DnsQuery
*q
, DnsTransactionState
*state
) {
552 _cleanup_(dns_answer_unrefp
) DnsAnswer
*answer
= NULL
;
553 DnsProtocol protocol
;
559 /* Tries to synthesize localhost RR replies (and others) where appropriate */
562 DNS_TRANSACTION_RCODE_FAILURE
,
563 DNS_TRANSACTION_NO_SERVERS
,
564 DNS_TRANSACTION_TIMEOUT
,
565 DNS_TRANSACTION_ATTEMPTS_MAX_REACHED
,
566 DNS_TRANSACTION_NETWORK_DOWN
,
567 DNS_TRANSACTION_NOT_FOUND
))
570 r
= dns_synthesize_answer(
582 dns_query_reset_answer(q
);
586 q
->answer_rcode
= DNS_RCODE_SUCCESS
;
587 q
->answer_protocol
= protocol
;
588 q
->answer_family
= family
;
589 q
->answer_authenticated
= true;
591 *state
= DNS_TRANSACTION_SUCCESS
;
596 int dns_query_go(DnsQuery
*q
) {
597 DnsScopeMatch found
= DNS_SCOPE_NO
;
598 DnsScope
*s
, *first
= NULL
;
599 DnsQueryCandidate
*c
;
604 if (q
->state
!= DNS_TRANSACTION_NULL
)
607 LIST_FOREACH(scopes
, s
, q
->manager
->dns_scopes
) {
611 name
= dns_question_first_name(dns_query_question_for_protocol(q
, s
->protocol
));
615 match
= dns_scope_good_domain(s
, q
->ifindex
, q
->flags
, name
);
619 if (match
== DNS_SCOPE_NO
)
624 if (match
== DNS_SCOPE_YES
) {
628 assert(match
== DNS_SCOPE_MAYBE
);
635 if (found
== DNS_SCOPE_NO
) {
636 DnsTransactionState state
= DNS_TRANSACTION_NO_SERVERS
;
638 dns_query_synthesize_reply(q
, &state
);
639 dns_query_complete(q
, state
);
643 r
= dns_query_add_candidate(q
, first
);
647 LIST_FOREACH(scopes
, s
, first
->scopes_next
) {
651 name
= dns_question_first_name(dns_query_question_for_protocol(q
, s
->protocol
));
655 match
= dns_scope_good_domain(s
, q
->ifindex
, q
->flags
, name
);
662 r
= dns_query_add_candidate(q
, s
);
667 q
->answer
= dns_answer_unref(q
->answer
);
669 q
->answer_family
= AF_UNSPEC
;
670 q
->answer_protocol
= _DNS_PROTOCOL_INVALID
;
672 r
= sd_event_add_time(
674 &q
->timeout_event_source
,
675 clock_boottime_or_monotonic(),
676 now(clock_boottime_or_monotonic()) + QUERY_TIMEOUT_USEC
, 0,
677 on_query_timeout
, q
);
681 (void) sd_event_source_set_description(q
->timeout_event_source
, "query-timeout");
683 q
->state
= DNS_TRANSACTION_PENDING
;
686 /* Start the transactions */
687 LIST_FOREACH(candidates_by_query
, c
, q
->candidates
) {
688 r
= dns_query_candidate_go(c
);
705 static void dns_query_accept(DnsQuery
*q
, DnsQueryCandidate
*c
) {
706 DnsTransactionState state
= DNS_TRANSACTION_NO_SERVERS
;
707 bool has_authenticated
= false, has_non_authenticated
= false;
708 DnssecResult dnssec_result_authenticated
= _DNSSEC_RESULT_INVALID
, dnssec_result_non_authenticated
= _DNSSEC_RESULT_INVALID
;
716 dns_query_synthesize_reply(q
, &state
);
717 dns_query_complete(q
, state
);
721 SET_FOREACH(t
, c
->transactions
, i
) {
725 case DNS_TRANSACTION_SUCCESS
: {
726 /* We found a successfuly reply, merge it into the answer */
727 r
= dns_answer_extend(&q
->answer
, t
->answer
);
729 dns_query_complete(q
, DNS_TRANSACTION_RESOURCES
);
733 q
->answer_rcode
= t
->answer_rcode
;
735 if (t
->answer_authenticated
) {
736 has_authenticated
= true;
737 dnssec_result_authenticated
= t
->answer_dnssec_result
;
739 has_non_authenticated
= true;
740 dnssec_result_non_authenticated
= t
->answer_dnssec_result
;
743 state
= DNS_TRANSACTION_SUCCESS
;
747 case DNS_TRANSACTION_NULL
:
748 case DNS_TRANSACTION_PENDING
:
749 case DNS_TRANSACTION_VALIDATING
:
750 case DNS_TRANSACTION_ABORTED
:
751 /* Ignore transactions that didn't complete */
755 /* Any kind of failure? Store the data away,
756 * if there's nothing stored yet. */
758 if (state
== DNS_TRANSACTION_SUCCESS
)
761 q
->answer
= dns_answer_unref(q
->answer
);
762 q
->answer_rcode
= t
->answer_rcode
;
763 q
->answer_dnssec_result
= t
->answer_dnssec_result
;
770 if (state
== DNS_TRANSACTION_SUCCESS
) {
771 q
->answer_authenticated
= has_authenticated
&& !has_non_authenticated
;
772 q
->answer_dnssec_result
= q
->answer_authenticated
? dnssec_result_authenticated
: dnssec_result_non_authenticated
;
775 q
->answer_protocol
= c
->scope
->protocol
;
776 q
->answer_family
= c
->scope
->family
;
778 dns_search_domain_unref(q
->answer_search_domain
);
779 q
->answer_search_domain
= dns_search_domain_ref(c
->search_domain
);
781 dns_query_synthesize_reply(q
, &state
);
782 dns_query_complete(q
, state
);
785 void dns_query_ready(DnsQuery
*q
) {
787 DnsQueryCandidate
*bad
= NULL
, *c
;
788 bool pending
= false;
791 assert(DNS_TRANSACTION_IS_LIVE(q
->state
));
793 /* Note that this call might invalidate the query. Callers
794 * should hence not attempt to access the query or transaction
795 * after calling this function, unless the block_ready
796 * counter was explicitly bumped before doing so. */
798 if (q
->block_ready
> 0)
801 LIST_FOREACH(candidates_by_query
, c
, q
->candidates
) {
802 DnsTransactionState state
;
804 state
= dns_query_candidate_state(c
);
807 case DNS_TRANSACTION_SUCCESS
:
808 /* One of the candidates is successful,
809 * let's use it, and copy its data out */
810 dns_query_accept(q
, c
);
813 case DNS_TRANSACTION_NULL
:
814 case DNS_TRANSACTION_PENDING
:
815 case DNS_TRANSACTION_VALIDATING
:
816 /* One of the candidates is still going on,
817 * let's maybe wait for it */
822 /* Any kind of failure */
831 dns_query_accept(q
, bad
);
834 static int dns_query_cname_redirect(DnsQuery
*q
, const DnsResourceRecord
*cname
) {
835 _cleanup_(dns_question_unrefp
) DnsQuestion
*nq_idna
= NULL
, *nq_utf8
= NULL
;
840 q
->n_cname_redirects
++;
841 if (q
->n_cname_redirects
> CNAME_MAX
)
844 r
= dns_question_cname_redirect(q
->question_idna
, cname
, &nq_idna
);
848 log_debug("Following CNAME/DNAME %s → %s.", dns_question_first_name(q
->question_idna
), dns_question_first_name(nq_idna
));
850 k
= dns_question_is_equal(q
->question_idna
, q
->question_utf8
);
854 /* Same question? Shortcut new question generation */
855 nq_utf8
= dns_question_ref(nq_idna
);
858 k
= dns_question_cname_redirect(q
->question_utf8
, cname
, &nq_utf8
);
862 log_debug("Following UTF8 CNAME/DNAME %s → %s.", dns_question_first_name(q
->question_utf8
), dns_question_first_name(nq_utf8
));
865 if (r
== 0 && k
== 0) /* No actual cname happened? */
868 dns_question_unref(q
->question_idna
);
869 q
->question_idna
= nq_idna
;
872 dns_question_unref(q
->question_utf8
);
873 q
->question_utf8
= nq_utf8
;
876 dns_query_free_candidates(q
);
877 dns_query_reset_answer(q
);
878 q
->state
= DNS_TRANSACTION_NULL
;
880 /* Turn off searching for the new name */
881 q
->flags
|= SD_RESOLVED_NO_SEARCH
;
886 int dns_query_process_cname(DnsQuery
*q
) {
887 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*cname
= NULL
;
888 DnsQuestion
*question
;
889 DnsResourceRecord
*rr
;
894 if (!IN_SET(q
->state
, DNS_TRANSACTION_SUCCESS
, DNS_TRANSACTION_NULL
))
895 return DNS_QUERY_NOMATCH
;
897 question
= dns_query_question_for_protocol(q
, q
->answer_protocol
);
899 DNS_ANSWER_FOREACH(rr
, q
->answer
) {
900 r
= dns_question_matches_rr(question
, rr
, DNS_SEARCH_DOMAIN_NAME(q
->answer_search_domain
));
904 return DNS_QUERY_MATCH
; /* The answer matches directly, no need to follow cnames */
906 r
= dns_question_matches_cname_or_dname(question
, rr
, DNS_SEARCH_DOMAIN_NAME(q
->answer_search_domain
));
910 cname
= dns_resource_record_ref(rr
);
914 return DNS_QUERY_NOMATCH
; /* No match and no cname to follow */
916 if (q
->flags
& SD_RESOLVED_NO_CNAME
)
919 /* OK, let's actually follow the CNAME */
920 r
= dns_query_cname_redirect(q
, cname
);
924 /* Let's see if the answer can already answer the new
925 * redirected question */
926 r
= dns_query_process_cname(q
);
927 if (r
!= DNS_QUERY_NOMATCH
)
930 /* OK, it cannot, let's begin with the new query */
935 return DNS_QUERY_RESTARTED
; /* We restarted the query for a new cname */
938 static int on_bus_track(sd_bus_track
*t
, void *userdata
) {
939 DnsQuery
*q
= userdata
;
944 log_debug("Client of active query vanished, aborting query.");
945 dns_query_complete(q
, DNS_TRANSACTION_ABORTED
);
949 int dns_query_bus_track(DnsQuery
*q
, sd_bus_message
*m
) {
956 r
= sd_bus_track_new(sd_bus_message_get_bus(m
), &q
->bus_track
, on_bus_track
, q
);
961 r
= sd_bus_track_add_sender(q
->bus_track
, m
);
968 DnsQuestion
* dns_query_question_for_protocol(DnsQuery
*q
, DnsProtocol protocol
) {
973 case DNS_PROTOCOL_DNS
:
974 return q
->question_idna
;
976 case DNS_PROTOCOL_MDNS
:
977 case DNS_PROTOCOL_LLMNR
:
978 return q
->question_utf8
;
985 const char *dns_query_string(DnsQuery
*q
) {
989 /* Returns a somewhat useful human-readable lookup key string for this query */
991 if (q
->request_address_string
)
992 return q
->request_address_string
;
994 if (q
->request_address_valid
) {
995 r
= in_addr_to_string(q
->request_family
, &q
->request_address
, &q
->request_address_string
);
997 return q
->request_address_string
;
1000 name
= dns_question_first_name(q
->question_utf8
);
1004 return dns_question_first_name(q
->question_idna
);