summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Gundersen <teg@jklm.no>2015-06-24 18:54:12 +0200
committerTom Gundersen <teg@jklm.no>2015-07-14 18:50:53 +0200
commit8300ba218e3cf5049496937be8bce10f22d09bbc (patch)
treef0be112a2c74809d87b38331cecd52af677800ec
parent91b14d6ff362b938a72db17b095ee9903d07381b (diff)
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.
-rw-r--r--src/resolve/resolved-dns-scope.c18
-rw-r--r--src/resolve/resolved-dns-scope.h4
-rw-r--r--src/resolve/resolved-dns-server.h2
-rw-r--r--src/resolve/resolved-dns-transaction.c23
-rw-r--r--src/resolve/resolved-dns-transaction.h3
5 files changed, 34 insertions, 16 deletions
diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c
index e01e97be3..34d4a98e8 100644
--- a/src/resolve/resolved-dns-scope.c
+++ b/src/resolve/resolved-dns-scope.c
@@ -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");
}
diff --git a/src/resolve/resolved-dns-scope.h b/src/resolve/resolved-dns-scope.h
index cfbde1343..f836407f9 100644
--- a/src/resolve/resolved-dns-scope.h
+++ b/src/resolve/resolved-dns-scope.h
@@ -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);
diff --git a/src/resolve/resolved-dns-server.h b/src/resolve/resolved-dns-server.h
index 03013beb8..06059e882 100644
--- a/src/resolve/resolved-dns-server.h
+++ b/src/resolve/resolved-dns-server.h
@@ -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;
diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c
index 3f4673df7..7fa73cd01 100644
--- a/src/resolve/resolved-dns-transaction.c
+++ b/src/resolve/resolved-dns-transaction.c
@@ -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;
diff --git a/src/resolve/resolved-dns-transaction.h b/src/resolve/resolved-dns-transaction.h
index f6d539d31..42f846e7d 100644
--- a/src/resolve/resolved-dns-transaction.h
+++ b/src/resolve/resolved-dns-transaction.h
@@ -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;