1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
4 #include "in-addr-util.h"
6 #include "resolved-dns-packet.h"
7 #include "resolved-dns-transaction.h"
8 #include "resolved-forward.h"
10 typedef struct DnsQueryCandidate
{
18 DnsSearchDomain
*search_domain
;
21 sd_event_source
*timeout_event_source
;
23 LIST_FIELDS(DnsQueryCandidate
, candidates_by_query
);
24 LIST_FIELDS(DnsQueryCandidate
, candidates_by_scope
);
27 typedef struct DnsQuery
{
30 /* The question, formatted in IDNA for use on classic DNS, and as UTF8 for use in LLMNR or mDNS. Note
31 * that even on classic DNS some labels might use UTF8 encoding. Specifically, DNS-SD service names
32 * (in contrast to their domain suffixes) use UTF-8 encoding even on DNS. Thus, the difference
33 * between these two fields is mostly relevant only for explicit *hostname* lookups as well as the
34 * domain suffixes of service lookups.
36 * Note that questions may consist of multiple RR keys at once, but they must be for the same domain
37 * name. This is used for A+AAAA and TXT+SRV lookups: we'll allocate a single DnsQuery object for
38 * them instead of two separate ones. That allows us minor optimizations with response handling:
39 * CNAME/DNAMEs of the first reply we get can already be used to follow the CNAME/DNAME chain for
40 * both, and we can take benefit of server replies that oftentimes put A responses into AAAA queries
41 * and vice versa (in the additional section). */
42 DnsQuestion
*question_idna
;
43 DnsQuestion
*question_utf8
;
45 /* If this is not a question by ourselves, but a "bypass" request, we propagate the original packet
46 * here, and use that instead. */
47 DnsPacket
*question_bypass
;
49 /* When we follow a CNAME redirect, we save the original question here, for informational/monitoring
50 * purposes. We'll keep adding to this whenever we go one step in the redirect, so that in the end
51 * this will contain the complete set of CNAME questions. */
52 DnsQuestion
*collected_questions
;
57 /* When resolving a service, we first create a TXT+SRV query, and then for the hostnames we discover
58 * auxiliary A+AAAA queries. This pointer always points from the auxiliary queries back to the
61 DnsQuery
*auxiliary_for
;
62 LIST_HEAD(DnsQuery
, auxiliary_queries
);
64 LIST_HEAD(DnsQueryCandidate
, candidates
);
65 sd_event_source
*timeout_event_source
;
72 DnssecResult answer_dnssec_result
;
73 uint64_t answer_query_flags
;
74 DnsProtocol answer_protocol
;
76 DnsPacket
*answer_full_packet
;
77 DnsSearchDomain
*answer_search_domain
;
79 DnsTransactionState state
;
80 int answer_errno
; /* if state is DNS_TRANSACTION_ERRNO */
84 uint8_t n_auxiliary_queries
;
85 uint8_t n_cname_redirects
;
87 bool previous_redirect_unauthenticated
:1;
88 bool previous_redirect_non_confidential
:1;
89 bool previous_redirect_non_synthetic
:1;
90 bool request_address_valid
:1;
92 /* Bus + Varlink client information */
93 sd_bus_message
*bus_request
;
94 sd_varlink
*varlink_request
;
96 union in_addr_union request_address
;
97 unsigned block_all_complete
;
98 char *request_address_string
;
100 /* DNS stub information */
101 DnsPacket
*request_packet
;
102 DnsStream
*request_stream
;
103 DnsAnswer
*reply_answer
;
104 DnsAnswer
*reply_authoritative
;
105 DnsAnswer
*reply_additional
;
106 DnsStubListenerExtra
*stub_listener_extra
;
108 /* Completion callback */
109 void (*complete
)(DnsQuery
* q
);
111 sd_bus_track
*bus_track
;
113 LIST_FIELDS(DnsQuery
, queries
);
114 LIST_FIELDS(DnsQuery
, auxiliary_queries
);
116 /* Note: fields should be ordered to minimize alignment gaps. Use pahole! */
125 DnsQueryCandidate
* dns_query_candidate_ref(DnsQueryCandidate
*);
126 DnsQueryCandidate
* dns_query_candidate_unref(DnsQueryCandidate
*);
127 DEFINE_TRIVIAL_CLEANUP_FUNC(DnsQueryCandidate
*, dns_query_candidate_unref
);
129 void dns_query_candidate_notify(DnsQueryCandidate
*c
);
131 int dns_query_new(Manager
*m
, DnsQuery
**q
, DnsQuestion
*question_utf8
, DnsQuestion
*question_idna
, DnsPacket
*question_bypass
, int family
, uint64_t flags
);
132 DnsQuery
*dns_query_free(DnsQuery
*q
);
134 int dns_query_make_auxiliary(DnsQuery
*q
, DnsQuery
*auxiliary_for
);
136 int dns_query_go(DnsQuery
*q
);
137 void dns_query_ready(DnsQuery
*q
);
139 int dns_query_process_cname_one(DnsQuery
*q
);
140 int dns_query_process_cname_many(DnsQuery
*q
);
142 void dns_query_complete(DnsQuery
*q
, DnsTransactionState state
);
144 DnsQuestion
* dns_query_question_for_protocol(DnsQuery
*q
, DnsProtocol protocol
);
146 const char* dns_query_string(DnsQuery
*q
);
148 DEFINE_TRIVIAL_CLEANUP_FUNC(DnsQuery
*, dns_query_free
);
150 bool dns_query_fully_authenticated(DnsQuery
*q
);
151 bool dns_query_fully_confidential(DnsQuery
*q
);
152 bool dns_query_fully_authoritative(DnsQuery
*q
);
154 int validate_and_mangle_query_flags(Manager
*manager
, uint64_t *flags
, const char *name
, uint64_t ok
);
156 uint64_t dns_query_reply_flags_make(DnsQuery
*q
);