| /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
| #pragma once |
| |
| #include "sd-bus.h" |
| |
| #include "set.h" |
| #include "varlink.h" |
| |
| typedef struct DnsQueryCandidate DnsQueryCandidate; |
| typedef struct DnsQuery DnsQuery; |
| typedef struct DnsStubListenerExtra DnsStubListenerExtra; |
| |
| #include "resolved-dns-answer.h" |
| #include "resolved-dns-question.h" |
| #include "resolved-dns-search-domain.h" |
| #include "resolved-dns-transaction.h" |
| |
| struct DnsQueryCandidate { |
| unsigned n_ref; |
| int error_code; |
| |
| DnsQuery *query; |
| DnsScope *scope; |
| |
| DnsSearchDomain *search_domain; |
| |
| Set *transactions; |
| |
| LIST_FIELDS(DnsQueryCandidate, candidates_by_query); |
| LIST_FIELDS(DnsQueryCandidate, candidates_by_scope); |
| }; |
| |
| struct DnsQuery { |
| Manager *manager; |
| |
| /* The question, formatted in IDNA for use on classic DNS, and as UTF8 for use in LLMNR or mDNS. Note |
| * that even on classic DNS some labels might use UTF8 encoding. Specifically, DNS-SD service names |
| * (in contrast to their domain suffixes) use UTF-8 encoding even on DNS. Thus, the difference |
| * between these two fields is mostly relevant only for explicit *hostname* lookups as well as the |
| * domain suffixes of service lookups. |
| * |
| * Note that questions may consist of multiple RR keys at once, but they must be for the same domain |
| * name. This is used for A+AAAA and TXT+SRV lookups: we'll allocate a single DnsQuery object for |
| * them instead of two separate ones. That allows us minor optimizations with response handling: |
| * CNAME/DNAMEs of the first reply we get can already be used to follow the CNAME/DNAME chain for |
| * both, and we can take benefit of server replies that oftentimes put A responses into AAAA queries |
| * and vice versa (in the additional section). */ |
| DnsQuestion *question_idna; |
| DnsQuestion *question_utf8; |
| |
| /* If this is not a question by ourselves, but a "bypass" request, we propagate the original packet |
| * here, and use that instead. */ |
| DnsPacket *question_bypass; |
| |
| uint64_t flags; |
| int ifindex; |
| |
| /* When resolving a service, we first create a TXT+SRV query, and then for the hostnames we discover |
| * auxiliary A+AAAA queries. This pointer always points from the auxiliary queries back to the |
| * TXT+SRV query. */ |
| int auxiliary_result; |
| DnsQuery *auxiliary_for; |
| LIST_HEAD(DnsQuery, auxiliary_queries); |
| |
| LIST_HEAD(DnsQueryCandidate, candidates); |
| sd_event_source *timeout_event_source; |
| |
| /* Discovered data */ |
| DnsAnswer *answer; |
| int answer_rcode; |
| DnssecResult answer_dnssec_result; |
| uint64_t answer_query_flags; |
| DnsProtocol answer_protocol; |
| int answer_family; |
| DnsPacket *answer_full_packet; |
| DnsSearchDomain *answer_search_domain; |
| |
| DnsTransactionState state; |
| int answer_errno; /* if state is DNS_TRANSACTION_ERRNO */ |
| |
| unsigned block_ready; |
| |
| uint8_t n_auxiliary_queries; |
| uint8_t n_cname_redirects; |
| |
| bool previous_redirect_unauthenticated:1; |
| bool previous_redirect_non_confidential:1; |
| bool previous_redirect_non_synthetic:1; |
| bool request_address_valid:1; |
| |
| /* Bus + Varlink client information */ |
| sd_bus_message *bus_request; |
| Varlink *varlink_request; |
| int request_family; |
| union in_addr_union request_address; |
| unsigned block_all_complete; |
| char *request_address_string; |
| |
| /* DNS stub information */ |
| DnsPacket *request_packet; |
| DnsStream *request_stream; |
| DnsAnswer *reply_answer; |
| DnsAnswer *reply_authoritative; |
| DnsAnswer *reply_additional; |
| DnsStubListenerExtra *stub_listener_extra; |
| |
| /* Completion callback */ |
| void (*complete)(DnsQuery* q); |
| |
| sd_bus_track *bus_track; |
| |
| LIST_FIELDS(DnsQuery, queries); |
| LIST_FIELDS(DnsQuery, auxiliary_queries); |
| |
| /* Note: fields should be ordered to minimize alignment gaps. Use pahole! */ |
| }; |
| |
| enum { |
| DNS_QUERY_MATCH, |
| DNS_QUERY_NOMATCH, |
| DNS_QUERY_CNAME, |
| }; |
| |
| DnsQueryCandidate* dns_query_candidate_ref(DnsQueryCandidate*); |
| DnsQueryCandidate* dns_query_candidate_unref(DnsQueryCandidate*); |
| DEFINE_TRIVIAL_CLEANUP_FUNC(DnsQueryCandidate*, dns_query_candidate_unref); |
| |
| void dns_query_candidate_notify(DnsQueryCandidate *c); |
| |
| int dns_query_new(Manager *m, DnsQuery **q, DnsQuestion *question_utf8, DnsQuestion *question_idna, DnsPacket *question_bypass, int family, uint64_t flags); |
| DnsQuery *dns_query_free(DnsQuery *q); |
| |
| int dns_query_make_auxiliary(DnsQuery *q, DnsQuery *auxiliary_for); |
| |
| int dns_query_go(DnsQuery *q); |
| void dns_query_ready(DnsQuery *q); |
| |
| int dns_query_process_cname_one(DnsQuery *q); |
| int dns_query_process_cname_many(DnsQuery *q); |
| |
| void dns_query_complete(DnsQuery *q, DnsTransactionState state); |
| |
| DnsQuestion* dns_query_question_for_protocol(DnsQuery *q, DnsProtocol protocol); |
| |
| const char *dns_query_string(DnsQuery *q); |
| |
| DEFINE_TRIVIAL_CLEANUP_FUNC(DnsQuery*, dns_query_free); |
| |
| bool dns_query_fully_authenticated(DnsQuery *q); |
| bool dns_query_fully_confidential(DnsQuery *q); |
| bool dns_query_fully_authoritative(DnsQuery *q); |
| |
| static inline uint64_t dns_query_reply_flags_make(DnsQuery *q) { |
| assert(q); |
| |
| return SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, |
| q->answer_family, |
| dns_query_fully_authenticated(q), |
| dns_query_fully_confidential(q)) | |
| (q->answer_query_flags & (SD_RESOLVED_FROM_MASK|SD_RESOLVED_SYNTHETIC)); |
| } |