Frédéric Perrin patch for ipv6 reverse resolution via address structure that
retains IP family.
This commit is contained in:
129
resolver.c
129
resolver.c
@@ -25,7 +25,18 @@
|
|||||||
|
|
||||||
#define RESOLVE_QUEUE_LENGTH 20
|
#define RESOLVE_QUEUE_LENGTH 20
|
||||||
|
|
||||||
struct in6_addr resolve_queue[RESOLVE_QUEUE_LENGTH];
|
struct addr_storage {
|
||||||
|
int af; /* AF_INET or AF_INET6 */
|
||||||
|
int len; /* sizeof(struct in_addr or in6_addr) */
|
||||||
|
union {
|
||||||
|
struct in_addr addr4;
|
||||||
|
struct in6_addr addr6;
|
||||||
|
} addr;
|
||||||
|
#define as_addr4 addr.addr4
|
||||||
|
#define as_addr6 addr.addr6
|
||||||
|
};
|
||||||
|
|
||||||
|
struct addr_storage resolve_queue[RESOLVE_QUEUE_LENGTH];
|
||||||
|
|
||||||
pthread_cond_t resolver_queue_cond;
|
pthread_cond_t resolver_queue_cond;
|
||||||
pthread_mutex_t resolver_queue_mutex;
|
pthread_mutex_t resolver_queue_mutex;
|
||||||
@@ -55,48 +66,37 @@ extern options_t options;
|
|||||||
* as NetBSD break the RFC and implement it in a non-thread-safe fashion, so
|
* as NetBSD break the RFC and implement it in a non-thread-safe fashion, so
|
||||||
* for the moment, the configure script won't try to use it.
|
* for the moment, the configure script won't try to use it.
|
||||||
*/
|
*/
|
||||||
char *do_resolve(struct in6_addr *addr) {
|
char *do_resolve(struct addr_storage *addr) {
|
||||||
struct sockaddr_in sin;
|
struct sockaddr_in sin;
|
||||||
struct sockaddr_in6 sin6;
|
struct sockaddr_in6 sin6;
|
||||||
char buf[NI_MAXHOST]; /* 1025 */
|
char buf[NI_MAXHOST]; /* 1025 */
|
||||||
int res, af;
|
int ret;
|
||||||
uint32_t* probe;
|
|
||||||
|
|
||||||
memset(&sin, '\0', sizeof(sin));
|
switch (addr->af) {
|
||||||
memset(&sin6, '\0', sizeof(sin6));
|
|
||||||
|
|
||||||
/* If the upper three (network byte order) uint32-parts
|
|
||||||
* are null, then there ought to be an IPv4 address here.
|
|
||||||
* Any such IPv6 would have to be 'xxxx::'. Neglectable? */
|
|
||||||
probe = (uint32_t *) addr;
|
|
||||||
af = (probe[1] || probe[2] || probe[3]) ? AF_INET6 : AF_INET;
|
|
||||||
|
|
||||||
switch (af) {
|
|
||||||
case AF_INET:
|
case AF_INET:
|
||||||
sin.sin_family = af;
|
sin.sin_family = addr->af;
|
||||||
sin.sin_port = 0;
|
sin.sin_port = 0;
|
||||||
memcpy(&sin.sin_addr, addr, sizeof(sin.sin_addr));
|
memcpy(&sin.sin_addr, &addr->as_addr4, addr->len);
|
||||||
|
|
||||||
if (getnameinfo((struct sockaddr*)&sin, sizeof sin,
|
ret = getnameinfo((struct sockaddr*)&sin, sizeof sin,
|
||||||
buf, sizeof buf, NULL, 0, NI_NAMEREQD) == 0)
|
buf, sizeof buf, NULL, 0, NI_NAMEREQD);
|
||||||
return xstrdup(buf);
|
|
||||||
else
|
|
||||||
return NULL;
|
|
||||||
break;
|
break;
|
||||||
case AF_INET6:
|
case AF_INET6:
|
||||||
sin6.sin6_family = af;
|
sin6.sin6_family = addr->af;
|
||||||
sin6.sin6_port = 0;
|
sin6.sin6_port = 0;
|
||||||
memcpy(&sin6.sin6_addr, addr, sizeof(sin6.sin6_addr));
|
memcpy(&sin6.sin6_addr, &addr->as_addr6, addr->len);
|
||||||
|
|
||||||
if (getnameinfo((struct sockaddr*)&sin6, sizeof sin6,
|
ret = getnameinfo((struct sockaddr*)&sin6, sizeof sin6,
|
||||||
buf, sizeof buf, NULL, 0, NI_NAMEREQD) == 0)
|
buf, sizeof buf, NULL, 0, NI_NAMEREQD);
|
||||||
return xstrdup(buf);
|
break;
|
||||||
else
|
|
||||||
return NULL;
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ret == 0)
|
||||||
|
return xstrdup(buf);
|
||||||
|
else
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif defined(USE_GETHOSTBYADDR_R)
|
#elif defined(USE_GETHOSTBYADDR_R)
|
||||||
@@ -106,7 +106,7 @@ char *do_resolve(struct in6_addr *addr) {
|
|||||||
* Some implementations of libc choose to implement gethostbyaddr_r as
|
* Some implementations of libc choose to implement gethostbyaddr_r as
|
||||||
* a non thread-safe wrapper to gethostbyaddr. An interesting choice...
|
* a non thread-safe wrapper to gethostbyaddr. An interesting choice...
|
||||||
*/
|
*/
|
||||||
char* do_resolve(struct in_addr * addr) {
|
char* do_resolve(struct addr_storage *addr) {
|
||||||
struct hostent hostbuf, *hp;
|
struct hostent hostbuf, *hp;
|
||||||
size_t hstbuflen = 1024;
|
size_t hstbuflen = 1024;
|
||||||
char *tmphstbuf;
|
char *tmphstbuf;
|
||||||
@@ -114,19 +114,19 @@ char* do_resolve(struct in_addr * addr) {
|
|||||||
int herr;
|
int herr;
|
||||||
char * ret = NULL;
|
char * ret = NULL;
|
||||||
|
|
||||||
/* Allocate buffer, remember to free it to avoid memory leakage. */
|
/* Allocate buffer, remember to free it to avoid memory leakage. */
|
||||||
tmphstbuf = xmalloc (hstbuflen);
|
tmphstbuf = xmalloc (hstbuflen);
|
||||||
|
|
||||||
/* Some machines have gethostbyaddr_r returning an integer error code; on
|
/* Some machines have gethostbyaddr_r returning an integer error code; on
|
||||||
* others, it returns a struct hostent*. */
|
* others, it returns a struct hostent*. */
|
||||||
#ifdef GETHOSTBYADDR_R_RETURNS_INT
|
#ifdef GETHOSTBYADDR_R_RETURNS_INT
|
||||||
while ((res = gethostbyaddr_r((char*)addr, sizeof(struct in_addr), AF_INET,
|
while ((res = gethostbyaddr_r((char*)&addr->addr, addr->len, addr->af,
|
||||||
&hostbuf, tmphstbuf, hstbuflen,
|
&hostbuf, tmphstbuf, hstbuflen,
|
||||||
&hp, &herr)) == ERANGE)
|
&hp, &herr)) == ERANGE)
|
||||||
#else
|
#else
|
||||||
/* ... also assume one fewer argument.... */
|
/* ... also assume one fewer argument.... */
|
||||||
while ((hp = gethostbyaddr_r((char*)addr, sizeof(struct in_addr), AF_INET,
|
while ((hp = gethostbyaddr_r((char*)&addr->addr, addr->len, addr->af,
|
||||||
&hostbuf, tmphstbuf, hstbuflen, &herr)) == NULL
|
&hostbuf, tmphstbuf, hstbuflen, &herr)) == NULL
|
||||||
&& errno == ERANGE)
|
&& errno == ERANGE)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
@@ -152,22 +152,22 @@ char* do_resolve(struct in_addr * addr) {
|
|||||||
#elif defined(USE_GETHOSTBYADDR)
|
#elif defined(USE_GETHOSTBYADDR)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation using gethostbyaddr. Since this is nonreentrant, we have to
|
* Implementation using gethostbyname. Since this is nonreentrant, we have to
|
||||||
* wrap it in a mutex, losing all benefit of multithreaded resolution.
|
* wrap it in a mutex, losing all benefit of multithreaded resolution.
|
||||||
*/
|
*/
|
||||||
char *do_resolve(struct in6_addr *addr) {
|
char *do_resolve(struct addr_storage *addr) {
|
||||||
static pthread_mutex_t ghba_mtx = PTHREAD_MUTEX_INITIALIZER;
|
static pthread_mutex_t ghba_mtx = PTHREAD_MUTEX_INITIALIZER;
|
||||||
char *s = NULL;
|
char *s = NULL;
|
||||||
struct hostent *he;
|
struct hostent *he;
|
||||||
|
|
||||||
pthread_mutex_lock(&ghba_mtx);
|
pthread_mutex_lock(&ghba_mtx);
|
||||||
he = gethostbyaddr((char*)addr, sizeof *addr, AF_INET);
|
he = gethostbyaddr((char*)&addr->addr, addr->len, addr->af);
|
||||||
if (he)
|
if (he)
|
||||||
s = xstrdup(he->h_name);
|
s = xstrdup(he->h_name);
|
||||||
pthread_mutex_unlock(&ghba_mtx);
|
pthread_mutex_unlock(&ghba_mtx);
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#elif defined(USE_LIBRESOLV)
|
#elif defined(USE_LIBRESOLV)
|
||||||
|
|
||||||
#include <arpa/nameser.h>
|
#include <arpa/nameser.h>
|
||||||
@@ -177,14 +177,17 @@ char *do_resolve(struct in6_addr *addr) {
|
|||||||
* libresolv implementation
|
* libresolv implementation
|
||||||
* resolver functions may not be thread safe
|
* resolver functions may not be thread safe
|
||||||
*/
|
*/
|
||||||
char* do_resolve(struct in6_addr * addr) {
|
char* do_resolve(struct addr_storage *addr) {
|
||||||
char msg[PACKETSZ];
|
char msg[PACKETSZ];
|
||||||
char s[35];
|
char s[35];
|
||||||
int l;
|
int l;
|
||||||
unsigned char* a;
|
unsigned char* a;
|
||||||
char * ret = NULL;
|
char * ret = NULL;
|
||||||
|
|
||||||
a = (unsigned char*)addr;
|
if (addr->af != AF_INET)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
a = (unsigned char*)&addr->addr;
|
||||||
|
|
||||||
snprintf(s, 35, "%d.%d.%d.%d.in-addr.arpa.",a[3], a[2], a[1], a[0]);
|
snprintf(s, 35, "%d.%d.%d.%d.in-addr.arpa.",a[3], a[2], a[1], a[0]);
|
||||||
|
|
||||||
@@ -242,7 +245,7 @@ static void do_resolve_ares_callback(void *arg, int status, unsigned char *abuf,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
char *do_resolve(struct in6_addr * addr) {
|
char *do_resolve(struct addr_storage * addr) {
|
||||||
struct ares_callback_comm C;
|
struct ares_callback_comm C;
|
||||||
char s[35];
|
char s[35];
|
||||||
unsigned char *a;
|
unsigned char *a;
|
||||||
@@ -251,6 +254,9 @@ char *do_resolve(struct in6_addr * addr) {
|
|||||||
static pthread_key_t ares_key;
|
static pthread_key_t ares_key;
|
||||||
static int gotkey;
|
static int gotkey;
|
||||||
|
|
||||||
|
if (addr->af != AF_INET)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
/* Make sure we have an ARES channel for this thread. */
|
/* Make sure we have an ARES channel for this thread. */
|
||||||
pthread_mutex_lock(&ares_init_mtx);
|
pthread_mutex_lock(&ares_init_mtx);
|
||||||
if (!gotkey) {
|
if (!gotkey) {
|
||||||
@@ -267,11 +273,11 @@ char *do_resolve(struct in6_addr * addr) {
|
|||||||
if (ares_init(chan) != ARES_SUCCESS) return NULL;
|
if (ares_init(chan) != ARES_SUCCESS) return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
a = (unsigned char*)addr;
|
a = (unsigned char*)&addr->as_addr4;
|
||||||
sprintf(s, "%d.%d.%d.%d.in-addr.arpa.", a[3], a[2], a[1], a[0]);
|
sprintf(s, "%d.%d.%d.%d.in-addr.arpa.", a[3], a[2], a[1], a[0]);
|
||||||
|
|
||||||
C.result = 0;
|
C.result = 0;
|
||||||
C.addr = addr;
|
C.addr = &addr->as_addr4;
|
||||||
ares_query(*chan, s, C_IN, T_PTR, do_resolve_ares_callback, &C);
|
ares_query(*chan, s, C_IN, T_PTR, do_resolve_ares_callback, &C);
|
||||||
while (C.result == 0) {
|
while (C.result == 0) {
|
||||||
int n;
|
int n;
|
||||||
@@ -308,13 +314,13 @@ char *do_resolve(struct in6_addr * addr) {
|
|||||||
|
|
||||||
int forking_resolver_worker(int fd) {
|
int forking_resolver_worker(int fd) {
|
||||||
while (1) {
|
while (1) {
|
||||||
struct in_addr a;
|
struct addr_storage a;
|
||||||
struct hostent *he;
|
struct hostent *he;
|
||||||
char buf[NAMESIZE] = {0};
|
char buf[NAMESIZE] = {0};
|
||||||
if (read(fd, &a, sizeof a) != sizeof a)
|
if (read(fd, &a, sizeof a) != sizeof a)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
he = gethostbyaddr((char*)&a, sizeof a, AF_INET);
|
he = gethostbyaddr((char*)&a.addr, a.len, a.af);
|
||||||
if (he)
|
if (he)
|
||||||
strncpy(buf, he->h_name, NAMESIZE - 1);
|
strncpy(buf, he->h_name, NAMESIZE - 1);
|
||||||
|
|
||||||
@@ -388,7 +394,7 @@ char *do_resolve(struct in6_addr *addr) {
|
|||||||
|
|
||||||
# warning No name resolution method specified; name resolution will not work
|
# warning No name resolution method specified; name resolution will not work
|
||||||
|
|
||||||
char *do_resolve(struct in6_addr *addr) {
|
char *do_resolve(struct addr_storage *addr) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -406,7 +412,7 @@ void resolver_worker(void* ptr) {
|
|||||||
/* Keep resolving until the queue is empty */
|
/* Keep resolving until the queue is empty */
|
||||||
while(head != tail) {
|
while(head != tail) {
|
||||||
char * hostname;
|
char * hostname;
|
||||||
struct in6_addr addr = resolve_queue[tail];
|
struct addr_storage addr = resolve_queue[tail];
|
||||||
|
|
||||||
/* mutex always locked at this point */
|
/* mutex always locked at this point */
|
||||||
|
|
||||||
@@ -457,36 +463,47 @@ void resolver_initialise() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void resolve(int af, struct in6_addr* addr, char* result, int buflen) {
|
void resolve(int af, void* addr, char* result, int buflen) {
|
||||||
char* hostname;
|
char* hostname;
|
||||||
union {
|
union {
|
||||||
char **ch_pp;
|
char **ch_pp;
|
||||||
void **void_pp;
|
void **void_pp;
|
||||||
} u_hostname = { &hostname };
|
} u_hostname = { &hostname };
|
||||||
int added = 0;
|
int added = 0;
|
||||||
|
struct addr_storage *raddr;
|
||||||
|
|
||||||
|
raddr = malloc(sizeof *raddr);
|
||||||
|
memset(raddr, 0, sizeof *raddr);
|
||||||
|
raddr->af = af;
|
||||||
|
raddr->len = (af == AF_INET ? sizeof(struct in_addr)
|
||||||
|
: sizeof(struct in6_addr));
|
||||||
|
memcpy(&raddr->addr, addr, raddr->len);
|
||||||
|
|
||||||
if(options.dnsresolution == 1) {
|
if(options.dnsresolution == 1) {
|
||||||
|
|
||||||
pthread_mutex_lock(&resolver_queue_mutex);
|
pthread_mutex_lock(&resolver_queue_mutex);
|
||||||
|
|
||||||
if(hash_find(ns_hash, addr, u_hostname.void_pp) == HASH_STATUS_OK) {
|
if(hash_find(ns_hash, raddr, u_hostname.void_pp) == HASH_STATUS_OK) {
|
||||||
/* Found => already resolved, or on the queue */
|
/* Found => already resolved, or on the queue, no need to keep
|
||||||
|
* it around */
|
||||||
|
free(raddr);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
hostname = xmalloc(INET6_ADDRSTRLEN);
|
hostname = xmalloc(INET6_ADDRSTRLEN);
|
||||||
inet_ntop(af, addr, hostname, INET6_ADDRSTRLEN);
|
inet_ntop(af, &raddr->addr, hostname, INET6_ADDRSTRLEN);
|
||||||
hash_insert(ns_hash, addr, hostname);
|
|
||||||
|
hash_insert(ns_hash, raddr, hostname);
|
||||||
|
|
||||||
if(((head + 1) % RESOLVE_QUEUE_LENGTH) == tail) {
|
if(((head + 1) % RESOLVE_QUEUE_LENGTH) == tail) {
|
||||||
/* queue full */
|
/* queue full */
|
||||||
}
|
}
|
||||||
else if((af == AF_INET6)
|
else if ((af == AF_INET6)
|
||||||
&& (IN6_IS_ADDR_LINKLOCAL(addr)
|
&& (IN6_IS_ADDR_LINKLOCAL(&raddr->as_addr6)
|
||||||
|| IN6_IS_ADDR_SITELOCAL(addr))) {
|
|| IN6_IS_ADDR_SITELOCAL(&raddr->as_addr6))) {
|
||||||
/* Link-local and site-local stay numerical. */
|
/* Link-local and site-local stay numerical. */
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
resolve_queue[head] = *addr;
|
resolve_queue[head] = *raddr;
|
||||||
head = (head + 1) % RESOLVE_QUEUE_LENGTH;
|
head = (head + 1) % RESOLVE_QUEUE_LENGTH;
|
||||||
added = 1;
|
added = 1;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user