version 1.1, 2012/02/21 16:57:34
|
version 1.1.1.2, 2016/10/18 14:04:50
|
Line 25
|
Line 25
|
|
|
#define RESOLVE_QUEUE_LENGTH 20 |
#define RESOLVE_QUEUE_LENGTH 20 |
|
|
struct in_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; |
|
|
Line 55 extern options_t options;
|
Line 66 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 in_addr *addr) { | char *do_resolve(struct addr_storage *addr) { |
struct sockaddr_in sin = {0}; | struct sockaddr_in sin; |
| struct sockaddr_in6 sin6; |
char buf[NI_MAXHOST]; /* 1025 */ |
char buf[NI_MAXHOST]; /* 1025 */ |
int res; | int ret; |
sin.sin_family = AF_INET; | |
sin.sin_addr = *addr; | |
sin.sin_port = 0; | |
|
|
if (getnameinfo((struct sockaddr*)&sin, sizeof sin, buf, sizeof buf, NULL, 0, NI_NAMEREQD) == 0) | switch (addr->af) { |
| case AF_INET: |
| sin.sin_family = addr->af; |
| sin.sin_port = 0; |
| memcpy(&sin.sin_addr, &addr->as_addr4, addr->len); |
| |
| ret = getnameinfo((struct sockaddr*)&sin, sizeof sin, |
| buf, sizeof buf, NULL, 0, NI_NAMEREQD); |
| break; |
| case AF_INET6: |
| sin6.sin6_family = addr->af; |
| sin6.sin6_port = 0; |
| memcpy(&sin6.sin6_addr, &addr->as_addr6, addr->len); |
| |
| ret = getnameinfo((struct sockaddr*)&sin6, sizeof sin6, |
| buf, sizeof buf, NULL, 0, NI_NAMEREQD); |
| break; |
| default: |
| return NULL; |
| } |
| |
| if (ret == 0) |
return xstrdup(buf); |
return xstrdup(buf); |
else |
else |
return NULL; |
return NULL; |
Line 76 char *do_resolve(struct in_addr *addr) {
|
Line 106 char *do_resolve(struct in_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 = NULL; |
size_t hstbuflen = 1024; |
size_t hstbuflen = 1024; |
char *tmphstbuf; |
char *tmphstbuf; |
int res; | int res = 0; |
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); |
|
|
|
/* nss-myhostname's gethostbyaddr_r() causes an assertion failure if an |
|
* "invalid" (as in outside of IPv4 or IPv6) address family is passed */ |
|
if (addr->af == AF_INET || addr->af == AF_INET6) { |
|
|
/* 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 |
{ |
{ |
Line 105 char* do_resolve(struct in_addr * addr) {
|
Line 139 char* do_resolve(struct in_addr * addr) {
|
hstbuflen *= 2; |
hstbuflen *= 2; |
tmphstbuf = realloc (tmphstbuf, hstbuflen); |
tmphstbuf = realloc (tmphstbuf, hstbuflen); |
} |
} |
|
} |
|
|
/* Check for errors. */ |
/* Check for errors. */ |
if (res || hp == NULL) { |
if (res || hp == NULL) { |
Line 125 char* do_resolve(struct in_addr * addr) {
|
Line 160 char* do_resolve(struct in_addr * addr) {
|
* Implementation using gethostbyname. 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 in_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); |
Line 147 char *do_resolve(struct in_addr *addr) {
|
Line 182 char *do_resolve(struct in_addr *addr) {
|
* libresolv implementation |
* libresolv implementation |
* resolver functions may not be thread safe |
* resolver functions may not be thread safe |
*/ |
*/ |
char* do_resolve(struct in_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]); |
|
|
l = res_search(s, C_IN, T_PTR, msg, PACKETSZ); |
l = res_search(s, C_IN, T_PTR, msg, PACKETSZ); |
Line 212 static void do_resolve_ares_callback(void *arg, int st
|
Line 250 static void do_resolve_ares_callback(void *arg, int st
|
} |
} |
} |
} |
|
|
char *do_resolve(struct in_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; |
Line 221 char *do_resolve(struct in_addr * addr) {
|
Line 259 char *do_resolve(struct in_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) { |
Line 237 char *do_resolve(struct in_addr * addr) {
|
Line 278 char *do_resolve(struct in_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; |
Line 278 char *do_resolve(struct in_addr * addr) {
|
Line 319 char *do_resolve(struct in_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); |
|
|
Line 293 int forking_resolver_worker(int fd) {
|
Line 334 int forking_resolver_worker(int fd) {
|
} |
} |
} |
} |
|
|
char *do_resolve(struct in_addr *addr) { | char *do_resolve(struct in6_addr *addr) { |
struct { |
struct { |
int fd; |
int fd; |
pid_t child; |
pid_t child; |
Line 358 char *do_resolve(struct in_addr *addr) {
|
Line 399 char *do_resolve(struct in_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 in_addr *addr) { | char *do_resolve(struct addr_storage *addr) { |
return NULL; |
return NULL; |
} |
} |
|
|
Line 376 void resolver_worker(void* ptr) {
|
Line 417 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 in_addr addr = resolve_queue[tail]; | struct addr_storage addr = resolve_queue[tail]; |
|
|
/* mutex always locked at this point */ |
/* mutex always locked at this point */ |
|
|
Line 427 void resolver_initialise() {
|
Line 468 void resolver_initialise() {
|
|
|
} |
} |
|
|
void resolve(struct in_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; |
|
|
if(options.dnsresolution == 1) { |
if(options.dnsresolution == 1) { |
|
|
|
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); |
|
|
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 = strdup(inet_ntoa(*addr)); | hostname = xmalloc(INET6_ADDRSTRLEN); |
hash_insert(ns_hash, addr, hostname); | inet_ntop(af, &raddr->addr, hostname, INET6_ADDRSTRLEN); |
|
|
|
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) |
|
&& (IN6_IS_ADDR_LINKLOCAL(&raddr->as_addr6) |
|
|| IN6_IS_ADDR_SITELOCAL(&raddr->as_addr6))) { |
|
/* 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; |
} |
} |