]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
resolved: pin the server used in a transaction
authorTom Gundersen <teg@jklm.no>
Wed, 24 Jun 2015 16:54:12 +0000 (18:54 +0200)
committerTom Gundersen <teg@jklm.no>
Tue, 14 Jul 2015 16:50:53 +0000 (18:50 +0200)
We want to discover information about the server and use that in when crafting
packets to be resent.

src/resolve/resolved-dns-scope.c
src/resolve/resolved-dns-scope.h
src/resolve/resolved-dns-server.h
src/resolve/resolved-dns-transaction.c
src/resolve/resolved-dns-transaction.h

index e01e97be354518b1faa7d519fc754cfc5181394b..34d4a98e822dbb7d3e1917e88c31ba9c67268b24 100644 (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");
         }
index cfbde1343f49641234e6aa6764d5750f2409fb2b..f836407f9b5c31854611586c23547273df574e39 100644 (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);
index 03013beb8292944c2fa2718bbb4d6632842803a9..06059e8829ee8016efb97e58831c57ad5099db50 100644 (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;
index 3f4673df7aa40a1ef134262e0c52716eab443ac9..7fa73cd01a78830207f035040a4ff8e6baf3da8a 100644 (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;
index f6d539d315165787b86cc7ef684177a57a95b25e..42f846e7d14605c7b03a732853f7170bbe839d0e 100644 (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;