replace hostent lookup with better performing in-memory copy.

the central dns resolver function proxy_gethostbyname() used
to iterate over the gethostent() db (/etc/hosts) on each dns
request.
since this is not threadsafe, we synchronized access to it
previously using mutexes. the parsing of this file is slow,
and blocking all threads to do it even moreso.
since gethostent_r() is only available on a few platforms,
i decided to read the hostent db once and then use a quick
in-memory lookup on further usage.

+ some further refactoring.
This commit is contained in:
rofl0r
2012-11-08 01:18:19 +01:00
parent c698d48c03
commit af5c6f0c6a
11 changed files with 208 additions and 39 deletions

View File

@ -13,13 +13,8 @@
#include "debug.h"
#include "ip_type.h"
#include "mutex.h"
struct stringpool mem;
static char *at_dumpstring(char* s, size_t len) {
PFUNC();
return stringpool_add(&mem, s, len);
}
#include "hash.h"
#include "stringdump.h"
/* stuff for our internal translation table */
@ -38,16 +33,6 @@ pthread_mutex_t internal_ips_lock;
internal_ip_lookup_table *internal_ips = NULL;
internal_ip_lookup_table internal_ips_buf;
uint32_t dalias_hash(char *s0) {
unsigned char *s = (void *) s0;
uint_fast32_t h = 0;
while(*s) {
h = 16 * h + *s++;
h ^= h >> 24 & 0xf0;
}
return h & 0xfffffff;
}
uint32_t index_from_internal_ip(ip_type internalip) {
PFUNC();
ip_type tmp = internalip;
@ -113,7 +98,7 @@ static ip_type ip_from_internal_list(char* name, size_t len) {
goto err_plus_unlock;
string_hash_tuple tmp = { 0 };
new_mem = at_dumpstring((char*) &tmp, sizeof(string_hash_tuple));
new_mem = dumpstring((char*) &tmp, sizeof(string_hash_tuple));
if(!new_mem)
goto oom;
@ -122,7 +107,7 @@ static ip_type ip_from_internal_list(char* name, size_t len) {
internal_ips->list[internal_ips->counter] = new_mem;
internal_ips->list[internal_ips->counter]->hash = hash;
new_mem = at_dumpstring((char*) name, len + 1);
new_mem = dumpstring((char*) name, len + 1);
if(!new_mem) {
internal_ips->list[internal_ips->counter] = 0;
@ -285,7 +270,6 @@ void at_init(void) {
memset(internal_ips, 0, sizeof *internal_ips);
initpipe(req_pipefd);
initpipe(resp_pipefd);
stringpool_init(&mem);
pthread_attr_init(&allocator_thread_attr);
pthread_attr_setstacksize(&allocator_thread_attr, 16 * 1024);
pthread_create(&allocator_thread, &allocator_thread_attr, threadfunc, 0);

View File

@ -34,8 +34,6 @@
#include <sys/time.h>
#include <stdarg.h>
#include <assert.h>
#include "mutex.h"
pthread_mutex_t hostdb_lock;
#include "core.h"
#include "common.h"
@ -666,12 +664,14 @@ int connect_proxy_chain(int sock, ip_type target_ip,
return -1;
}
#include "hostentdb.h"
struct hostent_list hl;
void core_initialize(void) {
MUTEX_INIT(&hostdb_lock);
hdb_init(&hl);
}
void core_unload(void) {
MUTEX_DESTROY(&hostdb_lock);
}
static void gethostbyname_data_setstring(struct gethostbyname_data* data, char* name) {
@ -682,9 +682,6 @@ static void gethostbyname_data_setstring(struct gethostbyname_data* data, char*
struct hostent *proxy_gethostbyname(const char *name, struct gethostbyname_data* data) {
PFUNC();
char buff[256];
size_t l = strlen(name);
struct hostent *hp;
data->resolved_addr_p[0] = (char *) &data->resolved_addr;
data->resolved_addr_p[1] = NULL;
@ -709,16 +706,13 @@ struct hostent *proxy_gethostbyname(const char *name, struct gethostbyname_data*
memset(buff, 0, sizeof(buff));
// this iterates over the "known hosts" db, usually /etc/hosts
MUTEX_LOCK(&hostdb_lock);
while((hp = gethostent()))
if(!strcmp(hp->h_name, name) && hp->h_addrtype == AF_INET && hp->h_length == sizeof(in_addr_t)) {
data->resolved_addr = *((in_addr_t*)(hp->h_addr_list[0]));
MUTEX_UNLOCK(&hostdb_lock);
goto retname;
}
MUTEX_UNLOCK(&hostdb_lock);
data->resolved_addr = at_get_ip_for_host((char*) name, l).as_int;
ip_type hdb_res = hdb_get(&hl, (char*) name);
if(hdb_res.as_int != ip_type_invalid.as_int) {
data->resolved_addr = hdb_res.as_int;
goto retname;
}
data->resolved_addr = at_get_ip_for_host((char*) name, strlen(name)).as_int;
if(data->resolved_addr == (in_addr_t) ip_type_invalid.as_int) return NULL;
retname:

12
src/hash.c Normal file
View File

@ -0,0 +1,12 @@
#include "hash.h"
/* dalias' version of the elf hash */
uint32_t dalias_hash(char *s0) {
unsigned char *s = (void *) s0;
uint_fast32_t h = 0;
while(*s) {
h = 16 * h + *s++;
h ^= h >> 24 & 0xf0;
}
return h & 0xfffffff;
}

10
src/hash.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef HASH_H
#define HASH_H
#include <stdint.h>
uint32_t dalias_hash(char *s0);
//RcB: DEP "hash.c"
#endif

56
src/hostentdb.c Normal file
View File

@ -0,0 +1,56 @@
#include <stdint.h>
#include <string.h>
#include <netdb.h>
#include <stdlib.h>
#include "ip_type.h"
#include "hash.h"
#include "stringdump.h"
#include "hostentdb.h"
#include "common.h"
#include "debug.h"
#define STEP 16
static void hdb_add(struct hostent_list* hl, char* host, ip_type ip) {
if(hl->count +1 > hl->capa) {
void * nu = realloc(hl->entries, (hl->capa + STEP) * sizeof(struct hostent_entry));
if(!nu) return;
hl->entries = nu;
hl->capa += STEP;
}
struct hostent_entry *h = &hl->entries[hl->count];
h->hash = dalias_hash(host);
h->ip.as_int = ip.as_int;
h->str = dumpstring(host, strlen(host) + 1);
if(h->str) hl->count++;
}
static void hdb_fill(struct hostent_list *hl) {
struct hostent* hp;
while((hp = gethostent()))
if(hp->h_addrtype == AF_INET && hp->h_length == sizeof(in_addr_t)) {
hdb_add(hl, hp->h_name, (ip_type) { .as_int = *((in_addr_t*)(hp->h_addr_list[0])) });
}
}
void hdb_init(struct hostent_list *hl) {
memset(hl, 0, sizeof *hl);
hdb_fill(hl);
}
ip_type hdb_get(struct hostent_list *hl, char* host) {
size_t i;
PFUNC();
uint32_t hash = dalias_hash(host);
for(i = 0; i < hl->count; i++) {
if(hl->entries[i].hash == hash && !strcmp(hl->entries[i].str, host)) {
#ifdef DEBUG
char ipbuf[16];
pc_stringfromipv4(hl->entries[i].ip.octet, ipbuf);
PDEBUG("got ip %s for hostent entry %s\n", ipbuf, host);
#endif
return hl->entries[i].ip;
}
}
return ip_type_invalid;
}

23
src/hostentdb.h Normal file
View File

@ -0,0 +1,23 @@
#ifndef HOSTENTDB_H
#define HOSTENTDB_H
#include "ip_type.h"
#include <unistd.h>
struct hostent_entry {
uint32_t hash;
ip_type ip;
char* str;
};
struct hostent_list {
size_t count;
size_t capa;
struct hostent_entry *entries;
};
void hdb_init(struct hostent_list *hl);
ip_type hdb_get(struct hostent_list *hl, char* host);
//RcB: DEP "hostendb.c"
#endif

View File

@ -94,9 +94,11 @@ static void* load_sym(char* symname, void* proxyfunc) {
#include "shm.h"
#include "allocator_thread.h"
#include "stringdump.h"
static void do_init(void) {
srand(time(NULL));
dumpstring_init(); // global string garbage can
core_initialize();
at_init();
@ -357,7 +359,7 @@ int getaddrinfo(const char *node, const char *service, const struct addrinfo *hi
INIT();
PDEBUG("getaddrinfo: %s %s\n", node, service);
PDEBUG("getaddrinfo: %s %s\n", node ? node : "null", service ? service : "null");
if(proxychains_resolver)
ret = proxy_getaddrinfo(node, service, hints, res);

13
src/stringdump.c Normal file
View File

@ -0,0 +1,13 @@
#include "stringdump.h"
#include "debug.h"
struct stringpool mem;
char *dumpstring(char* s, size_t len) {
PFUNC();
return stringpool_add(&mem, s, len);
}
void dumpstring_init(void) {
stringpool_init(&mem);
}

12
src/stringdump.h Normal file
View File

@ -0,0 +1,12 @@
#ifndef STRINGDUMP_H
#define STRINGDUMP_H
#include "shm.h"
#include <unistd.h>
char *dumpstring(char* s, size_t len);
void dumpstring_init(void);
//RcB: DEP "stringdump.h"
#endif