Merge pull request #2043 from teg/resolved-edns0-5
resolved: add edns0 support
This commit is contained in:
@@ -28,6 +28,8 @@
|
||||
#include "utf8.h"
|
||||
#include "util.h"
|
||||
|
||||
#define EDNS0_OPT_DO (1<<15)
|
||||
|
||||
int dns_packet_new(DnsPacket **ret, DnsProtocol protocol, size_t mtu) {
|
||||
DnsPacket *p;
|
||||
size_t a;
|
||||
@@ -267,7 +269,7 @@ static int dns_packet_extend(DnsPacket *p, size_t add, void **ret, size_t *start
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dns_packet_truncate(DnsPacket *p, size_t sz) {
|
||||
void dns_packet_truncate(DnsPacket *p, size_t sz) {
|
||||
Iterator i;
|
||||
char *s;
|
||||
void *n;
|
||||
@@ -609,6 +611,57 @@ fail:
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Append the OPT pseudo-RR described in RFC6891 */
|
||||
int dns_packet_append_opt_rr(DnsPacket *p, uint16_t max_udp_size, bool edns0_do, size_t *start) {
|
||||
size_t saved_size;
|
||||
int r;
|
||||
|
||||
assert(p);
|
||||
/* we must never advertise supported packet size smaller than the legacy max */
|
||||
assert(max_udp_size >= DNS_PACKET_UNICAST_SIZE_MAX);
|
||||
|
||||
saved_size = p->size;
|
||||
|
||||
/* empty name */
|
||||
r = dns_packet_append_uint8(p, 0, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* type */
|
||||
r = dns_packet_append_uint16(p, DNS_TYPE_OPT, NULL);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
/* maximum udp packet that can be received */
|
||||
r = dns_packet_append_uint16(p, max_udp_size, NULL);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
/* extended RCODE and VERSION */
|
||||
r = dns_packet_append_uint16(p, 0, NULL);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
/* flags: DNSSEC OK (DO), see RFC3225 */
|
||||
r = dns_packet_append_uint16(p, edns0_do ? EDNS0_OPT_DO : 0, NULL);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
/* RDLENGTH */
|
||||
r = dns_packet_append_uint16(p, 0, NULL);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
if (start)
|
||||
*start = saved_size;
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
dns_packet_truncate(p, saved_size);
|
||||
return r;
|
||||
}
|
||||
|
||||
int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *start) {
|
||||
size_t saved_size, rdlength_offset, end, rdlength;
|
||||
int r;
|
||||
@@ -1450,6 +1503,10 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) {
|
||||
r = dns_packet_read_name(p, &rr->ptr.name, true, NULL);
|
||||
break;
|
||||
|
||||
case DNS_TYPE_OPT: /* we only care about the header */
|
||||
r = 0;
|
||||
break;
|
||||
|
||||
case DNS_TYPE_HINFO:
|
||||
r = dns_packet_read_string(p, &rr->hinfo.cpu, NULL);
|
||||
if (r < 0)
|
||||
|
||||
@@ -65,6 +65,9 @@ struct DnsPacketHeader {
|
||||
/* RFC 1035 say 512 is the maximum, for classic unicast DNS */
|
||||
#define DNS_PACKET_UNICAST_SIZE_MAX 512
|
||||
|
||||
/* With EDNS0 we can use larger packets, default to 4096, which is what is commonly used */
|
||||
#define DNS_PACKET_UNICAST_SIZE_LARGE_MAX 4096
|
||||
|
||||
#define DNS_PACKET_SIZE_START 512
|
||||
|
||||
struct DnsPacket {
|
||||
@@ -160,6 +163,9 @@ int dns_packet_append_label(DnsPacket *p, const char *s, size_t l, size_t *start
|
||||
int dns_packet_append_name(DnsPacket *p, const char *name, bool allow_compression, size_t *start);
|
||||
int dns_packet_append_key(DnsPacket *p, const DnsResourceKey *key, size_t *start);
|
||||
int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *start);
|
||||
int dns_packet_append_opt_rr(DnsPacket *p, uint16_t max_udp_size, bool edns0_do, size_t *start);
|
||||
|
||||
void dns_packet_truncate(DnsPacket *p, size_t sz);
|
||||
|
||||
int dns_packet_read(DnsPacket *p, size_t sz, const void **ret, size_t *start);
|
||||
int dns_packet_read_blob(DnsPacket *p, void *d, size_t sz, size_t *start);
|
||||
|
||||
@@ -158,12 +158,13 @@ void dns_scope_packet_lost(DnsScope *s, usec_t usec) {
|
||||
s->resend_timeout = MIN(s->resend_timeout * 2, MULTICAST_RESEND_TIMEOUT_MAX_USEC);
|
||||
}
|
||||
|
||||
int dns_scope_emit(DnsScope *s, int fd, DnsPacket *p) {
|
||||
int dns_scope_emit(DnsScope *s, int fd, DnsServer *server, DnsPacket *p) {
|
||||
union in_addr_union addr;
|
||||
int ifindex = 0, r;
|
||||
int family;
|
||||
uint16_t port;
|
||||
uint32_t mtu;
|
||||
size_t saved_size = 0;
|
||||
|
||||
assert(s);
|
||||
assert(p);
|
||||
@@ -178,9 +179,29 @@ int dns_scope_emit(DnsScope *s, int fd, DnsPacket *p) {
|
||||
|
||||
switch (s->protocol) {
|
||||
case DNS_PROTOCOL_DNS:
|
||||
assert(server);
|
||||
|
||||
if (DNS_PACKET_QDCOUNT(p) > 1)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (server->possible_features >= DNS_SERVER_FEATURE_LEVEL_EDNS0) {
|
||||
bool edns_do;
|
||||
size_t packet_size;
|
||||
|
||||
edns_do = server->possible_features >= DNS_SERVER_FEATURE_LEVEL_DO;
|
||||
|
||||
if (server->possible_features >= DNS_SERVER_FEATURE_LEVEL_LARGE)
|
||||
packet_size = DNS_PACKET_UNICAST_SIZE_LARGE_MAX;
|
||||
else
|
||||
packet_size = server->received_udp_packet_max;
|
||||
|
||||
r = dns_packet_append_opt_rr(p, packet_size, edns_do, &saved_size);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
DNS_PACKET_HEADER(p)->arcount = htobe16(be16toh(DNS_PACKET_HEADER(p)->arcount) + 1);
|
||||
}
|
||||
|
||||
if (p->size > DNS_PACKET_UNICAST_SIZE_MAX)
|
||||
return -EMSGSIZE;
|
||||
|
||||
@@ -191,6 +212,12 @@ int dns_scope_emit(DnsScope *s, int fd, DnsPacket *p) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (saved_size > 0) {
|
||||
dns_packet_truncate(p, saved_size);
|
||||
|
||||
DNS_PACKET_HEADER(p)->arcount = htobe16(be16toh(DNS_PACKET_HEADER(p)->arcount) - 1);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case DNS_PROTOCOL_LLMNR:
|
||||
@@ -243,6 +270,11 @@ static int dns_scope_socket(DnsScope *s, int type, int family, const union in_ad
|
||||
if (!srv)
|
||||
return -ESRCH;
|
||||
|
||||
srv->possible_features = dns_server_possible_features(srv);
|
||||
|
||||
if (type == SOCK_DGRAM && srv->possible_features < DNS_SERVER_FEATURE_LEVEL_UDP)
|
||||
return -EAGAIN;
|
||||
|
||||
sa.sa.sa_family = srv->family;
|
||||
if (srv->family == AF_INET) {
|
||||
sa.in.sin_port = htobe16(port);
|
||||
@@ -734,7 +766,7 @@ static int on_conflict_dispatch(sd_event_source *es, usec_t usec, void *userdata
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = dns_scope_emit(scope, -1, p);
|
||||
r = dns_scope_emit(scope, -1, NULL, p);
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "Failed to send conflict packet: %m");
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ DnsScope* dns_scope_free(DnsScope *s);
|
||||
void dns_scope_packet_received(DnsScope *s, usec_t rtt);
|
||||
void dns_scope_packet_lost(DnsScope *s, usec_t usec);
|
||||
|
||||
int dns_scope_emit(DnsScope *s, int fd, DnsPacket *p);
|
||||
int dns_scope_emit(DnsScope *s, int fd, DnsServer *server, DnsPacket *p);
|
||||
int dns_scope_tcp_socket(DnsScope *s, int family, const union in_addr_union *address, uint16_t port, DnsServer **server);
|
||||
int dns_scope_udp_dns_socket(DnsScope *s, DnsServer **server);
|
||||
|
||||
|
||||
@@ -23,12 +23,20 @@
|
||||
#include "resolved-dns-server.h"
|
||||
#include "resolved-resolv-conf.h"
|
||||
#include "siphash24.h"
|
||||
#include "string-table.h"
|
||||
#include "string-util.h"
|
||||
|
||||
/* After how much time to repeat classic DNS requests */
|
||||
#define DNS_TIMEOUT_MIN_USEC (500 * USEC_PER_MSEC)
|
||||
#define DNS_TIMEOUT_MAX_USEC (5 * USEC_PER_SEC)
|
||||
|
||||
/* The amount of time to wait before retrying with a full feature set */
|
||||
#define DNS_SERVER_FEATURE_GRACE_PERIOD_MAX_USEC (6 * USEC_PER_HOUR)
|
||||
#define DNS_SERVER_FEATURE_GRACE_PERIOD_MIN_USEC (5 * USEC_PER_MINUTE)
|
||||
|
||||
/* The number of times we will attempt a certain feature set before degrading */
|
||||
#define DNS_SERVER_FEATURE_RETRY_ATTEMPTS 3
|
||||
|
||||
int dns_server_new(
|
||||
Manager *m,
|
||||
DnsServer **ret,
|
||||
@@ -60,6 +68,10 @@ int dns_server_new(
|
||||
|
||||
s->n_ref = 1;
|
||||
s->manager = m;
|
||||
s->verified_features = _DNS_SERVER_FEATURE_LEVEL_INVALID;
|
||||
s->possible_features = DNS_SERVER_FEATURE_LEVEL_BEST;
|
||||
s->features_grace_period_usec = DNS_SERVER_FEATURE_GRACE_PERIOD_MIN_USEC;
|
||||
s->received_udp_packet_max = DNS_PACKET_UNICAST_SIZE_MAX;
|
||||
s->type = type;
|
||||
s->family = family;
|
||||
s->address = *in_addr;
|
||||
@@ -212,18 +224,43 @@ void dns_server_move_back_and_unmark(DnsServer *s) {
|
||||
}
|
||||
}
|
||||
|
||||
void dns_server_packet_received(DnsServer *s, usec_t rtt) {
|
||||
void dns_server_packet_received(DnsServer *s, DnsServerFeatureLevel features, usec_t rtt, size_t size) {
|
||||
assert(s);
|
||||
|
||||
if (rtt <= s->max_rtt)
|
||||
return;
|
||||
if (features == DNS_SERVER_FEATURE_LEVEL_LARGE) {
|
||||
/* even if we successfully receive a reply to a request announcing
|
||||
support for large packets, that does not mean we can necessarily
|
||||
receive large packets. */
|
||||
if (s->verified_features < DNS_SERVER_FEATURE_LEVEL_LARGE - 1) {
|
||||
s->verified_features = DNS_SERVER_FEATURE_LEVEL_LARGE - 1;
|
||||
assert_se(sd_event_now(s->manager->event, clock_boottime_or_monotonic(), &s->verified_usec) >= 0);
|
||||
}
|
||||
} else if (s->verified_features < features) {
|
||||
s->verified_features = features;
|
||||
assert_se(sd_event_now(s->manager->event, clock_boottime_or_monotonic(), &s->verified_usec) >= 0);
|
||||
}
|
||||
|
||||
s->max_rtt = rtt;
|
||||
s->resend_timeout = MIN(MAX(DNS_TIMEOUT_MIN_USEC, s->max_rtt * 2), DNS_TIMEOUT_MAX_USEC);
|
||||
if (s->possible_features == features)
|
||||
s->n_failed_attempts = 0;
|
||||
|
||||
/* Remember the size of the largest UDP packet we received from a server,
|
||||
we know that we can always announce support for packets with at least
|
||||
this size. */
|
||||
if (s->received_udp_packet_max < size)
|
||||
s->received_udp_packet_max = size;
|
||||
|
||||
if (s->max_rtt < rtt) {
|
||||
s->max_rtt = rtt;
|
||||
s->resend_timeout = MIN(MAX(DNS_TIMEOUT_MIN_USEC, s->max_rtt * 2), DNS_TIMEOUT_MAX_USEC);
|
||||
}
|
||||
}
|
||||
|
||||
void dns_server_packet_lost(DnsServer *s, usec_t usec) {
|
||||
void dns_server_packet_lost(DnsServer *s, DnsServerFeatureLevel features, usec_t usec) {
|
||||
assert(s);
|
||||
assert(s->manager);
|
||||
|
||||
if (s->possible_features == features)
|
||||
s->n_failed_attempts ++;
|
||||
|
||||
if (s->resend_timeout > usec)
|
||||
return;
|
||||
@@ -231,6 +268,66 @@ void dns_server_packet_lost(DnsServer *s, usec_t usec) {
|
||||
s->resend_timeout = MIN(s->resend_timeout * 2, DNS_TIMEOUT_MAX_USEC);
|
||||
}
|
||||
|
||||
void dns_server_packet_failed(DnsServer *s, DnsServerFeatureLevel features) {
|
||||
assert(s);
|
||||
assert(s->manager);
|
||||
|
||||
if (s->possible_features != features)
|
||||
return;
|
||||
|
||||
s->n_failed_attempts = (unsigned) -1;
|
||||
}
|
||||
|
||||
static bool dns_server_grace_period_expired(DnsServer *s) {
|
||||
usec_t ts;
|
||||
|
||||
assert(s);
|
||||
assert(s->manager);
|
||||
|
||||
if (s->verified_usec == 0)
|
||||
return false;
|
||||
|
||||
assert_se(sd_event_now(s->manager->event, clock_boottime_or_monotonic(), &ts) >= 0);
|
||||
|
||||
if (s->verified_usec + s->features_grace_period_usec > ts)
|
||||
return false;
|
||||
|
||||
s->features_grace_period_usec = MIN(s->features_grace_period_usec * 2, DNS_SERVER_FEATURE_GRACE_PERIOD_MAX_USEC);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
DnsServerFeatureLevel dns_server_possible_features(DnsServer *s) {
|
||||
assert(s);
|
||||
|
||||
if (s->possible_features != DNS_SERVER_FEATURE_LEVEL_BEST &&
|
||||
dns_server_grace_period_expired(s)) {
|
||||
_cleanup_free_ char *ip = NULL;
|
||||
|
||||
s->possible_features = DNS_SERVER_FEATURE_LEVEL_BEST;
|
||||
s->n_failed_attempts = 0;
|
||||
s->verified_usec = 0;
|
||||
|
||||
in_addr_to_string(s->family, &s->address, &ip);
|
||||
log_info("Grace period over, resuming full feature set for DNS server %s", strna(ip));
|
||||
} else if (s->possible_features <= s->verified_features)
|
||||
s->possible_features = s->verified_features;
|
||||
else if (s->n_failed_attempts >= DNS_SERVER_FEATURE_RETRY_ATTEMPTS &&
|
||||
s->possible_features > DNS_SERVER_FEATURE_LEVEL_WORST) {
|
||||
_cleanup_free_ char *ip = NULL;
|
||||
|
||||
s->possible_features --;
|
||||
s->n_failed_attempts = 0;
|
||||
s->verified_usec = 0;
|
||||
|
||||
in_addr_to_string(s->family, &s->address, &ip);
|
||||
log_warning("Using degraded feature set (%s) for DNS server %s",
|
||||
dns_server_feature_level_to_string(s->possible_features), strna(ip));
|
||||
}
|
||||
|
||||
return s->possible_features;
|
||||
}
|
||||
|
||||
static void dns_server_hash_func(const void *p, struct siphash *state) {
|
||||
const DnsServer *s = p;
|
||||
|
||||
@@ -392,3 +489,12 @@ void manager_next_dns_server(Manager *m) {
|
||||
else
|
||||
manager_set_dns_server(m, m->dns_servers);
|
||||
}
|
||||
|
||||
static const char* const dns_server_feature_level_table[_DNS_SERVER_FEATURE_LEVEL_MAX] = {
|
||||
[DNS_SERVER_FEATURE_LEVEL_TCP] = "TCP",
|
||||
[DNS_SERVER_FEATURE_LEVEL_UDP] = "UDP",
|
||||
[DNS_SERVER_FEATURE_LEVEL_EDNS0] = "UDP+EDNS0",
|
||||
[DNS_SERVER_FEATURE_LEVEL_DO] = "UDP+EDNS0+DO",
|
||||
[DNS_SERVER_FEATURE_LEVEL_LARGE] = "UDP+EDNS0+DO+LARGE",
|
||||
};
|
||||
DEFINE_STRING_TABLE_LOOKUP(dns_server_feature_level, DnsServerFeatureLevel);
|
||||
|
||||
@@ -31,8 +31,24 @@ typedef enum DnsServerType {
|
||||
DNS_SERVER_LINK,
|
||||
} DnsServerType;
|
||||
|
||||
#include "resolved-manager.h"
|
||||
typedef enum DnsServerFeatureLevel {
|
||||
DNS_SERVER_FEATURE_LEVEL_TCP,
|
||||
DNS_SERVER_FEATURE_LEVEL_UDP,
|
||||
DNS_SERVER_FEATURE_LEVEL_EDNS0,
|
||||
DNS_SERVER_FEATURE_LEVEL_DO,
|
||||
DNS_SERVER_FEATURE_LEVEL_LARGE,
|
||||
_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)
|
||||
|
||||
const char* dns_server_feature_level_to_string(int i) _const_;
|
||||
int dns_server_feature_level_from_string(const char *s) _pure_;
|
||||
|
||||
#include "resolved-link.h"
|
||||
#include "resolved-manager.h"
|
||||
|
||||
struct DnsServer {
|
||||
Manager *manager;
|
||||
@@ -49,6 +65,12 @@ struct DnsServer {
|
||||
usec_t max_rtt;
|
||||
|
||||
bool marked:1;
|
||||
DnsServerFeatureLevel verified_features;
|
||||
DnsServerFeatureLevel possible_features;
|
||||
size_t received_udp_packet_max;
|
||||
unsigned n_failed_attempts;
|
||||
usec_t verified_usec;
|
||||
usec_t features_grace_period_usec;
|
||||
|
||||
/* If linked is set, then this server appears in the servers linked list */
|
||||
bool linked:1;
|
||||
@@ -69,8 +91,9 @@ DnsServer* dns_server_unref(DnsServer *s);
|
||||
void dns_server_unlink(DnsServer *s);
|
||||
void dns_server_move_back_and_unmark(DnsServer *s);
|
||||
|
||||
void dns_server_packet_received(DnsServer *s, usec_t rtt);
|
||||
void dns_server_packet_lost(DnsServer *s, usec_t usec);
|
||||
void dns_server_packet_received(DnsServer *s, DnsServerFeatureLevel features, usec_t rtt, size_t size);
|
||||
void dns_server_packet_lost(DnsServer *s, DnsServerFeatureLevel features, usec_t usec);
|
||||
void dns_server_packet_failed(DnsServer *s, DnsServerFeatureLevel features);
|
||||
|
||||
DnsServer *dns_server_find(DnsServer *first, int family, const union in_addr_union *in_addr);
|
||||
|
||||
@@ -86,4 +109,6 @@ void manager_next_dns_server(Manager *m);
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(DnsServer*, dns_server_unref);
|
||||
|
||||
DnsServerFeatureLevel dns_server_possible_features(DnsServer *s);
|
||||
|
||||
extern const struct hash_ops dns_server_hash_ops;
|
||||
|
||||
@@ -418,7 +418,22 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) {
|
||||
case DNS_PROTOCOL_DNS:
|
||||
assert(t->server);
|
||||
|
||||
dns_server_packet_received(t->server, ts - t->start_usec);
|
||||
if (IN_SET(DNS_PACKET_RCODE(p), DNS_RCODE_FORMERR, DNS_RCODE_SERVFAIL, DNS_RCODE_NOTIMP)) {
|
||||
|
||||
/* request failed, immediately try again with reduced features */
|
||||
log_debug("Server returned error: %s", dns_rcode_to_string(DNS_PACKET_RCODE(p)));
|
||||
|
||||
dns_server_packet_failed(t->server, t->current_features);
|
||||
|
||||
r = dns_transaction_go(t);
|
||||
if (r < 0) {
|
||||
dns_transaction_complete(t, DNS_TRANSACTION_RESOURCES);
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
} else
|
||||
dns_server_packet_received(t->server, t->current_features, ts - t->start_usec, p->size);
|
||||
|
||||
break;
|
||||
case DNS_PROTOCOL_LLMNR:
|
||||
@@ -530,10 +545,13 @@ static int dns_transaction_emit(DnsTransaction *t) {
|
||||
t->server = dns_server_ref(server);
|
||||
}
|
||||
|
||||
r = dns_scope_emit(t->scope, t->dns_udp_fd, t->sent);
|
||||
r = dns_scope_emit(t->scope, t->dns_udp_fd, t->server, t->sent);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (t->server)
|
||||
t->current_features = t->server->possible_features;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -544,15 +562,26 @@ static int on_transaction_timeout(sd_event_source *s, usec_t usec, void *userdat
|
||||
assert(s);
|
||||
assert(t);
|
||||
|
||||
/* Timeout reached? Try again, with a new server */
|
||||
dns_transaction_next_dns_server(t);
|
||||
/* Timeout reached? Increase the timeout for the server used */
|
||||
switch (t->scope->protocol) {
|
||||
case DNS_PROTOCOL_DNS:
|
||||
assert(t->server);
|
||||
|
||||
/* ... and possibly increased timeout */
|
||||
if (t->server)
|
||||
dns_server_packet_lost(t->server, usec - t->start_usec);
|
||||
else
|
||||
dns_server_packet_lost(t->server, t->current_features, usec - t->start_usec);
|
||||
|
||||
break;
|
||||
case DNS_PROTOCOL_LLMNR:
|
||||
case DNS_PROTOCOL_MDNS:
|
||||
dns_scope_packet_lost(t->scope, usec - t->start_usec);
|
||||
|
||||
break;
|
||||
default:
|
||||
assert_not_reached("Invalid DNS protocol.");
|
||||
}
|
||||
|
||||
/* ...and try again with a new server */
|
||||
dns_transaction_next_dns_server(t);
|
||||
|
||||
r = dns_transaction_go(t);
|
||||
if (r < 0)
|
||||
dns_transaction_complete(t, DNS_TRANSACTION_RESOURCES);
|
||||
@@ -734,11 +763,13 @@ int dns_transaction_go(DnsTransaction *t) {
|
||||
* always be made via TCP on LLMNR */
|
||||
r = dns_transaction_open_tcp(t);
|
||||
} else {
|
||||
/* Try via UDP, and if that fails due to large size try via TCP */
|
||||
/* Try via UDP, and if that fails due to large size or lack of
|
||||
* support try via TCP */
|
||||
r = dns_transaction_emit(t);
|
||||
if (r == -EMSGSIZE)
|
||||
if (r == -EMSGSIZE || r == -EAGAIN)
|
||||
r = dns_transaction_open_tcp(t);
|
||||
}
|
||||
|
||||
if (r == -ESRCH) {
|
||||
/* No servers to send this to? */
|
||||
dns_transaction_complete(t, DNS_TRANSACTION_NO_SERVERS);
|
||||
|
||||
@@ -79,6 +79,9 @@ struct DnsTransaction {
|
||||
/* The active server */
|
||||
DnsServer *server;
|
||||
|
||||
/* the features of the DNS server at time of transaction start */
|
||||
DnsServerFeatureLevel current_features;
|
||||
|
||||
/* TCP connection logic, if we need it */
|
||||
DnsStream *stream;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user