Skip to content

Commit

Permalink
Fix bug occurring in mixed resolver lists
Browse files Browse the repository at this point in the history
Mixed resolver lists with IPv4 and IPv6 resolvers could cause MassDNS to
fail sending queries.

By default, one IPv4 socket and one IPv6 socket are created to send
queries to IPv4 and IPv6 resolvers respectively. Initially, MassDNS
would pick a resolver at random and select an appropriate socket. When
a timeout occured, MassDNS would then pick a new resolver at random
while failing to update the socket. As a result, consecutive queries
would fail in each iteration in which the address family of the
randomly selected socket would differ from the address family of
the socket that was picked initially.

When the issue occurred, MassDNS would output "Address family not
supported by protocol". While the bug could have led to false negatives,
a rough calculation suggests that the impact on the reliability of
MassDNS was rather low.
  • Loading branch information
blechschmidt committed Sep 22, 2021
1 parent 5cacad7 commit 2b39408
Show file tree
Hide file tree
Showing 2 changed files with 5 additions and 11 deletions.
8 changes: 4 additions & 4 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -487,7 +487,7 @@ void add_default_socket(int version)
socket_info_t info;

info.descriptor = socket(version == 4 ? PF_INET : PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
info.protocol = version == 4 ? PROTO_IPV4 : PROTO_IPV6;
info.protocol = version == 4 ? AF_INET : AF_INET6;
info.type = SOCKET_TYPE_QUERY;
if(info.descriptor >= 0)
{
Expand All @@ -512,7 +512,7 @@ void set_user_sockets(single_list_t *bind_addrs, buffer_t *buffer)
struct sockaddr_storage* addr = element->data;
socket_info_t info;
info.descriptor = socket(addr->ss_family, SOCK_DGRAM, IPPROTO_UDP);
info.protocol = addr->ss_family == AF_INET ? PROTO_IPV4 : PROTO_IPV6;
info.protocol = addr->ss_family;
info.type = SOCKET_TYPE_QUERY;
if(info.descriptor >= 0)
{
Expand Down Expand Up @@ -713,12 +713,12 @@ void send_query(lookup_t *lookup)
interfaces = &context.sockets.interfaces6;
}

if(lookup->socket == NULL)
if(lookup->socket == NULL || lookup->socket->protocol != lookup->resolver->address.ss_family)
{
// Pick a random socket from that pool
// Pool of sockets cannot be empty due to check when parsing resolvers. Socket creation must have succeeded.
size_t socket_index = urandom_size_t() % interfaces->len;
lookup->socket = (socket_info_t *) interfaces->data + socket_index;
lookup->socket = ((socket_info_t *) interfaces->data) + socket_index;
}

ssize_t result = dns_question_create_from_name(query_buffer, &lookup->key->name, lookup->key->type,
Expand Down
8 changes: 1 addition & 7 deletions src/net.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,6 @@
#define loop_sockets(sockets) \
for (socket_info_t *socket = (sockets)->data; socket < ((socket_info_t*)(sockets)->data) + (sockets)->len; socket++)

typedef enum
{
PROTO_IPV4 = 1 << 0,
PROTO_IPV6 = 1 << 1
} ip_support_t;

typedef enum
{
SOCKET_TYPE_INTERFACE,
Expand All @@ -37,7 +31,7 @@ typedef enum

typedef struct
{
ip_support_t protocol;
sa_family_t protocol;
int descriptor;
socket_type_t type;
void *data;
Expand Down

0 comments on commit 2b39408

Please sign in to comment.