From 0eb99d0a6a7d28a16e739b3a0e4900b9e4dc76f9 Mon Sep 17 00:00:00 2001 From: Tom Gundersen Date: Wed, 15 Jul 2015 18:48:17 +0200 Subject: resloved: transaction - unify IPv4 and IPv6 sockets A transaction can only have one socket at a time, so no need to distinguish these. --- src/resolve/resolved-dns-scope.c | 7 +--- src/resolve/resolved-dns-transaction.c | 65 +++++++++++----------------------- src/resolve/resolved-dns-transaction.h | 10 ++---- 3 files changed, 24 insertions(+), 58 deletions(-) diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c index 0aab1e35d3..ce419f1a04 100644 --- a/src/resolve/resolved-dns-scope.c +++ b/src/resolve/resolved-dns-scope.c @@ -162,12 +162,7 @@ int dns_scope_emit(DnsScope *s, DnsTransaction *t, DnsPacket *p, DnsServer **ser if (p->size + UDP_PACKET_HEADER_SIZE > mtu) return -EMSGSIZE; - if (family == AF_INET) - fd = transaction_dns_ipv4_fd(t); - else if (family == AF_INET6) - fd = transaction_dns_ipv6_fd(t); - else - return -EAFNOSUPPORT; + fd = transaction_dns_fd(t); if (fd < 0) return fd; diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c index 3d46c99df8..4644f8a9e1 100644 --- a/src/resolve/resolved-dns-transaction.c +++ b/src/resolve/resolved-dns-transaction.c @@ -39,10 +39,8 @@ 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); + sd_event_source_unref(t->dns_event_source); + safe_close(t->dns_fd); dns_server_unref(t->server); dns_stream_free(t->stream); @@ -94,7 +92,7 @@ int dns_transaction_new(DnsTransaction **ret, DnsScope *s, DnsQuestion *q) { if (!t) return -ENOMEM; - t->dns_ipv4_fd = t->dns_ipv6_fd = -1; + t->dns_fd = -1; t->question = dns_question_ref(q); @@ -655,7 +653,7 @@ static int on_dns_packet(sd_event_source *s, int fd, uint32_t revents, void *use return 0; } -int transaction_dns_ipv4_fd(DnsTransaction *t) { +int transaction_dns_fd(DnsTransaction *t) { const int one = 1; int r; @@ -663,59 +661,36 @@ int transaction_dns_ipv4_fd(DnsTransaction *t) { assert(t->scope); assert(t->scope->manager); - if (t->dns_ipv4_fd >= 0) - return t->dns_ipv4_fd; + if (t->dns_fd >= 0) + return t->dns_fd; - t->dns_ipv4_fd = socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); - if (t->dns_ipv4_fd < 0) + t->dns_fd = socket(t->scope->family, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); + if (t->dns_fd < 0) return -errno; - r = setsockopt(t->dns_ipv4_fd, IPPROTO_IP, IP_PKTINFO, &one, sizeof(one)); - if (r < 0) { - r = -errno; - goto fail; + switch (t->scope->family) { + case AF_INET: + r = setsockopt(t->dns_fd, IPPROTO_IP, IP_PKTINFO, &one, sizeof(one)); + break; + case AF_INET6: + r = setsockopt(t->dns_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one)); + break; + default: + return -EAFNOSUPPORT; } - - 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); + r = sd_event_add_io(t->scope->manager->event, &t->dns_event_source, t->dns_fd, EPOLLIN, on_dns_packet, t); if (r < 0) goto fail; - return t->dns_ipv6_fd; + return t->dns_fd; fail: - t->dns_ipv6_fd = safe_close(t->dns_ipv6_fd); + t->dns_fd = safe_close(t->dns_fd); return r; } diff --git a/src/resolve/resolved-dns-transaction.h b/src/resolve/resolved-dns-transaction.h index 87f342ca11..1c8f82352a 100644 --- a/src/resolve/resolved-dns-transaction.h +++ b/src/resolve/resolved-dns-transaction.h @@ -61,11 +61,8 @@ 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; + int dns_fd; + sd_event_source *dns_event_source; /* the active server */ DnsServer *server; @@ -95,8 +92,7 @@ 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); +int transaction_dns_fd(DnsTransaction *t); const char* dns_transaction_state_to_string(DnsTransactionState p) _const_; DnsTransactionState dns_transaction_state_from_string(const char *s) _pure_; -- cgit v1.2.3-54-g00ecf From 86ad4cd709ced8daf2b75ab564dece1ce82ffed9 Mon Sep 17 00:00:00 2001 From: Tom Gundersen Date: Sat, 25 Jul 2015 04:38:25 +0200 Subject: resolved: transaction - don't request PKTINFO for unicast DNS This was only ever used by LLMNR, so don't request this for unicast DNS packets. --- src/resolve/resolved-dns-transaction.c | 16 ---------------- src/resolve/resolved-manager.c | 10 ++++++---- 2 files changed, 6 insertions(+), 20 deletions(-) diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c index 4644f8a9e1..e8413d4234 100644 --- a/src/resolve/resolved-dns-transaction.c +++ b/src/resolve/resolved-dns-transaction.c @@ -654,7 +654,6 @@ static int on_dns_packet(sd_event_source *s, int fd, uint32_t revents, void *use } int transaction_dns_fd(DnsTransaction *t) { - const int one = 1; int r; assert(t); @@ -668,21 +667,6 @@ int transaction_dns_fd(DnsTransaction *t) { if (t->dns_fd < 0) return -errno; - switch (t->scope->family) { - case AF_INET: - r = setsockopt(t->dns_fd, IPPROTO_IP, IP_PKTINFO, &one, sizeof(one)); - break; - case AF_INET6: - r = setsockopt(t->dns_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one)); - break; - default: - return -EAFNOSUPPORT; - } - if (r < 0) { - r = -errno; - goto fail; - } - r = sd_event_add_io(t->scope->manager->event, &t->dns_event_source, t->dns_fd, EPOLLIN, on_dns_packet, t); if (r < 0) goto fail; diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c index 17de14bae1..9fda64ba39 100644 --- a/src/resolve/resolved-manager.c +++ b/src/resolve/resolved-manager.c @@ -912,10 +912,12 @@ int manager_recv(Manager *m, int fd, DnsProtocol protocol, DnsPacket **ret) { if (p->ifindex == LOOPBACK_IFINDEX) p->ifindex = 0; - /* If we don't know the interface index still, we look for the - * first local interface with a matching address. Yuck! */ - if (p->ifindex <= 0) - p->ifindex = manager_find_ifindex(m, p->family, &p->destination); + if (protocol != DNS_PROTOCOL_DNS) { + /* If we don't know the interface index still, we look for the + * first local interface with a matching address. Yuck! */ + if (p->ifindex <= 0) + p->ifindex = manager_find_ifindex(m, p->family, &p->destination); + } *ret = p; p = NULL; -- cgit v1.2.3-54-g00ecf From 647f6aa8fcc50a5bb18f188e4d11d568ed307811 Mon Sep 17 00:00:00 2001 From: Tom Gundersen Date: Sat, 25 Jul 2015 04:45:26 +0200 Subject: resolved: transaction - close socket when changing server Close the socket when changing the server in a transaction, in order for it to be reopened with the right server when we send the next packet. This fixes a regression where we could get stuck with a failing server. --- src/resolve/resolved-dns-transaction.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c index e8413d4234..5540cd386e 100644 --- a/src/resolve/resolved-dns-transaction.c +++ b/src/resolve/resolved-dns-transaction.c @@ -308,6 +308,16 @@ static int dns_transaction_open_tcp(DnsTransaction *t) { return 0; } +static void dns_transaction_next_dns_server(DnsTransaction *t) { + assert(t); + + t->server = dns_server_unref(t->server); + t->dns_event_source = sd_event_source_unref(t->dns_event_source); + t->dns_fd = safe_close(t->dns_fd); + + dns_scope_next_dns_server(t->scope); +} + void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) { int r; @@ -394,7 +404,7 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) { } /* On DNS, couldn't send? Try immediately again, with a new server */ - dns_scope_next_dns_server(t->scope); + dns_transaction_next_dns_server(t); r = dns_transaction_go(t); if (r < 0) { @@ -437,7 +447,7 @@ static int on_transaction_timeout(sd_event_source *s, usec_t usec, void *userdat assert(t); /* Timeout reached? Try again, with a new server */ - dns_scope_next_dns_server(t->scope); + dns_transaction_next_dns_server(t); r = dns_transaction_go(t); if (r < 0) @@ -614,7 +624,7 @@ int dns_transaction_go(DnsTransaction *t) { } /* Couldn't send? Try immediately again, with a new server */ - dns_scope_next_dns_server(t->scope); + dns_transaction_next_dns_server(t); return dns_transaction_go(t); } -- cgit v1.2.3-54-g00ecf From 0db643664cf37111be163c0c64ccd66b519daf34 Mon Sep 17 00:00:00 2001 From: Tom Gundersen Date: Wed, 15 Jul 2015 19:22:29 +0200 Subject: resolved: transaction - move DNS UDP socket creation to the scope With access to the server when creating the socket, we can connect() to the server and hence simplify message sending and receiving in follow-up patches. --- src/resolve/resolved-dns-scope.c | 34 ++++++++++++++++++++-------------- src/resolve/resolved-dns-scope.h | 1 + src/resolve/resolved-dns-transaction.c | 10 +++++++--- src/resolve/resolved-dns-transaction.h | 2 +- 4 files changed, 29 insertions(+), 18 deletions(-) diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c index ce419f1a04..5129412604 100644 --- a/src/resolve/resolved-dns-scope.c +++ b/src/resolve/resolved-dns-scope.c @@ -148,24 +148,20 @@ int dns_scope_emit(DnsScope *s, DnsTransaction *t, DnsPacket *p, DnsServer **ser if (DNS_PACKET_QDCOUNT(p) > 1) return -EOPNOTSUPP; - srv = dns_scope_get_dns_server(s); - if (!srv) - return -ESRCH; - - family = srv->family; - addr = srv->address; - port = 53; - if (p->size > DNS_PACKET_UNICAST_SIZE_MAX) return -EMSGSIZE; if (p->size + UDP_PACKET_HEADER_SIZE > mtu) return -EMSGSIZE; - fd = transaction_dns_fd(t); + fd = transaction_dns_fd(t, &srv); if (fd < 0) return fd; + family = srv->family; + addr = srv->address; + port = 53; + } else if (s->protocol == DNS_PROTOCOL_LLMNR) { if (DNS_PACKET_QDCOUNT(p) > 1) @@ -200,7 +196,7 @@ int dns_scope_emit(DnsScope *s, DnsTransaction *t, DnsPacket *p, DnsServer **ser return 1; } -int dns_scope_tcp_socket(DnsScope *s, int family, const union in_addr_union *address, uint16_t port, DnsServer **server) { +static int dns_scope_socket(DnsScope *s, int type, 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 = {}; @@ -244,13 +240,15 @@ int dns_scope_tcp_socket(DnsScope *s, int family, const union in_addr_union *add return -EAFNOSUPPORT; } - fd = socket(sa.sa.sa_family, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); + fd = socket(sa.sa.sa_family, type|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); if (fd < 0) return -errno; - r = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one)); - if (r < 0) - return -errno; + if (type == SOCK_STREAM) { + r = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one)); + if (r < 0) + return -errno; + } if (s->link) { uint32_t ifindex = htobe32(s->link->ifindex); @@ -293,6 +291,14 @@ int dns_scope_tcp_socket(DnsScope *s, int family, const union in_addr_union *add return ret; } +int dns_scope_udp_dns_socket(DnsScope *s, DnsServer **server) { + return dns_scope_socket(s, SOCK_DGRAM, AF_UNSPEC, NULL, 53, server); +} + +int dns_scope_tcp_socket(DnsScope *s, int family, const union in_addr_union *address, uint16_t port, DnsServer **server) { + return dns_scope_socket(s, SOCK_STREAM, family, address, port, server); +} + DnsScopeMatch dns_scope_good_domain(DnsScope *s, int ifindex, uint64_t flags, const char *domain) { char **i; diff --git a/src/resolve/resolved-dns-scope.h b/src/resolve/resolved-dns-scope.h index 21a160ea39..9d08bc3259 100644 --- a/src/resolve/resolved-dns-scope.h +++ b/src/resolve/resolved-dns-scope.h @@ -67,6 +67,7 @@ DnsScope* dns_scope_free(DnsScope *s); 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); +int dns_scope_udp_dns_socket(DnsScope *s, 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-transaction.c b/src/resolve/resolved-dns-transaction.c index 5540cd386e..5580e376c0 100644 --- a/src/resolve/resolved-dns-transaction.c +++ b/src/resolve/resolved-dns-transaction.c @@ -663,7 +663,8 @@ static int on_dns_packet(sd_event_source *s, int fd, uint32_t revents, void *use return 0; } -int transaction_dns_fd(DnsTransaction *t) { +int transaction_dns_fd(DnsTransaction *t, DnsServer **_server) { + DnsServer *server; int r; assert(t); @@ -673,14 +674,17 @@ int transaction_dns_fd(DnsTransaction *t) { if (t->dns_fd >= 0) return t->dns_fd; - t->dns_fd = socket(t->scope->family, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); + t->dns_fd = dns_scope_udp_dns_socket(t->scope, &server); if (t->dns_fd < 0) - return -errno; + return t->dns_fd; r = sd_event_add_io(t->scope->manager->event, &t->dns_event_source, t->dns_fd, EPOLLIN, on_dns_packet, t); if (r < 0) goto fail; + if (_server) + *_server = server; + return t->dns_fd; fail: diff --git a/src/resolve/resolved-dns-transaction.h b/src/resolve/resolved-dns-transaction.h index 1c8f82352a..ab4db0612f 100644 --- a/src/resolve/resolved-dns-transaction.h +++ b/src/resolve/resolved-dns-transaction.h @@ -92,7 +92,7 @@ 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_fd(DnsTransaction *t); +int transaction_dns_fd(DnsTransaction *t, DnsServer **server); const char* dns_transaction_state_to_string(DnsTransactionState p) _const_; DnsTransactionState dns_transaction_state_from_string(const char *s) _pure_; -- cgit v1.2.3-54-g00ecf From c19ffd9fbfcca170746918982cb687874dc37f5c Mon Sep 17 00:00:00 2001 From: Tom Gundersen Date: Mon, 27 Jul 2015 20:18:43 +0200 Subject: resolved: transaction - move a couple of functions No functional change, but makes follow-up patch clearer. --- src/resolve/resolved-dns-transaction.c | 100 ++++++++++++++++----------------- 1 file changed, 50 insertions(+), 50 deletions(-) diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c index 5580e376c0..c4e055dfd8 100644 --- a/src/resolve/resolved-dns-transaction.c +++ b/src/resolve/resolved-dns-transaction.c @@ -439,6 +439,56 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) { dns_transaction_complete(t, DNS_TRANSACTION_FAILURE); } +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_fd(DnsTransaction *t, DnsServer **_server) { + DnsServer *server; + int r; + + assert(t); + assert(t->scope); + assert(t->scope->manager); + + if (t->dns_fd >= 0) + return t->dns_fd; + + t->dns_fd = dns_scope_udp_dns_socket(t->scope, &server); + if (t->dns_fd < 0) + return t->dns_fd; + + r = sd_event_add_io(t->scope->manager->event, &t->dns_event_source, t->dns_fd, EPOLLIN, on_dns_packet, t); + if (r < 0) + goto fail; + + if (_server) + *_server = server; + + return t->dns_fd; + +fail: + t->dns_fd = safe_close(t->dns_fd); + return r; +} + static int on_transaction_timeout(sd_event_source *s, usec_t usec, void *userdata) { DnsTransaction *t = userdata; int r; @@ -642,56 +692,6 @@ 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_fd(DnsTransaction *t, DnsServer **_server) { - DnsServer *server; - int r; - - assert(t); - assert(t->scope); - assert(t->scope->manager); - - if (t->dns_fd >= 0) - return t->dns_fd; - - t->dns_fd = dns_scope_udp_dns_socket(t->scope, &server); - if (t->dns_fd < 0) - return t->dns_fd; - - r = sd_event_add_io(t->scope->manager->event, &t->dns_event_source, t->dns_fd, EPOLLIN, on_dns_packet, t); - if (r < 0) - goto fail; - - if (_server) - *_server = server; - - return t->dns_fd; - -fail: - t->dns_fd = safe_close(t->dns_fd); - return r; -} - static const char* const dns_transaction_state_table[_DNS_TRANSACTION_STATE_MAX] = { [DNS_TRANSACTION_NULL] = "null", [DNS_TRANSACTION_PENDING] = "pending", -- cgit v1.2.3-54-g00ecf From 471d40d92fc8e7b452dff99a156f9e0b520ded20 Mon Sep 17 00:00:00 2001 From: Tom Gundersen Date: Wed, 15 Jul 2015 19:22:29 +0200 Subject: resolved: transaction - introduce dns_transaction_emit() This function emits the UDP packet via the scope, but first it will determine the current server (and connect to it) and store the server in the transaction. This should not change the behavior, but simplifies the code. --- src/resolve/resolved-dns-scope.c | 18 +++----------- src/resolve/resolved-dns-scope.h | 2 +- src/resolve/resolved-dns-transaction.c | 45 +++++++++++++++------------------- src/resolve/resolved-dns-transaction.h | 2 -- 4 files changed, 24 insertions(+), 43 deletions(-) diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c index 5129412604..e8c6108924 100644 --- a/src/resolve/resolved-dns-scope.c +++ b/src/resolve/resolved-dns-scope.c @@ -125,18 +125,17 @@ void dns_scope_next_dns_server(DnsScope *s) { manager_next_dns_server(s->manager); } -int dns_scope_emit(DnsScope *s, DnsTransaction *t, DnsPacket *p, DnsServer **server) { - DnsServer *srv = NULL; +int dns_scope_emit(DnsScope *s, int fd, DnsPacket *p) { union in_addr_union addr; int ifindex = 0, r; int family; uint16_t port; uint32_t mtu; - int fd; assert(s); assert(p); assert(p->protocol == s->protocol); + assert((s->protocol == DNS_PROTOCOL_DNS) != (fd < 0)); if (s->link) { mtu = s->link->mtu; @@ -154,14 +153,6 @@ int dns_scope_emit(DnsScope *s, DnsTransaction *t, DnsPacket *p, DnsServer **ser if (p->size + UDP_PACKET_HEADER_SIZE > mtu) return -EMSGSIZE; - fd = transaction_dns_fd(t, &srv); - if (fd < 0) - return fd; - - family = srv->family; - addr = srv->address; - port = 53; - } else if (s->protocol == DNS_PROTOCOL_LLMNR) { if (DNS_PACKET_QDCOUNT(p) > 1) @@ -190,9 +181,6 @@ int dns_scope_emit(DnsScope *s, DnsTransaction *t, DnsPacket *p, DnsServer **ser if (r < 0) return r; - if (server) - *server = srv; - return 1; } @@ -688,7 +676,7 @@ static int on_conflict_dispatch(sd_event_source *es, usec_t usec, void *userdata return 0; } - r = dns_scope_emit(scope, NULL, p, NULL); + r = dns_scope_emit(scope, -1, p); 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 9d08bc3259..29479ad550 100644 --- a/src/resolve/resolved-dns-scope.h +++ b/src/resolve/resolved-dns-scope.h @@ -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, DnsTransaction *t, DnsPacket *p, DnsServer **server); +int dns_scope_emit(DnsScope *s, int fd, DnsPacket *p); int dns_scope_tcp_socket(DnsScope *s, int family, const union in_addr_union *address, uint16_t port, DnsServer **server); int dns_scope_udp_dns_socket(DnsScope *s, DnsServer **server); diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c index c4e055dfd8..956c2e9973 100644 --- a/src/resolve/resolved-dns-transaction.c +++ b/src/resolve/resolved-dns-transaction.c @@ -460,33 +460,33 @@ static int on_dns_packet(sd_event_source *s, int fd, uint32_t revents, void *use return 0; } -int transaction_dns_fd(DnsTransaction *t, DnsServer **_server) { - DnsServer *server; +static int dns_transaction_emit(DnsTransaction *t) { int r; assert(t); - assert(t->scope); - assert(t->scope->manager); - if (t->dns_fd >= 0) - return t->dns_fd; + if (t->scope->protocol == DNS_PROTOCOL_DNS && !t->server) { + DnsServer *server = NULL; + _cleanup_close_ int fd = -1; - t->dns_fd = dns_scope_udp_dns_socket(t->scope, &server); - if (t->dns_fd < 0) - return t->dns_fd; + fd = dns_scope_udp_dns_socket(t->scope, &server); + if (fd < 0) + return fd; - r = sd_event_add_io(t->scope->manager->event, &t->dns_event_source, t->dns_fd, EPOLLIN, on_dns_packet, t); - if (r < 0) - goto fail; + r = sd_event_add_io(t->scope->manager->event, &t->dns_event_source, fd, EPOLLIN, on_dns_packet, t); + if (r < 0) + return r; - if (_server) - *_server = server; + t->dns_fd = fd; + fd = -1; + t->server = dns_server_ref(server); + } - return t->dns_fd; + r = dns_scope_emit(t->scope, t->dns_fd, t->sent); + if (r < 0) + return r; -fail: - t->dns_fd = safe_close(t->dns_fd); - return r; + return 0; } static int on_transaction_timeout(sd_event_source *s, usec_t usec, void *userdata) { @@ -574,7 +574,6 @@ 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; @@ -654,13 +653,9 @@ 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, t->sent, &server); - if (r >= 0) - t->server = dns_server_ref(server); - else if (r == -EMSGSIZE) + r = dns_transaction_emit(t); + if (r == -EMSGSIZE) r = dns_transaction_open_tcp(t); } if (r == -ESRCH) { diff --git a/src/resolve/resolved-dns-transaction.h b/src/resolve/resolved-dns-transaction.h index ab4db0612f..a8f4267bc8 100644 --- a/src/resolve/resolved-dns-transaction.h +++ b/src/resolve/resolved-dns-transaction.h @@ -92,8 +92,6 @@ 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_fd(DnsTransaction *t, DnsServer **server); - const char* dns_transaction_state_to_string(DnsTransactionState p) _const_; DnsTransactionState dns_transaction_state_from_string(const char *s) _pure_; -- cgit v1.2.3-54-g00ecf From 72290734be81e83e6ef9520c07692f68095eb5b2 Mon Sep 17 00:00:00 2001 From: Tom Gundersen Date: Sat, 25 Jul 2015 05:11:34 +0200 Subject: resolved: scope - write() unicast DNS packets As we have connect()ed to the desired DNS server, we no longer need to pass control messages manually when sending packets. Simplify the logic accordingly. --- src/resolve/resolved-dns-scope.c | 12 ++++++++---- src/resolve/resolved-manager.c | 36 ++++++++++++++++++++++++++++++++++++ src/resolve/resolved-manager.h | 1 + 3 files changed, 45 insertions(+), 4 deletions(-) diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c index e8c6108924..927a1ddc26 100644 --- a/src/resolve/resolved-dns-scope.c +++ b/src/resolve/resolved-dns-scope.c @@ -153,6 +153,10 @@ int dns_scope_emit(DnsScope *s, int fd, DnsPacket *p) { if (p->size + UDP_PACKET_HEADER_SIZE > mtu) return -EMSGSIZE; + r = manager_write(s->manager, fd, p); + if (r < 0) + return r; + } else if (s->protocol == DNS_PROTOCOL_LLMNR) { if (DNS_PACKET_QDCOUNT(p) > 1) @@ -174,13 +178,13 @@ int dns_scope_emit(DnsScope *s, int fd, DnsPacket *p) { return -EAFNOSUPPORT; if (fd < 0) return fd; + + r = manager_send(s->manager, fd, ifindex, family, &addr, port, p); + if (r < 0) + return r; } else return -EAFNOSUPPORT; - r = manager_send(s->manager, fd, ifindex, family, &addr, port, p); - if (r < 0) - return r; - return 1; } diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c index 9fda64ba39..5be01d3cb8 100644 --- a/src/resolve/resolved-manager.c +++ b/src/resolve/resolved-manager.c @@ -949,6 +949,42 @@ static int sendmsg_loop(int fd, struct msghdr *mh, int flags) { } } +static int write_loop(int fd, void *message, size_t length) { + int r; + + assert(fd >= 0); + assert(message); + + for (;;) { + if (write(fd, message, length) >= 0) + return 0; + + if (errno == EINTR) + continue; + + if (errno != EAGAIN) + return -errno; + + r = fd_wait_for_event(fd, POLLOUT, SEND_TIMEOUT_USEC); + if (r < 0) + return r; + if (r == 0) + return -ETIMEDOUT; + } +} + +int manager_write(Manager *m, int fd, DnsPacket *p) { + int r; + + log_debug("Sending %s packet with id %u", DNS_PACKET_QR(p) ? "response" : "query", DNS_PACKET_ID(p)); + + r = write_loop(fd, DNS_PACKET_DATA(p), p->size); + if (r < 0) + return r; + + return 0; +} + static int manager_ipv4_send(Manager *m, int fd, int ifindex, const struct in_addr *addr, uint16_t port, DnsPacket *p) { union sockaddr_union sa = { .in.sin_family = AF_INET, diff --git a/src/resolve/resolved-manager.h b/src/resolve/resolved-manager.h index 005f844df2..53b5acb33c 100644 --- a/src/resolve/resolved-manager.h +++ b/src/resolve/resolved-manager.h @@ -119,6 +119,7 @@ void manager_next_dns_server(Manager *m); uint32_t manager_find_mtu(Manager *m); +int manager_write(Manager *m, int fd, DnsPacket *p); 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); -- cgit v1.2.3-54-g00ecf From 088480faf1228e5f537fdef9c974874567529868 Mon Sep 17 00:00:00 2001 From: Tom Gundersen Date: Sat, 25 Jul 2015 05:12:49 +0200 Subject: resolved: transaction - don't unref server when creating TCP socket This was a bug. --- src/resolve/resolved-dns-transaction.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c index 956c2e9973..a8ff233673 100644 --- a/src/resolve/resolved-dns-transaction.c +++ b/src/resolve/resolved-dns-transaction.c @@ -243,7 +243,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; + DnsServer *server = NULL; _cleanup_close_ int fd = -1; int r; -- cgit v1.2.3-54-g00ecf From c73ee39d1031f8d7e01448bf1a9810943d7c6560 Mon Sep 17 00:00:00 2001 From: Tom Gundersen Date: Sat, 25 Jul 2015 05:14:08 +0200 Subject: resolved: transaction - don't explicitly verify packet source This is handled by the kernel now that the socket is connect()ed. --- src/resolve/resolved-dns-transaction.c | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c index a8ff233673..b235fda3d2 100644 --- a/src/resolve/resolved-dns-transaction.c +++ b/src/resolve/resolved-dns-transaction.c @@ -350,24 +350,6 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) { } } - if (t->scope->protocol == DNS_PROTOCOL_DNS) { - - /* For DNS we are fine with accepting packets on any - * interface, but the source IP address must be the - * one of the DNS server we queried */ - - assert(t->server); - - if (t->server->family != p->family) - return; - - if (!in_addr_equal(p->family, &p->sender, &t->server->address)) - return; - - if (p->sender_port != 53) - return; - } - if (t->received != p) { dns_packet_unref(t->received); t->received = dns_packet_ref(p); -- cgit v1.2.3-54-g00ecf From 75c0cab158e9da7f78ad040d23cd52720a025659 Mon Sep 17 00:00:00 2001 From: Tom Gundersen Date: Thu, 23 Jul 2015 18:45:49 +0200 Subject: util: base32hex - explain distinction with base32 --- src/basic/util.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/basic/util.c b/src/basic/util.c index 7896be8788..1c15fbc172 100644 --- a/src/basic/util.c +++ b/src/basic/util.c @@ -954,7 +954,12 @@ int unhexmem(const char *p, size_t l, void **mem, size_t *len) { return 0; } -/* https://tools.ietf.org/html/rfc4648#section-6 */ +/* https://tools.ietf.org/html/rfc4648#section-6 + * Notice that base32hex differs from base32 in the alphabet it uses. + * The distinction is that the base32hex representation preserves the + * order of the underlying data when compared as bytestrings, this is + * useful when representing NSEC3 hashes, as one can then verify the + * order of hashes directly from their representation. */ char base32hexchar(int x) { static const char table[32] = "0123456789" "ABCDEFGHIJKLMNOPQRSTUV"; -- cgit v1.2.3-54-g00ecf