diff --git a/Makefile b/Makefile index bdaab44..481d904 100644 --- a/Makefile +++ b/Makefile @@ -15,7 +15,9 @@ sysconfdir=$(prefix)/etc SRCS = $(sort $(wildcard src/*.c)) OBJS = $(SRCS:.c=.o) -LOBJS = src/core.o src/common.o src/libproxychains.o src/shm.o src/allocator_thread.o src/ip_type.o +LOBJS = src/core.o src/common.o src/libproxychains.o src/shm.o \ + src/allocator_thread.o src/ip_type.o src/stringdump.o \ + src/hostentdb.o src/hash.o CFLAGS += -Wall -O0 -g -std=c99 -D_GNU_SOURCE -pipe LDFLAGS = -shared -fPIC -Wl,--no-as-needed -ldl -lpthread diff --git a/src/allocator_thread.c b/src/allocator_thread.c index 3ff0122..01aee47 100644 --- a/src/allocator_thread.c +++ b/src/allocator_thread.c @@ -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); diff --git a/src/core.c b/src/core.c index 5701948..e6bd5cb 100644 --- a/src/core.c +++ b/src/core.c @@ -34,8 +34,6 @@ #include #include #include -#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: diff --git a/src/hash.c b/src/hash.c new file mode 100644 index 000000000..792dd87 --- /dev/null +++ b/src/hash.c @@ -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; +} diff --git a/src/hash.h b/src/hash.h new file mode 100644 index 000000000..811e6f0 --- /dev/null +++ b/src/hash.h @@ -0,0 +1,10 @@ +#ifndef HASH_H +#define HASH_H + +#include + +uint32_t dalias_hash(char *s0); + +//RcB: DEP "hash.c" + +#endif diff --git a/src/hostentdb.c b/src/hostentdb.c new file mode 100644 index 000000000..1562162 --- /dev/null +++ b/src/hostentdb.c @@ -0,0 +1,56 @@ +#include +#include +#include +#include + +#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; +} \ No newline at end of file diff --git a/src/hostentdb.h b/src/hostentdb.h new file mode 100644 index 000000000..4f807d1 --- /dev/null +++ b/src/hostentdb.h @@ -0,0 +1,23 @@ +#ifndef HOSTENTDB_H +#define HOSTENTDB_H + +#include "ip_type.h" +#include + +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 diff --git a/src/libproxychains.c b/src/libproxychains.c index d293006..41b193b 100644 --- a/src/libproxychains.c +++ b/src/libproxychains.c @@ -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); diff --git a/src/stringdump.c b/src/stringdump.c new file mode 100644 index 000000000..ff946f0 --- /dev/null +++ b/src/stringdump.c @@ -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); +} diff --git a/src/stringdump.h b/src/stringdump.h new file mode 100644 index 000000000..4c16d6f --- /dev/null +++ b/src/stringdump.h @@ -0,0 +1,12 @@ +#ifndef STRINGDUMP_H +#define STRINGDUMP_H + +#include "shm.h" +#include + +char *dumpstring(char* s, size_t len); +void dumpstring_init(void); + +//RcB: DEP "stringdump.h" + +#endif diff --git a/tests/test_gethostent_r.c b/tests/test_gethostent_r.c new file mode 100644 index 000000000..c846775 --- /dev/null +++ b/tests/test_gethostent_r.c @@ -0,0 +1,61 @@ +#include +#include +#include +#include "../src/common.h" + +/* +int gethostent_r( + struct hostent *ret, char *buf, size_t buflen, + struct hostent **result, int *h_errnop); + +Glibc2 also has reentrant versions gethostent_r(), gethostbyaddr_r(), +gethostbyname_r() and gethostbyname2_r(). + +The caller supplies a hostent structure ret which will be filled in on success, +and a temporary work buffer buf of size buflen. +After the call, result will point to the result on success. +In case of an error or if no entry is found result will be NULL. +The functions return 0 on success and a nonzero error number on failure. +In addition to the errors returned by the nonreentrant versions of these functions, +if buf is too small, the functions will return ERANGE, and the call should be retried +with a larger buffer. +The global variable h_errno is not modified, but the address of a variable in which +to store error numbers is passed in h_errnop. +*/ + +void printhostent(struct hostent *hp) { + char ipbuf[16]; + pc_stringfromipv4(hp->h_addr_list[0], ipbuf); + printf("alias: %p, len: %d, name: %s, addrlist: %p, addrtype: %d, ip: %s\n", + hp->h_aliases, + hp->h_length, + hp->h_name, + hp->h_addr_list, + hp->h_addrtype, + ipbuf + ); +} + +int main(int argc, char** argv) { + struct hostent he_buf; + struct hostent *he_res; + char h_buf[1024]; + int ch_errno; + int ret; + do { + ret = gethostent_r(&he_buf, h_buf, sizeof(h_buf), &he_res, &ch_errno); + printf("ret: %d, h_errno: %d\n", ret, ch_errno); + if(ret != 0) { + errno = ret; + ret = -1; + } + if(ret == -1) { + perror("gethostent_r"); + break; + } + if(he_res) { + printhostent(he_res); + } + } while (he_res); + return 0; +} \ No newline at end of file