diff options
Diffstat (limited to 'ares_process.c')
-rw-r--r-- | ares_process.c | 90 |
1 files changed, 67 insertions, 23 deletions
diff --git a/ares_process.c b/ares_process.c index 71f9394..689d1c1 100644 --- a/ares_process.c +++ b/ares_process.c @@ -434,7 +434,7 @@ static void read_udp_packets(ares_channel channel, fd_set *read_fds, ssize_t count; unsigned char buf[PACKETSZ + 1]; #ifdef HAVE_RECVFROM - struct sockaddr_in from; + struct sockaddr_storage from; ares_socklen_t fromlen; #endif @@ -480,16 +480,32 @@ static void read_udp_packets(ares_channel channel, fd_set *read_fds, if (count == -1 && try_again(SOCKERRNO)) continue; else if (count <= 0) - handle_error(channel, i, now); + { + handle_error(channel, i, now); + break; + } #ifdef HAVE_RECVFROM - else if (from.sin_addr.s_addr != server->addr.s_addr) - /* Address response came from did not match the address - * we sent the request to. Someone may be attempting - * to perform a cache poisoning attack */ - break; + /* Check if address response came from did match the address + * we sent the request to. Someone may be attempting + * to perform a cache poisoning attack */ + else if (from.ss_family == AF_INET) + { + struct sockaddr_in *from4 = (struct sockaddr_in *) &from; + struct sockaddr_in *srv4 = (struct sockaddr_in *) server->addr->ai_addr; + if (from4->sin_addr.s_addr != srv4->sin_addr.s_addr) + break; + } + else if (from.ss_family == AF_INET6) + { + struct sockaddr_in6 *from6 = (struct sockaddr_in6 *) &from; + struct sockaddr_in6 *srv6 = (struct sockaddr_in6 *) server->addr->ai_addr; + if (memcmp(from6->sin6_addr.s6_addr, + srv6->sin6_addr.s6_addr, + 16)) /* FIXME - is there any portable constant? */ + break; + } #endif - else - process_answer(channel, buf, (int)count, i, 0, now); + process_answer(channel, buf, (int)count, i, 0, now); } while (count > 0); } } @@ -889,14 +905,39 @@ static int configure_socket(ares_socket_t s, ares_channel channel) return 0; } +static int addrinfo_set_port(struct addrinfo *addr, int port) +{ + int rc = ARES_SUCCESS; + struct sockaddr_in *sockin = NULL; + struct sockaddr_in6 *sockin6 = NULL; + + switch (addr->ai_family) + { + case AF_INET: + sockin = (struct sockaddr_in *) addr->ai_addr; + sockin->sin_port = (unsigned short)(port & 0xffff); + break; + + case AF_INET6: + sockin6 = (struct sockaddr_in6 *) addr->ai_addr; + sockin6->sin6_port = (unsigned short)(port & 0xffff); + break; + + default: + rc = ARES_EBADFAMILY; + break; + } + + return rc; +} + static int open_tcp_socket(ares_channel channel, struct server_state *server) { ares_socket_t s; int opt; - struct sockaddr_in sockin; /* Acquire a socket. */ - s = socket(AF_INET, SOCK_STREAM, 0); + s = socket(server->addr->ai_family, SOCK_STREAM, 0); if (s == ARES_SOCKET_BAD) return -1; @@ -923,12 +964,14 @@ static int open_tcp_socket(ares_channel channel, struct server_state *server) } #endif + if (addrinfo_set_port(server->addr, channel->tcp_port) != ARES_SUCCESS) + { + sclose(s); + return -1; + } + /* Connect to the server. */ - memset(&sockin, 0, sizeof(sockin)); - sockin.sin_family = AF_INET; - sockin.sin_addr = server->addr; - sockin.sin_port = (unsigned short)(channel->tcp_port & 0xffff); - if (connect(s, (struct sockaddr *) &sockin, sizeof(sockin)) == -1) + if (connect(s, server->addr->ai_addr, server->addr->ai_addrlen) == -1) { int err = SOCKERRNO; @@ -960,10 +1003,9 @@ static int open_tcp_socket(ares_channel channel, struct server_state *server) static int open_udp_socket(ares_channel channel, struct server_state *server) { ares_socket_t s; - struct sockaddr_in sockin; /* Acquire a socket. */ - s = socket(AF_INET, SOCK_DGRAM, 0); + s = socket(server->addr->ai_family, SOCK_DGRAM, 0); if (s == ARES_SOCKET_BAD) return -1; @@ -974,12 +1016,14 @@ static int open_udp_socket(ares_channel channel, struct server_state *server) return -1; } + if (addrinfo_set_port(server->addr, channel->udp_port) != ARES_SUCCESS) + { + sclose(s); + return -1; + } + /* Connect to the server. */ - memset(&sockin, 0, sizeof(sockin)); - sockin.sin_family = AF_INET; - sockin.sin_addr = server->addr; - sockin.sin_port = (unsigned short)(channel->udp_port & 0xffff); - if (connect(s, (struct sockaddr *) &sockin, sizeof(sockin)) == -1) + if (connect(s, server->addr->ai_addr, server->addr->ai_addrlen) == -1) { int err = SOCKERRNO; |