]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
resolved: use one UDP socket per transaction 585/head
authorTom Gundersen <teg@jklm.no>
Thu, 9 Jul 2015 12:19:55 +0000 (14:19 +0200)
committerTom Gundersen <teg@jklm.no>
Tue, 14 Jul 2015 16:50:57 +0000 (18:50 +0200)
We used to have one global socket, use one per transaction instead. This
has the side-effect of giving us a random UDP port per transaction, and
hence increasing the entropy and making cache poisoining significantly
harder to achieve.

We still reuse the same port number for packets belonging to the same
transaction (resent packets).

TODO
src/resolve/resolved-dns-scope.c
src/resolve/resolved-dns-scope.h
src/resolve/resolved-dns-transaction.c
src/resolve/resolved-dns-transaction.h
src/resolve/resolved-manager.c
src/resolve/resolved-manager.h

diff --git a/TODO b/TODO
index c1b57beeb92d427fafc55f0be426cc4c8a52d1a5..1f5023c3e52084d0e9f2ec94f4b7889b4fdbc24d 100644 (file)
--- a/TODO
+++ b/TODO
@@ -353,7 +353,6 @@ Features:
   - edns0
   - dname
   - cname on PTR (?)
-  - maybe randomize DNS UDP source ports
 
 * Allow multiple ExecStart= for all Type= settings, so that we can cover rescue.service nicely
 
index 34d4a98e822dbb7d3e1917e88c31ba9c67268b24..7b72c090c25364cbf703dd0246c48943218c4e80 100644 (file)
@@ -125,7 +125,7 @@ void dns_scope_next_dns_server(DnsScope *s) {
                 manager_next_dns_server(s->manager);
 }
 
