diff options
Diffstat (limited to 'ares/ares_process.c')
-rw-r--r-- | ares/ares_process.c | 125 |
1 files changed, 105 insertions, 20 deletions
diff --git a/ares/ares_process.c b/ares/ares_process.c index 01036f5be..ab0b79dc6 100644 --- a/ares/ares_process.c +++ b/ares/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) { |