diff --git a/TODO b/TODO index c1b57beeb9..1f5023c3e5 100644 --- 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 diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c index 34d4a98e82..7b72c090c2 100644 --- a/src/resolve/resolved-dns-scope.c +++ b/src/resolve/resolved-dns-scope.c @@ -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"); } diff --git a/src/resolve/resolved-dns-scope.h b/src/resolve/resolved-dns-scope.h index f836407f9b..5c5ccc71c5 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, 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); diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c index 3260ded424..e468f245f7 100644 --- a/src/resolve/resolved-dns-transaction.c +++ b/src/resolve/resolved-dns-transaction.c @@ -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", diff --git a/src/resolve/resolved-dns-transaction.h b/src/resolve/resolved-dns-transaction.h index 42f846e7d1..87f342ca11 100644 --- a/src/resolve/resolved-dns-transaction.h +++ b/src/resolve/resolved-dns-transaction.h @@ -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_; diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c index e050092a12..17de14bae1 100644 --- a/src/resolve/resolved-manager.c +++ b/src/resolve/resolved-manager.c @@ -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; diff --git a/src/resolve/resolved-manager.h b/src/resolve/resolved-manager.h index 4e70a5b500..005f844df2 100644 --- a/src/resolve/resolved-manager.h +++ b/src/resolve/resolved-manager.h @@ -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);