summaryrefslogtreecommitdiff
path: root/ares_process.c
diff options
context:
space:
mode:
authorYang Tse <yangsita@gmail.com>2010-03-05 20:01:47 +0000
committerYang Tse <yangsita@gmail.com>2010-03-05 20:01:47 +0000
commit8fe746fcf2d5b54242a828840ccac630f7a4075a (patch)
tree0ae06cf5be407aea2129f1b47c59c1f433d425db /ares_process.c
parent249fc61b8cf1848c4444bef60fc6248930bd0d20 (diff)
downloadc-ares-8fe746fcf2d5b54242a828840ccac630f7a4075a.tar.gz
c-ares-8fe746fcf2d5b54242a828840ccac630f7a4075a.tar.bz2
c-ares-8fe746fcf2d5b54242a828840ccac630f7a4075a.zip
Added IPv6 name servers support
Diffstat (limited to 'ares_process.c')
-rw-r--r--ares_process.c125
1 files changed, 105 insertions, 20 deletions
diff --git a/ares_process.c b/ares_process.c
index 01036f5..ab0b79d 100644
--- a/ares_process.c
+++ b/ares_process.c
@@ -97,6 +97,7 @@ static int open_tcp_socket(ares_channel channel, struct server_state *server);
static int open_udp_socket(ares_channel channel, struct server_state *server);
static int same_questions(const unsigned char *qbuf, int qlen,
const unsigned char *abuf, int alen);
+static int same_address(struct sockaddr *sa, struct ares_addr *aa);
static void end_query(ares_channel channel, struct query *query, int status,
unsigned char *abuf, int alen);
@@ -434,8 +435,11 @@ 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;
ares_socklen_t fromlen;
+ union {
+ struct sockaddr_in sa4;
+ struct sockaddr_in6 sa6;
+ } from;
#endif
if(!read_fds && (read_fd == ARES_SOCKET_BAD))
@@ -471,7 +475,10 @@ static void read_udp_packets(ares_channel channel, fd_set *read_fds,
* packets as we can. */
do {
#ifdef HAVE_RECVFROM
- fromlen = sizeof(from);
+ if (server->addr.family == AF_INET)
+ fromlen = sizeof(from.sa4);
+ else
+ fromlen = sizeof(from.sa6);
count = (ssize_t)recvfrom(server->udp_socket, (void *)buf, sizeof(buf),
0, (struct sockaddr *)&from, &fromlen);
#else
@@ -482,10 +489,10 @@ static void read_udp_packets(ares_channel channel, fd_set *read_fds,
else if (count <= 0)
handle_error(channel, i, now);
#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 */
+ else if (!same_address((struct sockaddr *)&from, &server->addr))
+ /* The address the response comes from does not match
+ * the address we sent the request to. Someone may be
+ * attempting to perform a cache poisoning attack. */
break;
#endif
else
@@ -893,10 +900,39 @@ static int open_tcp_socket(ares_channel channel, struct server_state *server)
{
ares_socket_t s;
int opt;
- struct sockaddr_in sockin;
+ ares_socklen_t salen;
+ union {
+ struct sockaddr_in sa4;
+ struct sockaddr_in6 sa6;
+ } saddr;
+ struct sockaddr *sa;
+
+ switch (server->addr.family)
+ {
+ case AF_INET:
+ sa = (void *)&saddr.sa4;
+ salen = sizeof(saddr.sa4);
+ memset(sa, 0, salen);
+ saddr.sa4.sin_family = AF_INET;
+ saddr.sa4.sin_port = (unsigned short)(channel->tcp_port & 0xffff);
+ memcpy(&saddr.sa4.sin_addr, &server->addr.addrV4,
+ sizeof(server->addr.addrV4));
+ break;
+ case AF_INET6:
+ sa = (void *)&saddr.sa6;
+ salen = sizeof(saddr.sa6);
+ memset(sa, 0, salen);
+ saddr.sa6.sin6_family = AF_INET6;
+ saddr.sa6.sin6_port = (unsigned short)(channel->tcp_port & 0xffff);
+ memcpy(&saddr.sa6.sin6_addr, &server->addr.addrV6,
+ sizeof(server->addr.addrV6));
+ break;
+ default:
+ return -1;
+ }
/* 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;
@@ -924,11 +960,7 @@ static int open_tcp_socket(ares_channel channel, struct server_state *server)
#endif
/* 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, sa, salen) == -1)
{
int err = SOCKERRNO;
@@ -960,10 +992,39 @@ 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;
+ ares_socklen_t salen;
+ union {
+ struct sockaddr_in sa4;
+ struct sockaddr_in6 sa6;
+ } saddr;
+ struct sockaddr *sa;
+
+ switch (server->addr.family)
+ {
+ case AF_INET:
+ sa = (void *)&saddr.sa4;
+ salen = sizeof(saddr.sa4);
+ memset(sa, 0, salen);
+ saddr.sa4.sin_family = AF_INET;
+ saddr.sa4.sin_port = (unsigned short)(channel->udp_port & 0xffff);
+ memcpy(&saddr.sa4.sin_addr, &server->addr.addrV4,
+ sizeof(server->addr.addrV4));
+ break;
+ case AF_INET6:
+ sa = (void *)&saddr.sa6;
+ salen = sizeof(saddr.sa6);
+ memset(sa, 0, salen);
+ saddr.sa6.sin6_family = AF_INET6;
+ saddr.sa6.sin6_port = (unsigned short)(channel->udp_port & 0xffff);
+ memcpy(&saddr.sa6.sin6_addr, &server->addr.addrV6,
+ sizeof(server->addr.addrV6));
+ break;
+ default:
+ return -1;
+ }
/* 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;
@@ -975,11 +1036,7 @@ static int open_udp_socket(ares_channel channel, struct server_state *server)
}
/* 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, sa, salen) == -1)
{
int err = SOCKERRNO;
@@ -1086,6 +1143,34 @@ static int same_questions(const unsigned char *qbuf, int qlen,
return 1;
}
+static int same_address(struct sockaddr *sa, struct ares_addr *aa)
+{
+ void *addr1;
+ void *addr2;
+
+ if (sa->sa_family == aa->family)
+ {
+ switch (aa->family)
+ {
+ case AF_INET:
+ addr1 = &aa->addrV4;
+ addr2 = &((struct sockaddr_in *)sa)->sin_addr;
+ if (memcmp(addr1, addr2, sizeof(aa->addrV4)) == 0)
+ return 1; /* match */
+ break;
+ case AF_INET6:
+ addr1 = &aa->addrV6;
+ addr2 = &((struct sockaddr_in6 *)sa)->sin6_addr;
+ if (memcmp(addr1, addr2, sizeof(aa->addrV6)) == 0)
+ return 1; /* match */
+ break;
+ default:
+ break;
+ }
+ }
+ return 0; /* different */
+}
+
static void end_query (ares_channel channel, struct query *query, int status,
unsigned char *abuf, int alen)
{