resolved: pin the server used in a transaction
We want to discover information about the server and use that in when crafting packets to be resent.
This commit is contained in:
parent
91b14d6ff3
commit
8300ba218e
|
@ -125,7 +125,8 @@ void dns_scope_next_dns_server(DnsScope *s) {
|
|||
manager_next_dns_server(s->manager);
|
||||
}
|
||||
|
||||
int dns_scope_emit(DnsScope *s, DnsPacket *p) {
|
||||
int dns_scope_emit(DnsScope *s, DnsPacket *p, DnsServer **server) {
|
||||
DnsServer *srv = NULL;
|
||||
union in_addr_union addr;
|
||||
int ifindex = 0, r;
|
||||
int family;
|
||||
|
@ -144,8 +145,6 @@ int dns_scope_emit(DnsScope *s, DnsPacket *p) {
|
|||
mtu = manager_find_mtu(s->manager);
|
||||
|
||||
if (s->protocol == DNS_PROTOCOL_DNS) {
|
||||
DnsServer *srv;
|
||||
|
||||
if (DNS_PACKET_QDCOUNT(p) > 1)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
|
@ -200,10 +199,14 @@ int dns_scope_emit(DnsScope *s, DnsPacket *p) {
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (server)
|
||||
*server = srv;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dns_scope_tcp_socket(DnsScope *s, int family, const union in_addr_union *address, uint16_t port) {
|
||||
int dns_scope_tcp_socket(DnsScope *s, int family, const union in_addr_union *address, uint16_t port, DnsServer **server) {
|
||||
DnsServer *srv = NULL;
|
||||
_cleanup_close_ int fd = -1;
|
||||
union sockaddr_union sa = {};
|
||||
socklen_t salen;
|
||||
|
@ -214,8 +217,6 @@ int dns_scope_tcp_socket(DnsScope *s, int family, const union in_addr_union *add
|
|||
assert((family == AF_UNSPEC) == !address);
|
||||
|
||||
if (family == AF_UNSPEC) {
|
||||
DnsServer *srv;
|
||||
|
||||
srv = dns_scope_get_dns_server(s);
|
||||
if (!srv)
|
||||
return -ESRCH;
|
||||
|
@ -288,6 +289,9 @@ int dns_scope_tcp_socket(DnsScope *s, int family, const union in_addr_union *add
|
|||
if (r < 0 && errno != EINPROGRESS)
|
||||
return -errno;
|
||||
|
||||
if (server)
|
||||
*server = srv;
|
||||
|
||||
ret = fd;
|
||||
fd = -1;
|
||||
|
||||
|
@ -696,7 +700,7 @@ static int on_conflict_dispatch(sd_event_source *es, usec_t usec, void *userdata
|
|||
return 0;
|
||||
}
|
||||
|
||||
r = dns_scope_emit(scope, p);
|
||||
r = dns_scope_emit(scope, p, NULL);
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "Failed to send conflict packet: %m");
|
||||
}
|
||||
|
|
|
@ -65,8 +65,8 @@ struct DnsScope {
|
|||
int dns_scope_new(Manager *m, DnsScope **ret, Link *l, DnsProtocol p, int family);
|
||||
DnsScope* dns_scope_free(DnsScope *s);
|
||||
|
||||
int dns_scope_emit(DnsScope *s, DnsPacket *p);
|
||||
int dns_scope_tcp_socket(DnsScope *s, int family, const union in_addr_union *address, uint16_t port);
|
||||
int dns_scope_emit(DnsScope *s, DnsPacket *p, DnsServer **server);
|
||||
int dns_scope_tcp_socket(DnsScope *s, int family, const union in_addr_union *address, uint16_t port, DnsServer **server);
|
||||
|
||||
DnsScopeMatch dns_scope_good_domain(DnsScope *s, int ifindex, uint64_t flags, const char *domain);
|
||||
int dns_scope_good_key(DnsScope *s, DnsResourceKey *key);
|
||||
|
|
|
@ -62,4 +62,6 @@ int dns_server_new(
|
|||
DnsServer* dns_server_ref(DnsServer *s);
|
||||
DnsServer* dns_server_unref(DnsServer *s);
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(DnsServer*, dns_server_unref);
|
||||
|
||||
extern const struct hash_ops dns_server_hash_ops;
|
||||
|
|
|
@ -39,6 +39,7 @@ DnsTransaction* dns_transaction_free(DnsTransaction *t) {
|
|||
dns_packet_unref(t->received);
|
||||
dns_answer_unref(t->cached);
|
||||
|
||||
dns_server_unref(t->server);
|
||||
dns_stream_free(t->stream);
|
||||
|
||||
if (t->scope) {
|
||||
|
@ -237,6 +238,7 @@ static int on_stream_complete(DnsStream *s, int error) {
|
|||
}
|
||||
|
||||
static int dns_transaction_open_tcp(DnsTransaction *t) {
|
||||
_cleanup_(dns_server_unrefp) DnsServer *server = NULL;
|
||||
_cleanup_close_ int fd = -1;
|
||||
int r;
|
||||
|
||||
|
@ -246,12 +248,12 @@ static int dns_transaction_open_tcp(DnsTransaction *t) {
|
|||
return 0;
|
||||
|
||||
if (t->scope->protocol == DNS_PROTOCOL_DNS)
|
||||
fd = dns_scope_tcp_socket(t->scope, AF_UNSPEC, NULL, 53);
|
||||
fd = dns_scope_tcp_socket(t->scope, AF_UNSPEC, NULL, 53, &server);
|
||||
else if (t->scope->protocol == DNS_PROTOCOL_LLMNR) {
|
||||
|
||||
/* When we already received a query to this (but it was truncated), send to its sender address */
|
||||
if (t->received)
|
||||
fd = dns_scope_tcp_socket(t->scope, t->received->family, &t->received->sender, t->received->sender_port);
|
||||
fd = dns_scope_tcp_socket(t->scope, t->received->family, &t->received->sender, t->received->sender_port, NULL);
|
||||
else {
|
||||
union in_addr_union address;
|
||||
int family = AF_UNSPEC;
|
||||
|
@ -265,7 +267,7 @@ static int dns_transaction_open_tcp(DnsTransaction *t) {
|
|||
if (r == 0)
|
||||
return -EINVAL;
|
||||
|
||||
fd = dns_scope_tcp_socket(t->scope, family, &address, LLMNR_PORT);
|
||||
fd = dns_scope_tcp_socket(t->scope, family, &address, LLMNR_PORT, NULL);
|
||||
}
|
||||
} else
|
||||
return -EAFNOSUPPORT;
|
||||
|
@ -285,6 +287,9 @@ static int dns_transaction_open_tcp(DnsTransaction *t) {
|
|||
return r;
|
||||
}
|
||||
|
||||
|
||||
dns_server_unref(t->server);
|
||||
t->server = dns_server_ref(server);
|
||||
t->received = dns_packet_unref(t->received);
|
||||
t->stream->complete = on_stream_complete;
|
||||
t->stream->transaction = t;
|
||||
|
@ -492,6 +497,7 @@ int dns_transaction_go(DnsTransaction *t) {
|
|||
}
|
||||
|
||||
t->n_attempts++;
|
||||
t->server = dns_server_unref(t->server);
|
||||
t->received = dns_packet_unref(t->received);
|
||||
t->cached = dns_answer_unref(t->cached);
|
||||
t->cached_rcode = 0;
|
||||
|
@ -571,17 +577,20 @@ int dns_transaction_go(DnsTransaction *t) {
|
|||
* always be made via TCP on LLMNR */
|
||||
r = dns_transaction_open_tcp(t);
|
||||
} else {
|
||||
DnsServer *server;
|
||||
|
||||
/* Try via UDP, and if that fails due to large size try via TCP */
|
||||
r = dns_scope_emit(t->scope, t->sent);
|
||||
if (r == -EMSGSIZE)
|
||||
r = dns_scope_emit(t->scope, t->sent, &server);
|
||||
if (r >= 0)
|
||||
t->server = dns_server_ref(server);
|
||||
else if (r == -EMSGSIZE)
|
||||
r = dns_transaction_open_tcp(t);
|
||||
}
|
||||
if (r == -ESRCH) {
|
||||
/* No servers to send this to? */
|
||||
dns_transaction_complete(t, DNS_TRANSACTION_NO_SERVERS);
|
||||
return 0;
|
||||
}
|
||||
if (r < 0) {
|
||||
} else if (r < 0) {
|
||||
if (t->scope->protocol != DNS_PROTOCOL_DNS) {
|
||||
dns_transaction_complete(t, DNS_TRANSACTION_RESOURCES);
|
||||
return 0;
|
||||
|
|
|
@ -61,6 +61,9 @@ struct DnsTransaction {
|
|||
sd_event_source *timeout_event_source;
|
||||
unsigned n_attempts;
|
||||
|
||||
/* the active server */
|
||||
DnsServer *server;
|
||||
|
||||
/* TCP connection logic, if we need it */
|
||||
DnsStream *stream;
|
||||
|
||||
|
|
Loading…
Reference in a new issue