Add IPv6 support

This commit is contained in:
Miroslav Lichvar
2009-10-09 15:00:59 +02:00
parent 183d56fd40
commit 8265ff2890
32 changed files with 1709 additions and 770 deletions

View File

@@ -32,85 +32,134 @@
#include "sysincl.h"
#include "nameserv.h"
#include "util.h"
#include <resolv.h>
/* ================================================== */
#define MAXRETRIES 10
static unsigned int retries = 0;
static unsigned long
Name2IPAddress(const char *name, int retry)
int
DNS_Name2IPAddress(const char *name, IPAddr *addr, int retry)
{
struct hostent *host;
unsigned char *address0;
unsigned long result;
#ifdef HAVE_IPV6
struct addrinfo hints, *res, *ai;
int result;
memset(&hints, 0, sizeof (hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_ADDRCONFIG;
try_again:
host = gethostbyname(name);
if (host == NULL) {
if (retry && h_errno == TRY_AGAIN && retries < 10) {
result = getaddrinfo(name, NULL, &hints, &res);
if (result) {
if (retry && result == EAI_AGAIN && retries < MAXRETRIES) {
sleep(2 << retries);
retries++;
res_init();
goto try_again;
}
result = DNS_Failed_Address;
} else {
address0 = host->h_addr_list[0];
result = ((((unsigned long)address0[0])<<24) |
(((unsigned long)address0[1])<<16) |
(((unsigned long)address0[2])<<8) |
(((unsigned long)address0[3])));
return 0;
}
return result;
}
/* ================================================== */
unsigned long
DNS_Name2IPAddress(const char *name)
{
return Name2IPAddress(name, 0);
}
/* ================================================== */
unsigned long
DNS_Name2IPAddressRetry(const char *name)
{
return Name2IPAddress(name, 1);
}
/* ================================================== */
const char *
DNS_IPAddress2Name(unsigned long ip_addr)
{
struct hostent *host;
static char buffer[16];
unsigned int a, b, c, d;
uint32_t addr;
addr = htonl(ip_addr);
if (addr == 0UL) {
/* Catch this as a special case that will never resolve to
anything */
strcpy(buffer, "0.0.0.0");
return buffer;
} else {
host = gethostbyaddr((const char *) &addr, sizeof(ip_addr), AF_INET);
if (!host) {
a = (ip_addr >> 24) & 0xff;
b = (ip_addr >> 16) & 0xff;
c = (ip_addr >> 8) & 0xff;
d = (ip_addr) & 0xff;
snprintf(buffer, sizeof(buffer), "%u.%u.%u.%u", a, b, c, d);
return buffer;
} else {
return host->h_name;
for (ai = res; !result && ai != NULL; ai = ai->ai_next) {
switch (ai->ai_family) {
case AF_INET:
addr->family = IPADDR_INET4;
addr->addr.in4 = ntohl(((struct sockaddr_in *)ai->ai_addr)->sin_addr.s_addr);
result = 1;
break;
#ifdef HAVE_IPV6
case AF_INET6:
addr->family = IPADDR_INET6;
memcpy(&addr->addr.in6, &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr.s6_addr, sizeof (addr->addr.in6));
result = 1;
break;
#endif
}
}
freeaddrinfo(res);
return result;
#else
struct hostent *host;
char *address0;
try_again:
host = gethostbyname(name);
if (host == NULL) {
if (retry && h_errno == TRY_AGAIN && retries < MAXRETRIES) {
sleep(2 << retries);
retries++;
res_init();
goto try_again;
}
} else {
addr->family = IPADDR_INET4;
address0 = host->h_addr_list[0];
addr->addr.in4 = ((((unsigned long)address0[0])<<24) |
(((unsigned long)address0[1])<<16) |
(((unsigned long)address0[2])<<8) |
(((unsigned long)address0[3])));
return 1;
}
return 0;
#endif
}
/* ================================================== */
void
DNS_IPAddress2Name(IPAddr *ip_addr, char *name, int len)
{
#ifdef HAVE_IPV6
int result;
struct sockaddr_in in4;
struct sockaddr_in6 in6;
switch (ip_addr->family) {
case IPADDR_INET4:
memset(&in4, 0, sizeof (in4));
in4.sin_family = AF_INET;
in4.sin_addr.s_addr = htonl(ip_addr->addr.in4);
result = getnameinfo((const struct sockaddr *)&in4, sizeof (in4), name, len, NULL, 0, 0);
break;
case IPADDR_INET6:
memset(&in6, 0, sizeof (in6));
in6.sin6_family = AF_INET6;
memcpy(&in6.sin6_addr.s6_addr, ip_addr->addr.in6, sizeof (in6.sin6_addr.s6_addr));
result = getnameinfo((const struct sockaddr *)&in6, sizeof (in6), name, len, NULL, 0, 0);
break;
default:
result = 1;
}
if (result)
snprintf(name, len, "%s", UTI_IPToString(ip_addr));
#else
struct hostent *host;
uint32_t addr;
switch (ip_addr->family) {
case IPADDR_INET4:
addr = htonl(ip_addr->addr.in4);
host = gethostbyaddr((const char *) &addr, sizeof (ip_addr), AF_INET);
break;
#ifdef HAVE_IPV6
case IPADDR_INET6:
host = gethostbyaddr((const void *) ip_addr->addr.in6, sizeof (ip_addr->addr.in6), AF_INET6);
break;
#endif
default:
host = NULL;
}
snprintf(name, len, "%s", host ? host->h_name : UTI_IPToString(ip_addr));
#endif
}
/* ================================================== */