From be7c4f5806a29298988601f9bac5a4ebab6c000c Mon Sep 17 00:00:00 2001 From: Jakub Hrozek Date: Mon, 1 Feb 2010 21:23:59 +0100 Subject: Allow the use of IPv6 nameservers This patch allows the use of IPv6 addresses for nameserves in both /etc/resolv.conf and by using the ares_set_nameservers() API. --- ares_process.c | 95 ++++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 72 insertions(+), 23 deletions(-) (limited to 'ares_process.c') diff --git a/ares_process.c b/ares_process.c index 71f9394..65b95f4 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,29 @@ 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) + { + if (((struct sockaddr_in *) &from)->sin_addr.s_addr != + server->addr.addrV4.s_addr) + break; + } + else if (from.ss_family == AF_INET6) + { + if (memcmp(((struct sockaddr_in6 *) &from)->sin6_addr.s6_addr, + server->addr.addrV6.s6_addr, + 16)) + 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 +902,44 @@ static int configure_socket(ares_socket_t s, ares_channel channel) return 0; } +static int prepare_addrinfo(struct server_state *server, int port, + struct sockaddr_storage *addr) +{ + const unsigned short sh_port = (unsigned short)(port & 0xffff); + int rc = ARES_SUCCESS; + + switch (server->addr.family) + { + case AF_INET: + ((struct sockaddr_in *) addr)->sin_family = AF_INET; + ((struct sockaddr_in *) addr)->sin_port = sh_port; + ((struct sockaddr_in *) addr)->sin_addr.s_addr = server->addr.addrV4.s_addr; + break; + + case AF_INET6: + ((struct sockaddr_in6 *) addr)->sin6_family = AF_INET6; + ((struct sockaddr_in6 *) addr)->sin6_port = sh_port; + memcpy(((struct sockaddr_in6 *) addr)->sin6_addr.s6_addr, + server->addr.addrV6.s6_addr, + 16); + 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; + struct sockaddr_storage addr; /* Acquire a socket. */ - s = socket(AF_INET, SOCK_STREAM, 0); + s = socket(server->addr.family, SOCK_STREAM, 0); if (s == ARES_SOCKET_BAD) return -1; @@ -923,12 +966,15 @@ static int open_tcp_socket(ares_channel channel, struct server_state *server) } #endif + if (prepare_addrinfo(server, channel->tcp_port, &addr) != 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, (struct sockaddr *) &addr, + sizeof(struct sockaddr_storage)) == -1) { int err = SOCKERRNO; @@ -960,10 +1006,10 @@ 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; + struct sockaddr_storage addr; /* Acquire a socket. */ - s = socket(AF_INET, SOCK_DGRAM, 0); + s = socket(server->addr.family, SOCK_DGRAM, 0); if (s == ARES_SOCKET_BAD) return -1; @@ -974,12 +1020,15 @@ static int open_udp_socket(ares_channel channel, struct server_state *server) return -1; } + if (prepare_addrinfo(server, channel->udp_port, &addr) != 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, (struct sockaddr *) &addr, + sizeof(struct sockaddr_storage)) == -1) { int err = SOCKERRNO; -- cgit