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 "resolved-etc-hosts.h"
29 #include "string-util.h"
31 /* How long to wait for the query in total */
32 #define QUERY_TIMEOUT_USEC (30 * USEC_PER_SEC)
35 #define QUERIES_MAX 2048
36 #define AUXILIARY_QUERIES_MAX 64
38 static int dns_query_candidate_new(DnsQueryCandidate
**ret
, DnsQuery
*q
, DnsScope
*s
) {
45 c
= new0(DnsQueryCandidate
, 1);
52 LIST_PREPEND(candidates_by_query
, q
->candidates
, c
);
53 LIST_PREPEND(candidates_by_scope
, s
->query_candidates
, c
);
59 static void dns_query_candidate_stop(DnsQueryCandidate
*c
) {
64 while ((t
= set_steal_first(c
->transactions
))) {
65 set_remove(t
->notify_query_candidates
, c
);
66 dns_transaction_gc(t
);
70 DnsQueryCandidate
* dns_query_candidate_free(DnsQueryCandidate
*c
) {
75 dns_query_candidate_stop(c
);
77 set_free(c
->transactions
);
78 dns_search_domain_unref(c
->search_domain
);
81 LIST_REMOVE(candidates_by_query
, c
->query
->candidates
, c
);
84 LIST_REMOVE(candidates_by_scope
, c
->scope
->query_candidates
, c
);
91 static int dns_query_candidate_next_search_domain(DnsQueryCandidate
*c
) {
92 DnsSearchDomain
*next
= NULL
;
96 if (c
->search_domain
&& c
->search_domain
->linked
)
97 next
= c
->search_domain
->domains_next
;
99 next
= dns_scope_get_search_domains(c
->scope
);
102 if (!next
) /* We hit the end of the list */
105 if (!next
->route_only
)
108 /* Skip over route-only domains */
109 next
= next
->domains_next
;
112 dns_search_domain_unref(c
->search_domain
);
113 c
->search_domain
= dns_search_domain_ref(next
);
118 static int dns_query_candidate_add_transaction(DnsQueryCandidate
*c
, DnsResourceKey
*key
) {
125 t
= dns_scope_find_transaction(c
->scope
, key
, true);
127 r
= dns_transaction_new(&t
, c
->scope
, key
);
131 if (set_contains(c
->transactions
, t
))
135 r
= set_ensure_allocated(&c
->transactions
, NULL
);
139 r
= set_ensure_allocated(&t
->notify_query_candidates
, 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
);
156 dns_transaction_gc(t
);
160 static int dns_query_candidate_go(DnsQueryCandidate
*c
) {
167 /* Start the transactions that are not started yet */
168 SET_FOREACH(t
, c
->transactions
, i
) {
169 if (t
->state
!= DNS_TRANSACTION_NULL
)
172 r
= dns_transaction_go(t
);
180 static DnsTransactionState
dns_query_candidate_state(DnsQueryCandidate
*c
) {
181 DnsTransactionState state
= DNS_TRANSACTION_NO_SERVERS
;
187 if (c
->error_code
!= 0)
188 return DNS_TRANSACTION_ERRNO
;
190 SET_FOREACH(t
, c
->transactions
, i
) {
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. */
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
;
210 case DNS_TRANSACTION_SUCCESS
:
215 if (state
!= DNS_TRANSACTION_SUCCESS
)
225 static int dns_query_candidate_setup_transactions(DnsQueryCandidate
*c
) {
226 DnsQuestion
*question
;
232 dns_query_candidate_stop(c
);
234 question
= dns_query_question_for_protocol(c
->query
, c
->scope
->protocol
);
236 /* Create one transaction per question key */
237 DNS_QUESTION_FOREACH(key
, question
) {
238 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*new_key
= NULL
;
240 if (c
->search_domain
) {
241 r
= dns_resource_key_new_append_suffix(&new_key
, key
, c
->search_domain
->name
);
246 r
= dns_query_candidate_add_transaction(c
, new_key
?: key
);
256 dns_query_candidate_stop(c
);
260 void dns_query_candidate_notify(DnsQueryCandidate
*c
) {
261 DnsTransactionState state
;
266 state
= dns_query_candidate_state(c
);
268 if (DNS_TRANSACTION_IS_LIVE(state
))
271 if (state
!= DNS_TRANSACTION_SUCCESS
&& c
->search_domain
) {
273 r
= dns_query_candidate_next_search_domain(c
);
278 /* OK, there's another search domain to try, let's do so. */
280 r
= dns_query_candidate_setup_transactions(c
);
285 /* New transactions where queued. Start them and wait */
287 r
= dns_query_candidate_go(c
);
297 dns_query_ready(c
->query
);
301 log_warning_errno(r
, "Failed to follow search domains: %m");
303 dns_query_ready(c
->query
);
306 static void dns_query_stop(DnsQuery
*q
) {
307 DnsQueryCandidate
*c
;
311 q
->timeout_event_source
= sd_event_source_unref(q
->timeout_event_source
);
313 LIST_FOREACH(candidates_by_query
, c
, q
->candidates
)
314 dns_query_candidate_stop(c
);
317 static void dns_query_free_candidates(DnsQuery
*q
) {
320 while (q
->candidates
)
321 dns_query_candidate_free(q
->candidates
);
324 static void dns_query_reset_answer(DnsQuery
*q
) {
327 q
->answer
= dns_answer_unref(q
->answer
);
329 q
->answer_dnssec_result
= _DNSSEC_RESULT_INVALID
;
331 q
->answer_authenticated
= false;
332 q
->answer_protocol
= _DNS_PROTOCOL_INVALID
;
333 q
->answer_family
= AF_UNSPEC
;
334 q
->answer_search_domain
= dns_search_domain_unref(q
->answer_search_domain
);
337 DnsQuery
*dns_query_free(DnsQuery
*q
) {
341 while (q
->auxiliary_queries
)
342 dns_query_free(q
->auxiliary_queries
);
344 if (q
->auxiliary_for
) {
345 assert(q
->auxiliary_for
->n_auxiliary_queries
> 0);
346 q
->auxiliary_for
->n_auxiliary_queries
--;
347 LIST_REMOVE(auxiliary_queries
, q
->auxiliary_for
->auxiliary_queries
, q
);
350 dns_query_free_candidates(q
);
352 dns_question_unref(q
->question_idna
);
353 dns_question_unref(q
->question_utf8
);
355 dns_query_reset_answer(q
);
357 sd_bus_message_unref(q
->request
);
358 sd_bus_track_unref(q
->bus_track
);
360 free(q
->request_address_string
);
363 LIST_REMOVE(queries
, q
->manager
->dns_queries
, q
);
364 q
->manager
->n_dns_queries
--;
375 DnsQuestion
*question_utf8
,
376 DnsQuestion
*question_idna
,
377 int ifindex
, uint64_t flags
) {
379 _cleanup_(dns_query_freep
) DnsQuery
*q
= NULL
;
386 if (dns_question_size(question_utf8
) > 0) {
387 r
= dns_question_is_valid_for_query(question_utf8
);
396 /* If the IDNA and UTF8 questions are the same, merge their references */
397 r
= dns_question_is_equal(question_idna
, question_utf8
);
401 question_idna
= question_utf8
;
403 if (dns_question_size(question_idna
) > 0) {
404 r
= dns_question_is_valid_for_query(question_idna
);
414 if (!good
) /* don't allow empty queries */
417 if (m
->n_dns_queries
>= QUERIES_MAX
)
420 q
= new0(DnsQuery
, 1);
424 q
->question_utf8
= dns_question_ref(question_utf8
);
425 q
->question_idna
= dns_question_ref(question_idna
);
426 q
->ifindex
= ifindex
;
428 q
->answer_dnssec_result
= _DNSSEC_RESULT_INVALID
;
429 q
->answer_protocol
= _DNS_PROTOCOL_INVALID
;
430 q
->answer_family
= AF_UNSPEC
;
432 /* First dump UTF8 question */
433 DNS_QUESTION_FOREACH(key
, question_utf8
) {
434 _cleanup_free_
char *p
= NULL
;
436 r
= dns_resource_key_to_string(key
, &p
);
440 log_debug("Looking up RR for %s.", strstrip(p
));
443 /* And then dump the IDNA question, but only what hasn't been dumped already through the UTF8 question. */
444 DNS_QUESTION_FOREACH(key
, question_idna
) {
445 _cleanup_free_
char *p
= NULL
;
447 r
= dns_question_contains(question_utf8
, key
);
453 r
= dns_resource_key_to_string(key
, &p
);
457 log_debug("Looking up IDNA RR for %s.", strstrip(p
));
460 LIST_PREPEND(queries
, m
->dns_queries
, q
);
471 int dns_query_make_auxiliary(DnsQuery
*q
, DnsQuery
*auxiliary_for
) {
473 assert(auxiliary_for
);
475 /* Ensure that that the query is not auxiliary yet, and
476 * nothing else is auxiliary to it either */
477 assert(!q
->auxiliary_for
);
478 assert(!q
->auxiliary_queries
);
480 /* Ensure that the unit we shall be made auxiliary for isn't
481 * auxiliary itself */
482 assert(!auxiliary_for
->auxiliary_for
);
484 if (auxiliary_for
->n_auxiliary_queries
>= AUXILIARY_QUERIES_MAX
)
487 LIST_PREPEND(auxiliary_queries
, auxiliary_for
->auxiliary_queries
, q
);
488 q
->auxiliary_for
= auxiliary_for
;
490 auxiliary_for
->n_auxiliary_queries
++;
494 static void dns_query_complete(DnsQuery
*q
, DnsTransactionState state
) {
496 assert(!DNS_TRANSACTION_IS_LIVE(state
));
497 assert(DNS_TRANSACTION_IS_LIVE(q
->state
));
499 /* Note that this call might invalidate the query. Callers
500 * should hence not attempt to access the query or transaction
501 * after calling this function. */
510 static int on_query_timeout(sd_event_source
*s
, usec_t usec
, void *userdata
) {
511 DnsQuery
*q
= userdata
;
516 dns_query_complete(q
, DNS_TRANSACTION_TIMEOUT
);
520 static int dns_query_add_candidate(DnsQuery
*q
, DnsScope
*s
) {
521 DnsQueryCandidate
*c
;
527 r
= dns_query_candidate_new(&c
, q
, s
);
531 /* If this a single-label domain on DNS, we might append a suitable search domain first. */
532 if ((q
->flags
& SD_RESOLVED_NO_SEARCH
) == 0) {
533 r
= dns_scope_name_needs_search_domain(s
, dns_question_first_name(q
->question_idna
));
537 /* OK, we need a search domain now. Let's find one for this scope */
539 r
= dns_query_candidate_next_search_domain(c
);
540 if (r
<= 0) /* if there's no search domain, then we won't add any transaction. */
545 r
= dns_query_candidate_setup_transactions(c
);
552 dns_query_candidate_free(c
);
556 static int dns_query_synthesize_reply(DnsQuery
*q
, DnsTransactionState
*state
) {
557 _cleanup_(dns_answer_unrefp
) DnsAnswer
*answer
= NULL
;
563 /* Tries to synthesize localhost RR replies (and others) where appropriate. Note that this is done *after* the
564 * the normal lookup finished. The data from the network hence takes precedence over the data we
565 * synthesize. (But note that many scopes refuse to resolve certain domain names) */
568 DNS_TRANSACTION_RCODE_FAILURE
,
569 DNS_TRANSACTION_NO_SERVERS
,
570 DNS_TRANSACTION_TIMEOUT
,
571 DNS_TRANSACTION_ATTEMPTS_MAX_REACHED
,
572 DNS_TRANSACTION_NETWORK_DOWN
,
573 DNS_TRANSACTION_NOT_FOUND
))
576 r
= dns_synthesize_answer(
585 dns_query_reset_answer(q
);
589 q
->answer_rcode
= DNS_RCODE_SUCCESS
;
590 q
->answer_protocol
= dns_synthesize_protocol(q
->flags
);
591 q
->answer_family
= dns_synthesize_family(q
->flags
);
592 q
->answer_authenticated
= true;
594 *state
= DNS_TRANSACTION_SUCCESS
;
599 static int dns_query_try_etc_hosts(DnsQuery
*q
) {
600 _cleanup_(dns_answer_unrefp
) DnsAnswer
*answer
= NULL
;
605 /* Looks in /etc/hosts for matching entries. Note that this is done *before* the normal lookup is done. The
606 * data from /etc/hosts hence takes precedence over the network. */
608 r
= manager_etc_hosts_lookup(
615 dns_query_reset_answer(q
);
619 q
->answer_rcode
= DNS_RCODE_SUCCESS
;
620 q
->answer_protocol
= dns_synthesize_protocol(q
->flags
);
621 q
->answer_family
= dns_synthesize_family(q
->flags
);
622 q
->answer_authenticated
= true;
627 int dns_query_go(DnsQuery
*q
) {
628 DnsScopeMatch found
= DNS_SCOPE_NO
;
629 DnsScope
*s
, *first
= NULL
;
630 DnsQueryCandidate
*c
;
635 if (q
->state
!= DNS_TRANSACTION_NULL
)
638 r
= dns_query_try_etc_hosts(q
);
642 dns_query_complete(q
, DNS_TRANSACTION_SUCCESS
);
646 LIST_FOREACH(scopes
, s
, q
->manager
->dns_scopes
) {
650 name
= dns_question_first_name(dns_query_question_for_protocol(q
, s
->protocol
));
654 match
= dns_scope_good_domain(s
, q
->ifindex
, q
->flags
, name
);
658 if (match
== DNS_SCOPE_NO
)
663 if (match
== DNS_SCOPE_YES
) {
667 assert(match
== DNS_SCOPE_MAYBE
);
674 if (found
== DNS_SCOPE_NO
) {
675 DnsTransactionState state
= DNS_TRANSACTION_NO_SERVERS
;
677 r
= dns_query_synthesize_reply(q
, &state
);
681 dns_query_complete(q
, state
);
685 r
= dns_query_add_candidate(q
, first
);
689 LIST_FOREACH(scopes
, s
, first
->scopes_next
) {
693 name
= dns_question_first_name(dns_query_question_for_protocol(q
, s
->protocol
));
697 match
= dns_scope_good_domain(s
, q
->ifindex
, q
->flags
, name
);
704 r
= dns_query_add_candidate(q
, s
);
709 dns_query_reset_answer(q
);
711 r
= sd_event_add_time(
713 &q
->timeout_event_source
,
714 clock_boottime_or_monotonic(),
715 now(clock_boottime_or_monotonic()) + QUERY_TIMEOUT_USEC
, 0,
716 on_query_timeout
, q
);
720 (void) sd_event_source_set_description(q
->timeout_event_source
, "query-timeout");
722 q
->state
= DNS_TRANSACTION_PENDING
;
725 /* Start the transactions */
726 LIST_FOREACH(candidates_by_query
, c
, q
->candidates
) {
727 r
= dns_query_candidate_go(c
);
744 static void dns_query_accept(DnsQuery
*q
, DnsQueryCandidate
*c
) {
745 DnsTransactionState state
= DNS_TRANSACTION_NO_SERVERS
;
746 bool has_authenticated
= false, has_non_authenticated
= false;
747 DnssecResult dnssec_result_authenticated
= _DNSSEC_RESULT_INVALID
, dnssec_result_non_authenticated
= _DNSSEC_RESULT_INVALID
;
755 r
= dns_query_synthesize_reply(q
, &state
);
759 dns_query_complete(q
, state
);
763 if (c
->error_code
!= 0) {
764 /* If the candidate had an error condition of its own, start with that. */
765 state
= DNS_TRANSACTION_ERRNO
;
766 q
->answer
= dns_answer_unref(q
->answer
);
768 q
->answer_dnssec_result
= _DNSSEC_RESULT_INVALID
;
769 q
->answer_errno
= c
->error_code
;
772 SET_FOREACH(t
, c
->transactions
, i
) {
776 case DNS_TRANSACTION_SUCCESS
: {
777 /* We found a successfuly reply, merge it into the answer */
778 r
= dns_answer_extend(&q
->answer
, t
->answer
);
782 q
->answer_rcode
= t
->answer_rcode
;
785 if (t
->answer_authenticated
) {
786 has_authenticated
= true;
787 dnssec_result_authenticated
= t
->answer_dnssec_result
;
789 has_non_authenticated
= true;
790 dnssec_result_non_authenticated
= t
->answer_dnssec_result
;
793 state
= DNS_TRANSACTION_SUCCESS
;
797 case DNS_TRANSACTION_NULL
:
798 case DNS_TRANSACTION_PENDING
:
799 case DNS_TRANSACTION_VALIDATING
:
800 case DNS_TRANSACTION_ABORTED
:
801 /* Ignore transactions that didn't complete */
805 /* Any kind of failure? Store the data away,
806 * if there's nothing stored yet. */
808 if (state
== DNS_TRANSACTION_SUCCESS
)
811 q
->answer
= dns_answer_unref(q
->answer
);
812 q
->answer_rcode
= t
->answer_rcode
;
813 q
->answer_dnssec_result
= t
->answer_dnssec_result
;
814 q
->answer_errno
= t
->answer_errno
;
821 if (state
== DNS_TRANSACTION_SUCCESS
) {
822 q
->answer_authenticated
= has_authenticated
&& !has_non_authenticated
;
823 q
->answer_dnssec_result
= q
->answer_authenticated
? dnssec_result_authenticated
: dnssec_result_non_authenticated
;
826 q
->answer_protocol
= c
->scope
->protocol
;
827 q
->answer_family
= c
->scope
->family
;
829 dns_search_domain_unref(q
->answer_search_domain
);
830 q
->answer_search_domain
= dns_search_domain_ref(c
->search_domain
);
832 r
= dns_query_synthesize_reply(q
, &state
);
836 dns_query_complete(q
, state
);
840 q
->answer_errno
= -r
;
841 dns_query_complete(q
, DNS_TRANSACTION_ERRNO
);
844 void dns_query_ready(DnsQuery
*q
) {
846 DnsQueryCandidate
*bad
= NULL
, *c
;
847 bool pending
= false;
850 assert(DNS_TRANSACTION_IS_LIVE(q
->state
));
852 /* Note that this call might invalidate the query. Callers
853 * should hence not attempt to access the query or transaction
854 * after calling this function, unless the block_ready
855 * counter was explicitly bumped before doing so. */
857 if (q
->block_ready
> 0)
860 LIST_FOREACH(candidates_by_query
, c
, q
->candidates
) {
861 DnsTransactionState state
;
863 state
= dns_query_candidate_state(c
);
866 case DNS_TRANSACTION_SUCCESS
:
867 /* One of the candidates is successful,
868 * let's use it, and copy its data out */
869 dns_query_accept(q
, c
);
872 case DNS_TRANSACTION_NULL
:
873 case DNS_TRANSACTION_PENDING
:
874 case DNS_TRANSACTION_VALIDATING
:
875 /* One of the candidates is still going on,
876 * let's maybe wait for it */
881 /* Any kind of failure */
890 dns_query_accept(q
, bad
);
893 static int dns_query_cname_redirect(DnsQuery
*q
, const DnsResourceRecord
*cname
) {
894 _cleanup_(dns_question_unrefp
) DnsQuestion
*nq_idna
= NULL
, *nq_utf8
= NULL
;
899 q
->n_cname_redirects
++;
900 if (q
->n_cname_redirects
> CNAME_MAX
)
903 r
= dns_question_cname_redirect(q
->question_idna
, cname
, &nq_idna
);
907 log_debug("Following CNAME/DNAME %s → %s.", dns_question_first_name(q
->question_idna
), dns_question_first_name(nq_idna
));
909 k
= dns_question_is_equal(q
->question_idna
, q
->question_utf8
);
913 /* Same question? Shortcut new question generation */
914 nq_utf8
= dns_question_ref(nq_idna
);
917 k
= dns_question_cname_redirect(q
->question_utf8
, cname
, &nq_utf8
);
921 log_debug("Following UTF8 CNAME/DNAME %s → %s.", dns_question_first_name(q
->question_utf8
), dns_question_first_name(nq_utf8
));
924 if (r
== 0 && k
== 0) /* No actual cname happened? */
927 dns_question_unref(q
->question_idna
);
928 q
->question_idna
= nq_idna
;
931 dns_question_unref(q
->question_utf8
);
932 q
->question_utf8
= nq_utf8
;
935 dns_query_free_candidates(q
);
936 dns_query_reset_answer(q
);
937 q
->state
= DNS_TRANSACTION_NULL
;
939 /* Turn off searching for the new name */
940 q
->flags
|= SD_RESOLVED_NO_SEARCH
;
945 int dns_query_process_cname(DnsQuery
*q
) {
946 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*cname
= NULL
;
947 DnsQuestion
*question
;
948 DnsResourceRecord
*rr
;
953 if (!IN_SET(q
->state
, DNS_TRANSACTION_SUCCESS
, DNS_TRANSACTION_NULL
))
954 return DNS_QUERY_NOMATCH
;
956 question
= dns_query_question_for_protocol(q
, q
->answer_protocol
);
958 DNS_ANSWER_FOREACH(rr
, q
->answer
) {
959 r
= dns_question_matches_rr(question
, rr
, DNS_SEARCH_DOMAIN_NAME(q
->answer_search_domain
));
963 return DNS_QUERY_MATCH
; /* The answer matches directly, no need to follow cnames */
965 r
= dns_question_matches_cname_or_dname(question
, rr
, DNS_SEARCH_DOMAIN_NAME(q
->answer_search_domain
));
969 cname
= dns_resource_record_ref(rr
);
973 return DNS_QUERY_NOMATCH
; /* No match and no cname to follow */
975 if (q
->flags
& SD_RESOLVED_NO_CNAME
)
978 /* OK, let's actually follow the CNAME */
979 r
= dns_query_cname_redirect(q
, cname
);
983 /* Let's see if the answer can already answer the new
984 * redirected question */
985 r
= dns_query_process_cname(q
);
986 if (r
!= DNS_QUERY_NOMATCH
)
989 /* OK, it cannot, let's begin with the new query */
994 return DNS_QUERY_RESTARTED
; /* We restarted the query for a new cname */
997 static int on_bus_track(sd_bus_track
*t
, void *userdata
) {
998 DnsQuery
*q
= userdata
;
1003 log_debug("Client of active query vanished, aborting query.");
1004 dns_query_complete(q
, DNS_TRANSACTION_ABORTED
);
1008 int dns_query_bus_track(DnsQuery
*q
, sd_bus_message
*m
) {
1014 if (!q
->bus_track
) {
1015 r
= sd_bus_track_new(sd_bus_message_get_bus(m
), &q
->bus_track
, on_bus_track
, q
);
1020 r
= sd_bus_track_add_sender(q
->bus_track
, m
);
1027 DnsQuestion
* dns_query_question_for_protocol(DnsQuery
*q
, DnsProtocol protocol
) {
1032 case DNS_PROTOCOL_DNS
:
1033 return q
->question_idna
;
1035 case DNS_PROTOCOL_MDNS
:
1036 case DNS_PROTOCOL_LLMNR
:
1037 return q
->question_utf8
;
1044 const char *dns_query_string(DnsQuery
*q
) {
1048 /* Returns a somewhat useful human-readable lookup key string for this query */
1050 if (q
->request_address_string
)
1051 return q
->request_address_string
;
1053 if (q
->request_address_valid
) {
1054 r
= in_addr_to_string(q
->request_family
, &q
->request_address
, &q
->request_address_string
);
1056 return q
->request_address_string
;
1059 name
= dns_question_first_name(q
->question_utf8
);
1063 return dns_question_first_name(q
->question_idna
);