-int dns_scope_emit(DnsScope *s, DnsPacket *p, DnsServer **server) {
+int dns_scope_emit(DnsScope *s, DnsTransaction *t, DnsPacket *p, DnsServer **server) {
         DnsServer *srv = NULL;
         union in_addr_union addr;
         int ifindex = 0, r;
@@ -163,9 +163,9 @@ int dns_scope_emit(DnsScope *s, DnsPacket *p, DnsServer **server) {
                         return -EMSGSIZE;
 
                 if (family == AF_INET)
-                        fd = manager_dns_ipv4_fd(s->manager);
+                        fd = transaction_dns_ipv4_fd(t);
                 else if (family == AF_INET6)
-                        fd = manager_dns_ipv6_fd(s->manager);
+                        fd = transaction_dns_ipv6_fd(t);
                 else
                         return -EAFNOSUPPORT;
                 if (fd < 0)
@@ -700,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, NULL);
+                r = dns_scope_emit(scope, NULL, p, NULL);
                 if (r < 0)
                         log_debug_errno(r, "Failed to send conflict packet: %m");
         }
index f836407f9b5c31854611586c23547273df574e39..5c5ccc71c537659cb360f31392f9706e5fd2354a 100644 (file)
@@ -65,7 +65,7 @@ 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, DnsServer **server);
+int dns_scope_emit(DnsScope *s, DnsTransaction *t, 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);
index 3260ded424c738c17a08788297cb9acf1b05408f..e468f245f70e5b5413f47421664029f5eb39b1a5 100644 (file)
@@ -39,6 +39,11 @@ DnsTransaction* dns_transaction_free(DnsTransaction *t) {
         dns_packet_unref(t->received);
         dns_answer_unref(t->cached);
 
+        sd_event_source_unref(t->dns_ipv4_event_source);
+        sd_event_source_unref(t->dns_ipv6_event_source);
+        safe_close(t->dns_ipv4_fd);
+        safe_close(t->dns_ipv6_fd);
+
         dns_server_unref(t->server);
         dns_stream_free(t->stream);
 
@@ -89,6 +94,8 @@ int dns_transaction_new(DnsTransaction **ret, DnsScope *s, DnsQuestion *q) {
         if (!t)
                 return -ENOMEM;
 
+        t->dns_ipv4_fd = t->dns_ipv6_fd = -1;
+
         t->question = dns_question_ref(q);
 
         do
@@ -590,7 +597,7 @@ int dns_transaction_go(DnsTransaction *t) {
                 DnsServer *server;
 
                 /* Try via UDP, and if that fails due to large size try via TCP */
-                r = dns_scope_emit(t->scope, t->sent, &server);
+                r = dns_scope_emit(t->scope, t, t->sent, &server);
                 if (r >= 0)
                         t->server = dns_server_ref(server);
                 else if (r == -EMSGSIZE)
@@ -625,6 +632,91 @@ int dns_transaction_go(DnsTransaction *t) {
         return 1;
 }
 
+static int on_dns_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
+        _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
+        DnsTransaction *t = userdata;
+        int r;
+
+        assert(t);
+        assert(t->scope);
+
+        r = manager_recv(t->scope->manager, fd, DNS_PROTOCOL_DNS, &p);
+        if (r <= 0)
+                return r;
+
+        if (dns_packet_validate_reply(p) > 0 &&
+            DNS_PACKET_ID(p) == t->id) {
+                dns_transaction_process_reply(t, p);
+        } else
+                log_debug("Invalid DNS packet.");
+
+        return 0;
+}
+
+int transaction_dns_ipv4_fd(DnsTransaction *t) {
+        const int one = 1;
+        int r;
+
+        assert(t);
+        assert(t->scope);
+        assert(t->scope->manager);
+
+        if (t->dns_ipv4_fd >= 0)
+                return t->dns_ipv4_fd;
+
+        t->dns_ipv4_fd = socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
+        if (t->dns_ipv4_fd < 0)
+                return -errno;
+
+        r = setsockopt(t->dns_ipv4_fd, IPPROTO_IP, IP_PKTINFO, &one, sizeof(one));
+        if (r < 0) {
+                r = -errno;
+                goto fail;
+        }
+
+        r = sd_event_add_io(t->scope->manager->event, &t->dns_ipv4_event_source, t->dns_ipv4_fd, EPOLLIN, on_dns_packet, t);
+        if (r < 0)
+                goto fail;
+
+        return t->dns_ipv4_fd;
+
+fail:
+        t->dns_ipv4_fd = safe_close(t->dns_ipv4_fd);
+        return r;
+}
+
+int transaction_dns_ipv6_fd(DnsTransaction *t) {
+        const int one = 1;
+        int r;
+
+        assert(t);
+        assert(t->scope);
+        assert(t->scope->manager);
+
+        if (t->dns_ipv6_fd >= 0)
+                return t->dns_ipv6_fd;
+
+        t->dns_ipv6_fd = socket(AF_INET6, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
+        if (t->dns_ipv6_fd < 0)
+                return -errno;
+
+        r = setsockopt(t->dns_ipv6_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one));
+        if (r < 0) {
+                r = -errno;
+                goto fail;
+        }
+
+        r = sd_event_add_io(t->scope->manager->event, &t->dns_ipv6_event_source, t->dns_ipv6_fd, EPOLLIN, on_dns_packet, t);
+        if (r < 0)
+                goto fail;
+
+        return t->dns_ipv6_fd;
+
+fail:
+        t->dns_ipv6_fd = safe_close(t->dns_ipv6_fd);
+        return r;
+}
+
 static const char* const dns_transaction_state_table[_DNS_TRANSACTION_STATE_MAX] = {
         [DNS_TRANSACTION_NULL] = "null",
         [DNS_TRANSACTION_PENDING] = "pending",
index 42f846e7d14605c7b03a732853f7170bbe839d0e..87f342ca1105ef402811437b807bc26a527d6958 100644 (file)
@@ -61,6 +61,12 @@ struct DnsTransaction {
         sd_event_source *timeout_event_source;
         unsigned n_attempts;
 
+        int dns_ipv4_fd;
+        int dns_ipv6_fd;
+
+        sd_event_source *dns_ipv4_event_source;
+        sd_event_source *dns_ipv6_event_source;
+
         /* the active server */
         DnsServer *server;
 
@@ -89,6 +95,9 @@ int dns_transaction_go(DnsTransaction *t);
 void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p);
 void dns_transaction_complete(DnsTransaction *t, DnsTransactionState state);
 
+int transaction_dns_ipv4_fd(DnsTransaction *t);
+int transaction_dns_ipv6_fd(DnsTransaction *t);
+
 const char* dns_transaction_state_to_string(DnsTransactionState p) _const_;
 DnsTransactionState dns_transaction_state_from_string(const char *s) _pure_;
 
index e050092a12123523de40f9693caca7f73a801034..17de14bae1eb95dab4c695bd0c824e5dc76e01cc 100644 (file)
@@ -404,7 +404,6 @@ int manager_new(Manager **ret) {
         if (!m)
                 return -ENOMEM;
 
-        m->dns_ipv4_fd = m->dns_ipv6_fd = -1;
         m->llmnr_ipv4_udp_fd = m->llmnr_ipv6_udp_fd = -1;
         m->llmnr_ipv4_tcp_fd = m->llmnr_ipv6_tcp_fd = -1;
         m->hostname_fd = -1;
@@ -486,11 +485,6 @@ Manager *manager_free(Manager *m) {
         sd_event_source_unref(m->network_event_source);
         sd_network_monitor_unref(m->network_monitor);
 
-        sd_event_source_unref(m->dns_ipv4_event_source);
-        sd_event_source_unref(m->dns_ipv6_event_source);
-        safe_close(m->dns_ipv4_fd);
-        safe_close(m->dns_ipv6_fd);
-
         manager_llmnr_stop(m);
 
         sd_bus_slot_unref(m->prepare_for_sleep_slot);
@@ -929,89 +923,6 @@ int manager_recv(Manager *m, int fd, DnsProtocol protocol, DnsPacket **ret) {
         return 1;
 }
 
-static int on_dns_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
-        _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
-        DnsTransaction *t = NULL;
-        Manager *m = userdata;
-        int r;
-
-        r = manager_recv(m, fd, DNS_PROTOCOL_DNS, &p);
-        if (r <= 0)
-                return r;
-
-        if (dns_packet_validate_reply(p) > 0) {
-                t = hashmap_get(m->dns_transactions, UINT_TO_PTR(DNS_PACKET_ID(p)));
-                if (!t)
-                        return 0;
-
-                dns_transaction_process_reply(t, p);
-
-        } else
-                log_debug("Invalid DNS packet.");
-
-        return 0;
-}
-
-int manager_dns_ipv4_fd(Manager *m) {
-        const int one = 1;
-        int r;
-
-        assert(m);
-
-        if (m->dns_ipv4_fd >= 0)
-                return m->dns_ipv4_fd;
-
-        m->dns_ipv4_fd = socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
-        if (m->dns_ipv4_fd < 0)
-                return -errno;
-
-        r = setsockopt(m->dns_ipv4_fd, IPPROTO_IP, IP_PKTINFO, &one, sizeof(one));
-        if (r < 0) {
-                r = -errno;
-                goto fail;
-        }
-
-        r = sd_event_add_io(m->event, &m->dns_ipv4_event_source, m->dns_ipv4_fd, EPOLLIN, on_dns_packet, m);
-        if (r < 0)
-                goto fail;
-
-        return m->dns_ipv4_fd;
-
-fail:
-        m->dns_ipv4_fd = safe_close(m->dns_ipv4_fd);
-        return r;
-}
-
-int manager_dns_ipv6_fd(Manager *m) {
-        const int one = 1;
-        int r;
-
-        assert(m);
-
-        if (m->dns_ipv6_fd >= 0)
-                return m->dns_ipv6_fd;
-
-        m->dns_ipv6_fd = socket(AF_INET6, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
-        if (m->dns_ipv6_fd < 0)
-                return -errno;
-
-        r = setsockopt(m->dns_ipv6_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one));
-        if (r < 0) {
-                r = -errno;
-                goto fail;
-        }
-
-        r = sd_event_add_io(m->event, &m->dns_ipv6_event_source, m->dns_ipv6_fd, EPOLLIN, on_dns_packet, m);
-        if (r < 0)
-                goto fail;
-
-        return m->dns_ipv6_fd;
-
-fail:
-        m->dns_ipv6_fd = safe_close(m->dns_ipv6_fd);
-        return r;
-}
-
 static int sendmsg_loop(int fd, struct msghdr *mh, int flags) {
         int r;
 
index 4e70a5b500526d3a060152b3a2410873d404e1f0..005f844df246df6232a97ef4776ad6af909ec8e6 100644 (file)
@@ -65,12 +65,6 @@ struct Manager {
         unsigned n_dns_streams;
 
         /* Unicast dns */
-        int dns_ipv4_fd;
-        int dns_ipv6_fd;
-
-        sd_event_source *dns_ipv4_event_source;
-        sd_event_source *dns_ipv6_event_source;
-
         LIST_HEAD(DnsServer, dns_servers);
         LIST_HEAD(DnsServer, fallback_dns_servers);
         DnsServer *current_dns_server;
@@ -128,9 +122,6 @@ uint32_t manager_find_mtu(Manager *m);
 int manager_send(Manager *m, int fd, int ifindex, int family, const union in_addr_union *addr, uint16_t port, DnsPacket *p);
 int manager_recv(Manager *m, int fd, DnsProtocol protocol, DnsPacket **ret);
 
-int manager_dns_ipv4_fd(Manager *m);
-int manager_dns_ipv6_fd(Manager *m);
-
 int manager_find_ifindex(Manager *m, int family, const union in_addr_union *in_addr);
 LinkAddress* manager_find_link_address(Manager *m, int family, const union in_addr_union *in_addr);