diff --git a/Makefile b/Makefile index 1c3c7bb..4a5c8fc 100644 --- a/Makefile +++ b/Makefile @@ -15,7 +15,7 @@ sysconfdir=$(prefix)/etc SRCS = $(sort $(wildcard src/*.c)) OBJS = $(SRCS:.c=.o) -LOBJS = src/core.o src/common.o src/libproxychains.o +LOBJS = src/core.o src/common.o src/libproxychains.o src/shm.o src/allocator_thread.o CFLAGS += -Wall -O0 -g -std=c99 -D_GNU_SOURCE -pipe -DTHREAD_SAFE LDFLAGS = -shared -fPIC -Wl,--no-as-needed -ldl -lpthread diff --git a/src/allocator_thread.c b/src/allocator_thread.c new file mode 100644 index 000000000..7590df0 --- /dev/null +++ b/src/allocator_thread.c @@ -0,0 +1,126 @@ +#include +#include +#include +#include +#include +#include +#include +#include "shm.h" +#include "debug.h" + +enum at_msgtype { + ATM_REALLOC, + ATM_STRINGDUMP, + ATM_EXIT, +}; + +static pthread_t allocator_thread; +static pthread_attr_t allocator_thread_attr; +static int req_pipefd[2]; +static int resp_pipefd[2]; +static size_t *at_oldsize; +static size_t *at_newsize; +static void **at_data; +struct stringpool mem; + +static void* threadfunc(void* x) { + (void) x; + int readfd = req_pipefd[0]; + int writefd = resp_pipefd[1]; + fd_set fds; + FD_ZERO(&fds); + FD_SET(readfd, &fds); + int ret; + int msg; + while((ret = select(readfd+1, &fds, NULL, NULL, NULL)) != -1) { + assert(ret); + if(read(readfd, &msg, sizeof(int)) != sizeof(int)) { + perror("read"); + } else { + void *nu; + switch(msg) { + case ATM_REALLOC: + nu = shm_realloc(*at_data, *at_oldsize, *at_newsize); + break; + case ATM_STRINGDUMP: + nu = stringpool_add(&mem, *at_data, *at_newsize); + break; + case ATM_EXIT: + return 0; + default: + abort(); + } + *at_data = nu; + write(writefd, &msg, sizeof(int)); + } + } + return 0; +} + +static void initpipe(int* fds) { + if(pipe2(fds, 0/*O_CLOEXEC*/) == -1) { + perror("pipe"); + exit(1); + } +} + +/* initialize with pointers to shared memory. these will + * be used to place responses and arguments */ +void at_init(void **data, size_t *oldsize, size_t *newsize) { + PFUNC(); + initpipe(req_pipefd); + initpipe(resp_pipefd); + at_oldsize = oldsize; + at_newsize = newsize; + at_data = data; + 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); +} + +void at_close(void) { + PFUNC(); + const int msg = ATM_EXIT; + write(req_pipefd[1], &msg, sizeof(int)); + pthread_join(allocator_thread, NULL); + close(req_pipefd[0]); + close(req_pipefd[1]); + close(resp_pipefd[0]); + close(resp_pipefd[1]); +} + +static int wait_reply(void) { + PFUNC(); + int readfd = resp_pipefd[0]; + fd_set fds; + FD_ZERO(&fds); + FD_SET(readfd, &fds); + int ret; + while((ret = select(readfd+1, &fds, NULL, NULL, NULL)) <= 0) { + if(ret < 0) perror("select2"); + } + read(readfd, &ret, sizeof(int)); + return ret; +} + +void *at_realloc(void* old, size_t oldsize, size_t newsize) { + PFUNC(); + *at_data = old; + *at_oldsize = oldsize; + *at_newsize = newsize; + const int msg = ATM_REALLOC; + write(req_pipefd[1], &msg, sizeof(int)); + assert(wait_reply() == msg); + return *at_data; +} + +char *at_dumpstring(char* s, size_t len) { + PFUNC(); + *at_data = s; + *at_newsize = len; + const int msg = ATM_STRINGDUMP; + write(req_pipefd[1], &msg, sizeof(int)); + assert(wait_reply() == msg); + return *at_data; +} diff --git a/src/allocator_thread.h b/src/allocator_thread.h new file mode 100644 index 000000000..938d3f7 --- /dev/null +++ b/src/allocator_thread.h @@ -0,0 +1,8 @@ +#include + +void *at_realloc(void* old, size_t oldsize, size_t newsize); +char *at_dumpstring(char* s, size_t len); +void at_init(void **data, size_t *oldsize, size_t *newsize); +void at_close(void); + +//RcB: DEP "allocator_thread.c" diff --git a/src/core.c b/src/core.c index 87149dc..72718e5 100644 --- a/src/core.c +++ b/src/core.c @@ -42,14 +42,15 @@ pthread_mutex_t hostdb_lock; #include "core.h" #include "common.h" +#include "shm.h" +#include "allocator_thread.h" extern int tcp_read_time_out; extern int tcp_connect_time_out; extern int proxychains_quiet_mode; extern unsigned int remote_dns_subnet; -internal_ip_lookup_table internal_ips = { 0, 0, NULL }; - +internal_ip_lookup_table *internal_ips = NULL; uint32_t dalias_hash(char *s0) { unsigned char *s = (void *) s0; @@ -62,6 +63,7 @@ uint32_t dalias_hash(char *s0) { } uint32_t index_from_internal_ip(ip_type internalip) { + PFUNC(); ip_type tmp = internalip; uint32_t ret; ret = tmp.octet[3] + (tmp.octet[2] << 8) + (tmp.octet[1] << 16); @@ -70,11 +72,12 @@ uint32_t index_from_internal_ip(ip_type internalip) { } char *string_from_internal_ip(ip_type internalip) { + PFUNC(); char *res = NULL; uint32_t index = index_from_internal_ip(internalip); MUTEX_LOCK(&internal_ips_lock); - if(index < internal_ips.counter) - res = internal_ips.list[index]->string; + if(index < internal_ips->counter) + res = internal_ips->list[index]->string; MUTEX_UNLOCK(&internal_ips_lock); return res; } @@ -220,6 +223,7 @@ static int timed_connect(int sock, const struct sockaddr *addr, socklen_t len) { int ret, value; socklen_t value_len; struct pollfd pfd[1]; + PFUNC(); pfd[0].fd = sock; pfd[0].events = POLLOUT; @@ -260,7 +264,7 @@ static int tunnel_to(int sock, ip_type ip, unsigned short port, proxy_type pt, c char *dns_name = NULL; size_t dns_len = 0; - PDEBUG("tunnel_to()\n"); + PFUNC(); // we use ip addresses with 224.* to lookup their dns name in our table, to allow remote DNS resolution // the range 224-255.* is reserved, and it won't go outside (unless the app does some other stuff with @@ -588,7 +592,7 @@ static int chain_step(int ns, proxy_data * pfrom, proxy_data * pto) { char *hostname; char ip_buf[16]; - PDEBUG("chain_step()\n"); + PFUNC(); if(pto->ip.octet[0] == remote_dns_subnet) { hostname = string_from_internal_ip(pto->ip); @@ -632,7 +636,7 @@ int connect_proxy_chain(int sock, ip_type target_ip, p3 = &p4; - PDEBUG("connect_proxy_chain\n"); + PFUNC(); again: @@ -744,6 +748,7 @@ 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]; uint32_t i, hash; // yep, new_mem never gets freed. once you passed a fake ip to the client, you can't "retreat" it @@ -789,9 +794,9 @@ struct hostent *proxy_gethostbyname(const char *name, struct gethostbyname_data* MUTEX_LOCK(&internal_ips_lock); // see if we already have this dns entry saved. - if(internal_ips.counter) { - for(i = 0; i < internal_ips.counter; i++) { - if(internal_ips.list[i]->hash == hash && !strcmp(name, internal_ips.list[i]->string)) { + if(internal_ips->counter) { + for(i = 0; i < internal_ips->counter; i++) { + if(internal_ips->list[i]->hash == hash && !strcmp(name, internal_ips->list[i]->string)) { data->resolved_addr = make_internal_ip(i); PDEBUG("got cached ip for %s\n", name); goto have_ip; @@ -799,12 +804,14 @@ struct hostent *proxy_gethostbyname(const char *name, struct gethostbyname_data* } } // grow list if needed. - if(internal_ips.capa < internal_ips.counter + 1) { + if(internal_ips->capa < internal_ips->counter + 1) { PDEBUG("realloc\n"); - new_mem = realloc(internal_ips.list, (internal_ips.capa + 16) * sizeof(void *)); + new_mem = at_realloc(internal_ips->list, + internal_ips->capa * sizeof(void *), + (internal_ips->capa + 16) * sizeof(void *)); if(new_mem) { - internal_ips.capa += 16; - internal_ips.list = new_mem; + internal_ips->capa += 16; + internal_ips->list = new_mem; } else { oom: proxychains_write_log("out of mem\n"); @@ -812,24 +819,30 @@ struct hostent *proxy_gethostbyname(const char *name, struct gethostbyname_data* } } - data->resolved_addr = make_internal_ip(internal_ips.counter); + data->resolved_addr = make_internal_ip(internal_ips->counter); if(data->resolved_addr == (in_addr_t) - 1) goto err_plus_unlock; l = strlen(name); - new_mem = malloc(sizeof(string_hash_tuple) + l + 1); + string_hash_tuple tmp = { 0 }; + new_mem = at_dumpstring((char*) &tmp, sizeof(string_hash_tuple)); if(!new_mem) goto oom; - PDEBUG("creating new entry %d for ip of %s\n", (int) internal_ips.counter, name); + PDEBUG("creating new entry %d for ip of %s\n", (int) internal_ips->counter, name); - internal_ips.list[internal_ips.counter] = new_mem; - internal_ips.list[internal_ips.counter]->hash = hash; - internal_ips.list[internal_ips.counter]->string = (char *) new_mem + sizeof(string_hash_tuple); + internal_ips->list[internal_ips->counter] = new_mem; + internal_ips->list[internal_ips->counter]->hash = hash; + + new_mem = at_dumpstring((char*) name, l + 1); + + if(!new_mem) { + internal_ips->list[internal_ips->counter] = 0; + goto oom; + } + internal_ips->list[internal_ips->counter]->string = new_mem; - memcpy(internal_ips.list[internal_ips.counter]->string, name, l + 1); - - internal_ips.counter += 1; + internal_ips->counter += 1; have_ip: @@ -839,10 +852,13 @@ struct hostent *proxy_gethostbyname(const char *name, struct gethostbyname_data* gethostbyname_data_setstring(data, (char*) name); + PDEBUG("return hostent space\n"); + return &data->hostent_space; err_plus_unlock: MUTEX_UNLOCK(&internal_ips_lock); + PDEBUG("return err\n"); return NULL; } @@ -853,6 +869,7 @@ struct addrinfo_data { }; void proxy_freeaddrinfo(struct addrinfo *res) { + PFUNC(); free(res); } @@ -860,6 +877,7 @@ void proxy_freeaddrinfo(struct addrinfo *res) { /* getservbyname on mac is using thread local storage, so we dont need mutex */ static int getservbyname_r(const char* name, const char* proto, struct servent* result_buf, char* buf, size_t buflen, struct servent** result) { + PFUNC(); struct servent *res; int ret; (void) buf; (void) buflen; @@ -885,6 +903,7 @@ int proxy_getaddrinfo(const char *node, const char *service, const struct addrin struct addrinfo *p; char buf[1024]; int port; + PFUNC(); // printf("proxy_getaddrinfo node %s service %s\n",node,service); space = calloc(1, sizeof(struct addrinfo_data)); diff --git a/src/core.h b/src/core.h index d4b4936..7ddd4cf 100644 --- a/src/core.h +++ b/src/core.h @@ -14,6 +14,7 @@ * * ***************************************************************************/ +#include #include #include #include @@ -35,13 +36,20 @@ typedef struct { char* string; } string_hash_tuple; +struct mallocinfo { + void * addr; + size_t oldsz; + size_t newsz; +}; + typedef struct { uint32_t counter; uint32_t capa; + struct mallocinfo mi; string_hash_tuple** list; } internal_ip_lookup_table; -extern internal_ip_lookup_table internal_ips; +extern internal_ip_lookup_table *internal_ips; #ifdef THREAD_SAFE #include extern pthread_mutex_t internal_ips_lock; @@ -143,11 +151,7 @@ void proxy_freeaddrinfo(struct addrinfo *res); void pc_stringfromipv4(unsigned char *ip_buf_4_bytes, char *outbuf_16_bytes); -#ifdef DEBUG -# define PDEBUG(fmt, args...) do { fprintf(stderr,"DEBUG:"fmt, ## args); fflush(stderr); } while(0) -#else -# define PDEBUG(fmt, args...) do {} while (0) -#endif +#include "debug.h" #endif diff --git a/src/debug.h b/src/debug.h new file mode 100644 index 000000000..ea33c3d --- /dev/null +++ b/src/debug.h @@ -0,0 +1,13 @@ +#ifndef DEBUG_H +#define DEBUG_H + +#ifdef DEBUG +# include +# define PDEBUG(fmt, args...) do { dprintf(2,"DEBUG:"fmt, ## args); } while(0) +#else +# define PDEBUG(fmt, args...) do {} while (0) +#endif + +# define PFUNC() do { PDEBUG("pid[%d]:%s\n", getpid(), __FUNCTION__); } while(0) + +#endif \ No newline at end of file diff --git a/src/libproxychains.c b/src/libproxychains.c index c21fa82..ed66121 100644 --- a/src/libproxychains.c +++ b/src/libproxychains.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -91,9 +92,17 @@ static void* load_sym(char* symname, void* proxyfunc) { #define SETUP_SYM(X) do { true_ ## X = load_sym( # X, X ); } while(0) +#include "shm.h" +#include "allocator_thread.h" + static void do_init(void) { MUTEX_INIT(&internal_ips_lock, NULL); MUTEX_INIT(&hostdb_lock, NULL); + internal_ips = shm_realloc(NULL, 0, sizeof(internal_ip_lookup_table)); + assert(internal_ips); + memset(internal_ips, 0, sizeof(internal_ip_lookup_table)); + at_init(&internal_ips->mi.addr, &internal_ips->mi.oldsz, &internal_ips->mi.newsz); + /* read the config file */ get_chain_data(proxychains_pd, &proxychains_proxy_count, &proxychains_ct); @@ -270,6 +279,7 @@ static void get_chain_data(proxy_data * pd, unsigned int *proxy_count, chain_typ /******* HOOK FUNCTIONS *******/ int connect(int sock, const struct sockaddr *addr, unsigned int len) { + PFUNC(); int socktype = 0, flags = 0, ret = 0; socklen_t optlen = 0; ip_type dest_ip; diff --git a/src/shm.c b/src/shm.c new file mode 100644 index 000000000..4d10aeb --- /dev/null +++ b/src/shm.c @@ -0,0 +1,48 @@ +#include +#include +#include +#include +#include +#include +#ifndef PAGE_SIZE +#define PAGE_SIZE 4096 +#endif +#include "shm.h" +#include "debug.h" + +/* allocates shared memory which can be accessed from the parent and its childs */ +void *shm_realloc(void* old, size_t old_size, size_t new_size) { + //PFUNC(); + void *nu = mmap(NULL, new_size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0); + if(old) { + if(!nu) return NULL; + assert(new_size >= old_size); + memcpy(nu, old, old_size); + munmap(old, old_size); + } + return nu; +} + +void stringpool_init(struct stringpool* sp) { + PFUNC(); + memset(sp, 0, sizeof *sp); +} + +char* stringpool_add(struct stringpool *sp, char* s, size_t len) { + //PFUNC(); + if(len > sp->alloced - sp->used) { + size_t newsz = sp->used + len; + size_t inc = PAGE_SIZE - (newsz % PAGE_SIZE); + newsz += (inc == PAGE_SIZE) ? 0 : inc; + void* p = shm_realloc(sp->start, sp->alloced, newsz); + if(p) { + sp->start = p; + sp->alloced = newsz; + } else + return 0; + } + char* ret = sp->start + sp->used; + memcpy(ret, s, len); + sp->used += len; + return ret; +} diff --git a/src/shm.h b/src/shm.h new file mode 100644 index 000000000..6254db3 --- /dev/null +++ b/src/shm.h @@ -0,0 +1,14 @@ +#include + +struct stringpool { + size_t alloced; + size_t used; + char* start; +}; + +void stringpool_init(struct stringpool* sp); +char* stringpool_add(struct stringpool *sp, char* s, size_t len); + +void *shm_realloc(void* old, size_t old_size, size_t new_size); + +//RcB: DEP "shm.c" diff --git a/tests/test_shm.c b/tests/test_shm.c new file mode 100644 index 000000000..c2ce93a --- /dev/null +++ b/tests/test_shm.c @@ -0,0 +1,39 @@ +#include "../src/shm.h" +#include + +#define s(A) (sizeof(A) - 1) +#define ss(A) (A), s(A) + +int main() { + char buf4096[4096]; + struct stringpool sp; + stringpool_init(&sp); + char *r; + size_t pos = 0; + r = stringpool_add(&sp, ss("AAAAA")); + assert(r == sp.start); + + pos += s("AAAAA"); + assert(sp.alloced == 4096); + assert(sp.used == pos); + + r = stringpool_add(&sp, buf4096, sizeof(buf4096)); + assert(r == sp.start + pos); + + pos += sizeof(buf4096); + assert(sp.alloced == 4096 * 2); + assert(sp.used == pos); + + r = stringpool_add(&sp, buf4096, 4096 - s("AAAAA")); + assert(r == sp.start + pos); + pos += 4096 - s("AAAAA"); + assert(pos == 4096 * 2); + + assert(sp.alloced == 4096 * 2); + assert(sp.used == pos); + + + + return 0; + +} \ No newline at end of file