resolved: use one UDP socket per transaction

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).
This commit is contained in:
Tom Gundersen 2015-07-09 14:19:55 +02:00
parent 29815b6c60
commit d20b1667db
7 changed files with 107 additions and 105 deletions

1
TODO
View File

@ -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

View 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");
}

View 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);

View 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",

View 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_;

View 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;

View 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);