Systemd/src/resolve/resolved-dns-server.h

165 lines
5.2 KiB
C
Raw Normal View History

/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
2014-07-18 13:59:49 +02:00
#include "in-addr-util.h"
2020-05-06 19:10:59 +02:00
#include "list.h"
#include "resolve-util.h"
#include "time-util.h"
2014-07-18 13:59:49 +02:00
2020-05-06 19:10:59 +02:00
typedef struct DnsScope DnsScope;
typedef struct DnsServer DnsServer;
2020-05-06 19:10:59 +02:00
typedef struct DnsStream DnsStream;
typedef struct DnsPacket DnsPacket;
typedef struct Link Link;
typedef struct Manager Manager;
#include "resolved-dnstls.h"
typedef enum DnsServerType {
DNS_SERVER_SYSTEM,
DNS_SERVER_FALLBACK,
DNS_SERVER_LINK,
_DNS_SERVER_TYPE_MAX,
_DNS_SERVER_TYPE_INVALID = -1
} DnsServerType;
const char* dns_server_type_to_string(DnsServerType i) _const_;
DnsServerType dns_server_type_from_string(const char *s) _pure_;
typedef enum DnsServerFeatureLevel {
DNS_SERVER_FEATURE_LEVEL_TCP,
DNS_SERVER_FEATURE_LEVEL_UDP,
DNS_SERVER_FEATURE_LEVEL_EDNS0,
DNS_SERVER_FEATURE_LEVEL_TLS_PLAIN,
DNS_SERVER_FEATURE_LEVEL_DO,
DNS_SERVER_FEATURE_LEVEL_LARGE,
DNS_SERVER_FEATURE_LEVEL_TLS_DO,
_DNS_SERVER_FEATURE_LEVEL_MAX,
_DNS_SERVER_FEATURE_LEVEL_INVALID = -1
} DnsServerFeatureLevel;
#define DNS_SERVER_FEATURE_LEVEL_WORST 0
#define DNS_SERVER_FEATURE_LEVEL_BEST (_DNS_SERVER_FEATURE_LEVEL_MAX - 1)
#define DNS_SERVER_FEATURE_LEVEL_IS_TLS(x) IN_SET(x, DNS_SERVER_FEATURE_LEVEL_TLS_PLAIN, DNS_SERVER_FEATURE_LEVEL_TLS_DO)
const char* dns_server_feature_level_to_string(int i) _const_;
int dns_server_feature_level_from_string(const char *s) _pure_;
struct DnsServer {
Manager *manager;
unsigned n_ref;
DnsServerType type;
2014-07-18 13:59:49 +02:00
Link *link;
int family;
union in_addr_union address;
int ifindex; /* for IPv6 link-local DNS servers */
uint16_t port;
char *server_name;
char *server_string;
char *server_string_full;
2018-12-04 20:52:43 +01:00
/* The long-lived stream towards this server. */
DnsStream *stream;
#if ENABLE_DNS_OVER_TLS
DnsTlsServerData dnstls_data;
#endif
DnsServerFeatureLevel verified_feature_level;
DnsServerFeatureLevel possible_feature_level;
size_t received_udp_packet_max;
unsigned n_failed_udp;
unsigned n_failed_tcp;
unsigned n_failed_tls;
bool packet_truncated:1;
bool packet_bad_opt:1;
bool packet_rrsig_missing:1;
usec_t verified_usec;
usec_t features_grace_period_usec;
/* Whether we already warned about downgrading to non-DNSSEC mode for this server */
bool warned_downgrade:1;
/* Used when GC'ing old DNS servers when configuration changes. */
bool marked:1;
/* If linked is set, then this server appears in the servers linked list */
bool linked:1;
LIST_FIELDS(DnsServer, servers);
};
int dns_server_new(
Manager *m,
DnsServer **ret,
DnsServerType type,
Link *link,
int family,
const union in_addr_union *address,
uint16_t port,
int ifindex,
const char *server_string);
DnsServer* dns_server_ref(DnsServer *s);
DnsServer* dns_server_unref(DnsServer *s);
void dns_server_unlink(DnsServer *s);
void dns_server_move_back_and_unmark(DnsServer *s);
resolve: do not derive query timeout from RTT DNS queries need timeout values to detect whether a DNS server is unresponsive or, if the query is sent over UDP, whether a DNS message was lost and has to be resent. The total time that it takes to answer a query to arrive is t + RTT, where t is the maximum time that the DNS server that is being queried needs to answer the query. An authoritative server stores a copy of the zone that it serves in main memory or secondary storage, so t is very small and therefore the time that it takes to answer a query is almost entirely determined by the RTT. Modern authoritative server software keeps its zones in main memory and, for example, Knot DNS and NSD are able to answer in less than 100 µs [1]. So iterative resolvers continuously measure the RTT to optimize their query timeouts and to resend queries more quickly if they are lost. systemd-resolved is a stub resolver: it forwards DNS queries to an upstream resolver and waits for an answer. So the time that it takes for systemd-resolved to answer a query is determined by the RTT and the time that it takes the upstream resolver to answer the query. It seems common for iterative resolver software to set a total timeout for the query. Such total timeout subsumes the timeout of all queries that the iterative has to make to answer a query. For example, BIND seems to use a default timeout of 10 s. At the moment systemd-resolved derives its query timeout entirely from the RTT and does not consider the query timeout of the upstream resolver. Therefore it often mistakenly degrades the feature set of its upstream resolvers if it takes them longer than usual to answer a query. It has been reported to be a considerable problem in practice, in particular if DNSSEC=yes. So the query timeout systemd-resolved should be derived from the timeout of the upstream resolved and the RTT to the upstream resolver. At the moment systemd-resolved measures the RTT as the time that it takes the upstream resolver to answer a query. This clearly leads to incorrect measurements. In order to correctly measure the RTT systemd-resolved would have to measure RTT separately and continuously, for example with a query with an empty question section or a query for the SOA RR of the root zone so that the upstream resolver would be able to answer to query without querying another server. However, this requires significant changes to systemd-resolved. So it seems best to postpone them until other issues have been addressed and to set the resend timeout to a fixed value for now. As mentioned, BIND seems to use a timeout of 10 s, so perhaps 12 s is a reasonable value that also accounts for common RTT values. If we assume that the we are going to retry, it could be less. So it should be enough to set the resend timeout to DNS_TIMEOUT_MAX_USEC as DNS_SERVER_FEATURE_RETRY_ATTEMPTS * DNS_TIMEOUT_MAX_USEC = 15 s. However, this will not solve the incorrect feature set degradation and should be seen as a temporary change until systemd-resolved does probe the feature set of an upstream resolver independently from the actual queries. [1] https://www.knot-dns.cz/benchmark/
2018-06-11 20:07:36 +02:00
void dns_server_packet_received(DnsServer *s, int protocol, DnsServerFeatureLevel level, size_t size);
void dns_server_packet_lost(DnsServer *s, int protocol, DnsServerFeatureLevel level);
void dns_server_packet_truncated(DnsServer *s, DnsServerFeatureLevel level);
void dns_server_packet_rrsig_missing(DnsServer *s, DnsServerFeatureLevel level);
void dns_server_packet_bad_opt(DnsServer *s, DnsServerFeatureLevel level);
void dns_server_packet_rcode_downgrade(DnsServer *s, DnsServerFeatureLevel level);
DnsServerFeatureLevel dns_server_possible_feature_level(DnsServer *s);
int dns_server_adjust_opt(DnsServer *server, DnsPacket *packet, DnsServerFeatureLevel level);
const char *dns_server_string(DnsServer *server);
const char *dns_server_string_full(DnsServer *server);
int dns_server_ifindex(const DnsServer *s);
uint16_t dns_server_port(const DnsServer *s);
bool dns_server_dnssec_supported(DnsServer *server);
void dns_server_warn_downgrade(DnsServer *server);
DnsServer *dns_server_find(DnsServer *first, int family, const union in_addr_union *in_addr, uint16_t port, int ifindex, const char *name);
void dns_server_unlink_all(DnsServer *first);
void dns_server_unlink_marked(DnsServer *first);
void dns_server_mark_all(DnsServer *first);
DnsServer *manager_get_first_dns_server(Manager *m, DnsServerType t);
DnsServer *manager_set_dns_server(Manager *m, DnsServer *s);
DnsServer *manager_get_dns_server(Manager *m);
void manager_next_dns_server(Manager *m);
DnssecMode dns_server_get_dnssec_mode(DnsServer *s);
DnsOverTlsMode dns_server_get_dns_over_tls_mode(DnsServer *s);
DEFINE_TRIVIAL_CLEANUP_FUNC(DnsServer*, dns_server_unref);
extern const struct hash_ops dns_server_hash_ops;
void dns_server_flush_cache(DnsServer *s);
void dns_server_reset_features(DnsServer *s);
void dns_server_reset_features_all(DnsServer *s);
void dns_server_dump(DnsServer *s, FILE *f);
void dns_server_unref_stream(DnsServer *s);
DnsScope *dns_server_scope(DnsServer *s);