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:
Tom Gundersen 2015-06-24 18:54:12 +02:00
parent 91b14d6ff3
commit 8300ba218e
5 changed files with 34 additions and 16 deletions

View File

@ -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");
}

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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;