From e547835be60e6170d91fc0449947b5af3c737d0c Mon Sep 17 00:00:00 2001 From: rofl0r Date: Sun, 6 Nov 2011 14:07:38 +0100 Subject: [PATCH 01/18] cleanup of the Makefile and renamed to proxychains4 --- Makefile | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/Makefile b/Makefile index beb5ae7..4623adb 100644 --- a/Makefile +++ b/Makefile @@ -23,11 +23,13 @@ PIC = -fPIC -O0 AR = $(CROSS_COMPILE)ar RANLIB = $(CROSS_COMPILE)ranlib -SHARED_LIBS = libproxychains.so -ALL_LIBS = $(SHARED_LIBS) -ALL_TOOLS = proxychains +LDSO_PATHNAME = libproxychains4.so + +SHARED_LIBS = $(LDSO_PATHNAME) +ALL_LIBS = $(SHARED_LIBS) +PXCHAINS = proxychains4 +ALL_TOOLS = $(PXCHAINS) -LDSO_PATHNAME = libproxychains.so.3 -include config.mak @@ -38,11 +40,9 @@ all: $(ALL_LIBS) $(ALL_TOOLS) #install: $(ALL_LIBS:lib/%=$(DESTDIR)$(libdir)/%) $(DESTDIR)$(LDSO_PATHNAME) install: - install -D -m 755 proxychains $(bindir) - install -D -m 755 src/proxyresolv $(bindir) - install -D -m 644 libproxychains.so $(libdir) - install -D -m 644 src/proxychains.conf /etc - ln -sf $(libdir)/libproxychains.so $(libdir)/libproxychains.so.3 + install -D -m 755 $(PXCHAINS) $(bindir)/$(PXCHAINS) + install -D -m 644 $(LDSO_PATHNAME) $(libdir) + install -D -m 644 src/proxychains.conf $(prefix)/etc clean: rm -f $(OBJS) @@ -55,16 +55,11 @@ clean: %.lo: %.c $(CC) $(CFLAGS) $(CFLAGS_MAIN) $(INC) $(PIC) -c -o $@ $< -libproxychains.so: $(LOBJS) - $(CC) $(LDFLAGS) -Wl,-soname=libproxychains.so -o $@ $(LOBJS) -lgcc +$(LDSO_PATHNAME): $(LOBJS) + $(CC) $(LDFLAGS) -Wl,-soname=$(LDSO_PATHNAME) -o $@ $(LOBJS) $(ALL_TOOLS): $(OBJS) - $(CC) src/main.o -o proxychains + $(CC) src/main.o -o $(PXCHAINS) -$(DESTDIR)$(libdir)/%.so: %.so - install -D -m 755 $< $@ - -$(DESTDIR)$(LDSO_PATHNAME): libproxychains.so - ln -sf $(libdir)/libproxychains.so $@ || true .PHONY: all clean install From d30b0a871283ef18c747d5985be7d74d428a7ba3 Mon Sep 17 00:00:00 2001 From: rofl0r Date: Sun, 6 Nov 2011 14:11:36 +0100 Subject: [PATCH 02/18] cleaned up main program --- src/common.h | 1 + src/main.c | 37 +++++++++++++++++++++++++++++++++++-- 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/src/common.h b/src/common.h index 8e34773..5ba648c 100644 --- a/src/common.h +++ b/src/common.h @@ -1,2 +1,3 @@ #define PROXYCHAINS_CONF_FILE_ENV_VAR "PROXYCHAINS_CONF_FILE" #define PROXYCHAINS_CONF_FILE "proxychains.conf" +#define LOG_PREFIX "[proxychains] " diff --git a/src/main.c b/src/main.c index 9777368..e63ecf5 100644 --- a/src/main.c +++ b/src/main.c @@ -39,6 +39,18 @@ int check_path(char* path) { return access(path, R_OK) != -1; } +static const char* dll_name = "libproxychains4.so"; + +static const char* dll_dirs[] = { + ".", + LIB_DIR, + "/lib", + "/usr/lib", + "/usr/local/lib", + "/lib64", + NULL +}; + int main(int argc, char *argv[]) { char *path = NULL; char buf[256]; @@ -92,12 +104,33 @@ int main(int argc, char *argv[]) { have: - printf("[proxychains config] %s\n", path); + printf(LOG_PREFIX "config file found: %s\n", path); /* Set PROXYCHAINS_CONF_FILE to get proxychains lib to use new config file. */ setenv(PROXYCHAINS_CONF_FILE_ENV_VAR, path, 1); + + + // search DLL + size_t i = 0; + const char* prefix = NULL; + + while(dll_dirs[i]) { + snprintf(buf, sizeof(buf), "%s/%s", dll_dirs[i], dll_name); + if(access(buf, R_OK) != -1) { + prefix = dll_dirs[i]; + break; + } + i++; + } + + if(!prefix) { + printf("couldnt locate %s\n", dll_name); + return EXIT_FAILURE; + } + printf(LOG_PREFIX "preloading %s/%s\n", prefix, dll_name); - snprintf(buf, sizeof(buf), "LD_PRELOAD=%s/libproxychains.so", LIB_DIR); + snprintf(buf, sizeof(buf), "LD_PRELOAD=%s/%s", prefix, dll_name); + putenv(buf); execvp(argv[start_argv], &argv[start_argv]); perror("proxychains can't load process...."); From 5de7fa20c82139f4115f5503b14e86e994243624 Mon Sep 17 00:00:00 2001 From: rofl0r Date: Sun, 6 Nov 2011 14:12:50 +0100 Subject: [PATCH 03/18] implemented remote proxy dns lookup via use of reserved ip ranges and a lookup table --- src/core.c | 656 +++++++++++++++++++++++++------------------ src/core.h | 90 ++++-- src/libproxychains.c | 66 +++-- 3 files changed, 476 insertions(+), 336 deletions(-) diff --git a/src/core.c b/src/core.c index d160d26..1d0cde7 100644 --- a/src/core.c +++ b/src/core.c @@ -34,37 +34,66 @@ #include #include #include "core.h" +#include "common.h" extern int tcp_read_time_out; extern int tcp_connect_time_out; extern int proxychains_quiet_mode; +internal_ip_lookup_table internal_ips = {0, 0, NULL}; + + +uint32_t dalias_hash(char* s) { + 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) { + ip_type tmp = internalip; + uint32_t ret; + ret = tmp.octet[3] + tmp.octet[2] << 8 + tmp.octet[1] << 16; + return ret; +} + +in_addr_t make_internal_ip(uint32_t index) { + ip_type ret; + if(index > 0xFFFFFF) return (in_addr_t) -1; + ret.octet[0] = 224; + ret.octet[1] = (index & 0xFF0000) >> 16; + ret.octet[2] = (index & 0xFF00) >> 8; + ret.octet[3] = index & 0xFF; + return (in_addr_t) ret.as_int; +} + static const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; static int poll_retry(struct pollfd *fds, nfds_t nfsd, int timeout) { - int ret; - int time_remain = timeout; - int time_elapsed = 0; + int ret; + int time_remain = timeout; + int time_elapsed = 0; - struct timeval start_time; - struct timeval tv; + struct timeval start_time; + struct timeval tv; - gettimeofday(&start_time, NULL); + gettimeofday(&start_time, NULL); - do - { - //printf("Retry %d\n", time_remain); - ret = poll(fds, nfsd, time_remain); - gettimeofday(&tv, NULL); - time_elapsed = ((tv.tv_sec - start_time.tv_sec) * 1000 + (tv.tv_usec - start_time.tv_usec) / 1000); - //printf("Time elapsed %d\n", time_elapsed); - time_remain = timeout - time_elapsed; - } - while (ret == -1 && errno == EINTR && time_remain > 0); - //if (ret == -1) - //printf("Return %d %d %s\n", ret, errno, strerror(errno)); - return ret; + do { + //printf("Retry %d\n", time_remain); + ret = poll(fds, nfsd, time_remain); + gettimeofday(&tv, NULL); + time_elapsed = ((tv.tv_sec - start_time.tv_sec) * 1000 + (tv.tv_usec - start_time.tv_usec) / 1000); + //printf("Time elapsed %d\n", time_elapsed); + time_remain = timeout - time_elapsed; + } while (ret == -1 && errno == EINTR && time_remain > 0); + + //if (ret == -1) + //printf("Return %d %d %s\n", ret, errno, strerror(errno)); + return ret; } @@ -108,20 +137,18 @@ static void encode_base_64(char* src,char* dest,int max_len) int proxychains_write_log(char *str,...) { - char buff[LOG_BUFF]; - va_list arglist; - FILE * log_file; - log_file=stderr; - if (!proxychains_quiet_mode) - { - va_start(arglist,str); - vsprintf(buff,str,arglist); - va_end(arglist); - fprintf(log_file,"%s",buff); - fflush(log_file); - } - - return EXIT_SUCCESS; + char buff[LOG_BUFF]; + va_list arglist; + FILE * log_file; + log_file=stderr; + if (!proxychains_quiet_mode) { + va_start(arglist,str); + vsprintf(buff,str,arglist); + va_end(arglist); + fprintf(log_file,"%s",buff); + fflush(log_file); + } + return EXIT_SUCCESS; } static int write_n_bytes(int fd,char *buff,size_t size) @@ -198,195 +225,239 @@ static int timed_connect(int sock, const struct sockaddr *addr, socklen_t len) return ret; } -static int tunnel_to(int sock, unsigned int ip, unsigned short port, proxy_type pt,char *user,char *pass) + +#define INVALID_INDEX 0xFFFFFFFFU +static int tunnel_to(int sock, ip_type ip, unsigned short port, proxy_type pt,char *user,char *pass) { #ifdef DEBUG PDEBUG("tunnel_to()\n"); #endif + uint32_t index = INVALID_INDEX; + char* dns_name = NULL; + size_t dns_len = 0; + + // 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 + // the results returned from gethostbyname et al.) + if(ip.octet[0] == 224) { + index = index_from_internal_ip(ip); + if(index > internal_ips.counter) goto err; + dns_name = internal_ips.list[index]->string; + if(!dns_name) goto err; + dns_len = strlen(dns_name); + if(!dns_len) goto err; + } + + size_t ulen = strlen(user); + size_t passlen = strlen(pass); + int len; - char buff[BUFF_SIZE]; - memset (buff, 0, sizeof(buff)); - switch(pt) - { - case HTTP_TYPE: - { - sprintf(buff,"CONNECT %s:%d HTTP/1.0\r\n", - inet_ntoa( * (struct in_addr *) &ip), - ntohs(port)); - if (user[0]) - { - char src[256]; - char dst[512]; - strcpy(src,user); - strcat(src,":"); - strcat(src,pass); - encode_base_64(src,dst,512); - strcat(buff,"Proxy-Authorization: Basic "); - strcat(buff,dst); - strcat(buff,"\r\n\r\n"); - } - else - strcat(buff,"\r\n"); + unsigned char buff[BUFF_SIZE]; + //memset (buff, 0, sizeof(buff)); + + switch(pt) { + case HTTP_TYPE: { + if(!dns_len) + snprintf(buff, sizeof(buff), "CONNECT %s:%d HTTP/1.0\r\n", + inet_ntoa( * (struct in_addr *) &ip.as_int), ntohs(port)); + else + snprintf(buff, sizeof(buff), "CONNECT %s:%d HTTP/1.0\r\n", dns_name, ntohs(port)); - len=strlen(buff); - - if(len!=send(sock,buff,len,0)) - return SOCKET_ERROR; - - memset(buff, 0, sizeof(buff)); - len=0 ; - // read header byte by byte. - while(len 4 && - buff[len-1]=='\n' && - buff[len-2]=='\r' && - buff[len-3]=='\n' && - buff[len-4]=='\r' ) - break; - } - - // if not ok (200) or response greather than BUFF_SIZE return BLOCKED; - if ( (len==BUFF_SIZE) || - ! ( buff[9] =='2' && - buff[10]=='0' && - buff[11]=='0' )) - return BLOCKED; - return SUCCESS; - } - break; - case SOCKS4_TYPE: - { - memset(buff,0,sizeof(buff)); - buff[0]=4; // socks version - buff[1]=1; // connect command - memcpy(&buff[2],&port,2); // dest port - memcpy(&buff[4],&ip,4); // dest host - len=strlen(user)+1; // username - if(len>1) - strcpy(&buff[8],user); - if((len+8)!=write_n_bytes(sock,buff,(8+len))) - return SOCKET_ERROR; - - if(8!=read_n_bytes(sock,buff,8)) - return SOCKET_ERROR; - - if (buff[0]!=0||buff[1]!=90) - return BLOCKED; - - return SUCCESS; - } - break; - case SOCKS5_TYPE: - { - if(user) - { - buff[0]=5; //version - buff[1]=2; //nomber of methods - buff[2]=0; // no auth method - buff[3]=2; /// auth method -> username / password - if(4!=write_n_bytes(sock,buff,4)) - return SOCKET_ERROR; - } - else - { - buff[0]=5; //version - buff[1]=1; //nomber of methods - buff[2]=0; // no auth method - if(3!=write_n_bytes(sock,buff,3)) - return SOCKET_ERROR; - } - - memset(buff,0,sizeof(buff)); - - if(2!=read_n_bytes(sock,buff,2)) - return SOCKET_ERROR; - - if (buff[0]!=5||(buff[1]!=0&&buff[1]!=2)) - { - if((buff[0]==0x05)&&(buff[1]==(char)0xFF)) - return BLOCKED; - else - return SOCKET_ERROR; - } - - if (buff[1]==2) - { - // authentication - char in[2]; - char out[515]; char* cur=out; - int c; - *cur++=1; // version - c=strlen(user); - *cur++=c; - strncpy(cur,user,c); - cur+=c; - c=strlen(pass); - *cur++=c; - strncpy(cur,pass,c); - cur+=c; - - if((cur-out)!=write_n_bytes(sock,out,cur-out)) - return SOCKET_ERROR; - - - if(2!=read_n_bytes(sock,in,2)) - return SOCKET_ERROR; - if(in[0]!=1||in[1]!=0) - { - if(in[0]!=1) - return SOCKET_ERROR; - else - return BLOCKED; - } - } - - buff[0]=5; // version - buff[1]=1; // connect - buff[2]=0; // reserved - buff[3]=1; // ip v4 - - memcpy(&buff[4],&ip,4); // dest host - memcpy(&buff[8],&port,2); // dest port + if (user[0]) + { + char src[256]; + char dst[512]; + memcpy(src, user, ulen); + memcpy(src + ulen, ":", 1); + memcpy(src + ulen + 1, pass, passlen); + src[ulen + 1 + passlen] = 0; - - if(10!=write_n_bytes(sock,buff,10)) - return SOCKET_ERROR; + encode_base_64(src,dst,512); + strcat(buff,"Proxy-Authorization: Basic "); + strcat(buff,dst); + strcat(buff,"\r\n\r\n"); + } + else + strcat(buff,"\r\n"); - if(4!=read_n_bytes(sock,buff,4)) - return SOCKET_ERROR; + len = strlen(buff); - if (buff[0]!=5||buff[1]!=0) - return SOCKET_ERROR; + if(len != send(sock, buff, len, 0)) + goto err; + + memset(buff, 0, sizeof(buff)); + len = 0 ; + // read header byte by byte. + while(len < BUFF_SIZE) { + if(1 == read_n_bytes(sock, buff+len, 1)) + len++; + else + goto err; + if (len > 4 && + buff[len-1]=='\n' && + buff[len-2]=='\r' && + buff[len-3]=='\n' && + buff[len-4]=='\r' ) + break; + } - switch (buff[3]) - { - case 1: len=4; break; - case 4: len=16; break; - case 3: len=0; - if(1!=read_n_bytes(sock,(char*)&len,1)) - return SOCKET_ERROR; - break; - default: - return SOCKET_ERROR; + // if not ok (200) or response greather than BUFF_SIZE return BLOCKED; + if (len == BUFF_SIZE || + !( buff[9] =='2' && + buff[10]=='0' && + buff[11]=='0' )) + return BLOCKED; + + return SUCCESS; + } + break; + + case SOCKS4_TYPE: { + buff[0] = 4; // socks version + buff[1] = 1; // connect command + memcpy(&buff[2],&port,2); // dest port + if(dns_len) { + ip.octet[0] = 0; + ip.octet[1] = 0; + ip.octet[2] = 0; + ip.octet[3] = 1; } + memcpy(&buff[4], &ip, 4); // dest host + len = ulen + 1; // username + if(len > 1) + memcpy(&buff[8], user, ulen + 1); + + // do socksv4a dns resolution on the server + if(dns_len) { + memcpy(&buff[8 + len], dns_name, dns_len + 1); + len += dns_len + 1; + } + + if((len + 8) != write_n_bytes(sock, buff, (8+len))) + goto err; - if((len+2)!=read_n_bytes(sock,buff,(len+2))) - return SOCKET_ERROR; + if(8 != read_n_bytes(sock,buff,8)) + goto err; + + if (buff[0] != 0 || buff[1] != 90) + return BLOCKED; return SUCCESS; - } - break; + } + break; + case SOCKS5_TYPE: { + if(user) { + buff[0]=5; //version + buff[1]=2; //nomber of methods + buff[2]=0; // no auth method + buff[3]=2; /// auth method -> username / password + if(4!=write_n_bytes(sock,buff,4)) + goto err; + } + else { + buff[0]=5; //version + buff[1]=1; //nomber of methods + buff[2]=0; // no auth method + if(3 != write_n_bytes(sock, buff, 3)) + goto err; + } - } + if(2 != read_n_bytes(sock, buff, 2)) + goto err; + + if (buff[0] != 5 || (buff[1] != 0 && buff[1] != 2)) { + if(buff[0] == 5 && buff[1] ==(char)0xFF) + return BLOCKED; + else + goto err; + } + + if (buff[1] == 2) { + // authentication + char in[2]; + char out[515]; char* cur=out; + int c; + *cur++=1; // version + c = ulen & 0xFF; + *cur++ = c; + memcpy(cur, user, c); + cur += c; + c = passlen & 0xFF; + *cur++ = c; + memcpy(cur, pass, c); + cur += c; + + if((cur-out) != write_n_bytes(sock, out, cur-out)) + goto err; + + + if(2 != read_n_bytes(sock,in,2)) + goto err; + if(in[0] != 1 || in[1] != 0) { + if(in[0] != 1) + goto err; + else + return BLOCKED; + } + } + int buff_iter = 0; + buff[buff_iter++] = 5; // version + buff[buff_iter++] = 1; // connect + buff[buff_iter++] = 0; // reserved + + if(!dns_len) { + buff[buff_iter++] = 1; // ip v4 + memcpy(buff + buff_iter, &ip, 4); // dest host + buff_iter += 4; + } else { + buff[buff_iter++] = 3; //dns + buff[buff_iter++] = dns_len & 0xFF; + memcpy(buff + buff_iter, dns_name, dns_len); + buff_iter += dns_len; + } + + memcpy(buff + buff_iter, &port, 2); // dest port + buff_iter += 2; + -return SOCKET_ERROR; + if(buff_iter != write_n_bytes(sock, buff, buff_iter)) + goto err; + + if(4 != read_n_bytes(sock,buff,4)) + goto err; + + if (buff[0] != 5 || buff[1] != 0) + goto err; + + switch (buff[3]) { + + case 1: len = 4; break; + case 4: len = 16; break; + case 3: len = 0; + if(1 != read_n_bytes(sock, (char*) &len, 1)) + goto err; + break; + default: + goto err; + } + + if(len + 2 != read_n_bytes(sock, buff, len+2)) + goto err; + + return SUCCESS; + } + break; + } + + err: + return SOCKET_ERROR; } +#define TP " ... " +#define DT "Dynamic chain" +#define ST "Strict chain" +#define RT "Random chain" + static int start_chain(int *fd, proxy_data *pd, char* begin_mark) { struct sockaddr_in addr; @@ -395,14 +466,14 @@ static int start_chain(int *fd, proxy_data *pd, char* begin_mark) if(*fd==-1) goto error; - proxychains_write_log("%s-<>-%s:%d-", + proxychains_write_log(LOG_PREFIX "%s "TP" %s:%d ", begin_mark, inet_ntoa(*(struct in_addr*)&pd->ip), htons(pd->port)); pd->ps=PLAY_STATE; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; - addr.sin_addr.s_addr = pd->ip; + addr.sin_addr.s_addr = (in_addr_t) pd->ip.as_int; addr.sin_port = pd->port; if (timed_connect (*fd ,(struct sockaddr*)&addr,sizeof(addr))) { pd->ps=DOWN_STATE; @@ -411,7 +482,7 @@ static int start_chain(int *fd, proxy_data *pd, char* begin_mark) pd->ps=BUSY_STATE; return SUCCESS; error1: - proxychains_write_log("<--timeout\n"); + proxychains_write_log(TP" timeout\n"); error: if(*fd!=-1) close(*fd); @@ -481,12 +552,23 @@ static unsigned int calc_alive(proxy_data *pd, unsigned int proxy_count) static int chain_step(int ns, proxy_data *pfrom, proxy_data *pto) { int retcode=-1; + char* hostname; + uint32_t index; #ifdef DEBUG PDEBUG("chain_step()\n"); #endif + if(pto->ip.octet[0] == 224) { + index = index_from_internal_ip(pto->ip); + if(index < internal_ips.counter) + hostname = internal_ips.list[index]->string; + else goto usenumericip; + } else { + usenumericip: + hostname = inet_ntoa(*(struct in_addr*)&pto->ip); + } - proxychains_write_log("<>-%s:%d-", - inet_ntoa(*(struct in_addr*)&pto->ip), + proxychains_write_log(TP" %s:%d ", + hostname, htons(pto->port)); retcode = tunnel_to(ns, pto->ip, pto->port, pfrom->pt, pfrom->user, @@ -509,7 +591,7 @@ static int chain_step(int ns, proxy_data *pfrom, proxy_data *pto) return retcode; } -int connect_proxy_chain( int sock, unsigned int target_ip, +int connect_proxy_chain( int sock, ip_type target_ip, unsigned short target_port, proxy_data *pd, unsigned int proxy_count, chain_type ct, unsigned int max_chain ) { @@ -519,11 +601,6 @@ int connect_proxy_chain( int sock, unsigned int target_ip, unsigned int offset=0; unsigned int alive_count=0; unsigned int curr_len=0; - -#define TP "<>" -#define DT "|D-chain|" -#define ST "|S-chain|" -#define RT "|R-chain|" p3=&p4; #ifdef DEBUG @@ -534,8 +611,8 @@ again: switch(ct) { case DYNAMIC_TYPE: - alive_count=calc_alive(pd,proxy_count); - offset=0; + alive_count = calc_alive(pd,proxy_count); + offset = 0; do { if(!(p1=select_proxy(FIFOLY,pd,proxy_count,&offset))) goto error_more; @@ -552,16 +629,16 @@ again: } p1=p2; } - proxychains_write_log(TP); - p3->ip=target_ip; - p3->port=target_port; - if(SUCCESS!=chain_step(ns,p1,p3)) + //proxychains_write_log(TP); + p3->ip = target_ip; + p3->port = target_port; + if(SUCCESS != chain_step(ns, p1, p3)) goto error; break; case STRICT_TYPE: - alive_count=calc_alive(pd, proxy_count); - offset=0; + alive_count = calc_alive(pd, proxy_count); + offset = 0; if(!(p1=select_proxy(FIFOLY, pd, proxy_count, &offset))) { #ifdef DEBUG PDEBUG("select_proxy failed\n"); @@ -583,12 +660,12 @@ again: #endif goto error_strict; } - p1=p2; + p1 = p2; } - proxychains_write_log(TP); - p3->ip=target_ip; - p3->port=target_port; - if(SUCCESS!=chain_step(ns,p1,p3)) + //proxychains_write_log(TP); + p3->ip = target_ip; + p3->port = target_port; + if(SUCCESS!=chain_step(ns, p1, p3)) goto error; break; @@ -604,23 +681,23 @@ again: while(++curr_lenip=target_ip; - p3->port=target_port; + //proxychains_write_log(TP); + p3->ip = target_ip; + p3->port = target_port; if(SUCCESS!=chain_step(ns,p1,p3)) goto error; } - proxychains_write_log("<><>-OK\n"); + proxychains_write_log(TP" OK\n"); dup2(ns,sock); close(ns); return 0; @@ -643,72 +720,91 @@ error_strict: return -1; } + static struct hostent hostent_space; static in_addr_t resolved_addr; -static char* resolved_addr_p; +static char* resolved_addr_p[2]; static char addr_name[1024*8]; +static const ip_type local_host = {127, 0, 0, 1}; struct hostent* proxy_gethostbyname(const char *name) { - int pipe_fd[2]; char buff[256]; - in_addr_t addr; - pid_t pid; - int status; + uint32_t i, hash; + void* new_mem; + size_t l; + struct hostent* hp; - hostent_space.h_addr_list = &resolved_addr_p; - *hostent_space.h_addr_list = (char*)&resolved_addr; + resolved_addr_p[0] = (char*) &resolved_addr; + resolved_addr_p[1] = NULL; + + hostent_space.h_addr_list = resolved_addr_p; + resolved_addr = 0; gethostname(buff,sizeof(buff)); - if(!strcmp(buff,name)) - goto got_buff; - + + if(!strcmp(buff, name)) { + resolved_addr = inet_addr(buff); + if (resolved_addr == (in_addr_t) (-1)) + resolved_addr = (in_addr_t) (local_host.as_int); + return &hostent_space; + } + memset(buff, 0, sizeof(buff)); - // TODO: this works only once, so cache it ... - // later while ((hp=gethostent())) if (!strcmp(hp->h_name,name)) return hp; - if(pipe(pipe_fd)) - goto err; - pid = fork(); - switch(pid) { - case 0: // child - proxychains_write_log("|DNS-request| %s \n", name); - dup2(pipe_fd[1],1); - //dup2(pipe_fd[1],2); - // putenv("LD_PRELOAD="); - execlp("proxyresolv","proxyresolv",name,NULL); - perror("can't exec proxyresolv"); - exit(2); - - case -1: //error - close(pipe_fd[0]); - close(pipe_fd[1]); - perror("can't fork"); - goto err; - - default: - close(pipe_fd[1]); - waitpid(pid, &status, 0); - read(pipe_fd[0],&buff,sizeof(buff)); - close(pipe_fd[0]); -got_buff: - addr = inet_addr(buff); - if (addr == (in_addr_t) (-1)) - goto err_dns; - memcpy(*(hostent_space.h_addr_list), - &addr ,sizeof(struct in_addr)); - hostent_space.h_name = addr_name; - hostent_space.h_length = sizeof (in_addr_t); + hash = dalias_hash((char*) name); + + if(internal_ips.counter) { + for( i = 0; i < internal_ips.counter; i++) { + if(internal_ips.list[i]->hash == hash) { + resolved_addr = make_internal_ip(i); + goto have_ip; + } + } } - proxychains_write_log("|DNS-response| %s is %s\n", - name, inet_ntoa(*(struct in_addr*)&addr)); + + if(internal_ips.capa < internal_ips.counter + 1) { + new_mem = realloc(internal_ips.list, internal_ips.capa + 16); + if(new_mem) { + internal_ips.capa += 16; + internal_ips.list = new_mem; + } else { + oom: + proxychains_write_log("out of mem\n"); + goto err; + } + } + + resolved_addr = make_internal_ip(internal_ips.counter); + if(resolved_addr == (in_addr_t) -1) goto err; + + l = strlen(name); + new_mem = malloc(sizeof(string_hash_tuple) + l + 1); + if(!new_mem) + goto oom; + + 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); + + memcpy(internal_ips.list[internal_ips.counter]->string, name, l + 1); + + internal_ips.counter += 1; + + have_ip: + + //strncpy(addr_name, name, sizeof(addr_name)); + + hostent_space.h_name = addr_name; + hostent_space.h_length = sizeof (in_addr_t); return &hostent_space; + err_dns: proxychains_write_log("|DNS-response|: %s does not exist\n", name); perror("err_dns"); diff --git a/src/core.h b/src/core.h index 581f7ce..0b65020 100644 --- a/src/core.h +++ b/src/core.h @@ -5,6 +5,7 @@ copyright : netcreature (C) 2002 email : netcreature@users.sourceforge.net ***************************************************************************/ +#include /* GPL */ /*************************************************************************** * * @@ -19,31 +20,66 @@ #define BUFF_SIZE 8*1024 // used to read responses from proxies. #define MAX_LOCALNET 1024 +typedef union { + unsigned char octet[4]; + uint32_t as_int; +} ip_type; + +typedef struct { + uint32_t hash; + char* string; +} string_hash_tuple; + +typedef struct { + uint32_t counter; + uint32_t capa; + string_hash_tuple** list; +} internal_ip_lookup_table; + +extern internal_ip_lookup_table internal_ips; + /*error codes*/ -typedef enum -{ - SUCCESS=0, - MEMORY_FAIL, // malloc failed - SOCKET_ERROR, // look errno for more - CHAIN_DOWN, // no proxy in chain responds to tcp - CHAIN_EMPTY, // if proxy_count = 0 - BLOCKED // target's port blocked on last proxy in the chain +typedef enum { + SUCCESS=0, + MEMORY_FAIL, // malloc failed + SOCKET_ERROR, // look errno for more + CHAIN_DOWN, // no proxy in chain responds to tcp + CHAIN_EMPTY, // if proxy_count = 0 + BLOCKED // target's port blocked on last proxy in the chain } ERR_CODE; -typedef enum {HTTP_TYPE,SOCKS4_TYPE,SOCKS5_TYPE} proxy_type; -typedef enum {DYNAMIC_TYPE,STRICT_TYPE,RANDOM_TYPE} chain_type; -typedef enum {PLAY_STATE,DOWN_STATE,BLOCKED_STATE,BUSY_STATE} proxy_state; -typedef enum {RANDOMLY,FIFOLY} select_type; +typedef enum { + HTTP_TYPE, + SOCKS4_TYPE, + SOCKS5_TYPE +} proxy_type; -typedef struct -{ +typedef enum { + DYNAMIC_TYPE, + STRICT_TYPE, + RANDOM_TYPE} +chain_type; + +typedef enum { + PLAY_STATE, + DOWN_STATE, + BLOCKED_STATE, + BUSY_STATE +} proxy_state; + +typedef enum { + RANDOMLY, + FIFOLY +} select_type; + +typedef struct { struct in_addr in_addr, netmask; unsigned short port; } localaddr_arg; typedef struct { - unsigned int ip; + ip_type ip; unsigned short port; proxy_type pt; proxy_state ps; @@ -53,21 +89,21 @@ typedef struct { typedef struct { proxy_data *pd; - chain_type ct; - unsigned int proxy_count; - int sock; - struct sockaddr addr; - int flags; + chain_type ct; + unsigned int proxy_count; + int sock; + struct sockaddr addr; + int flags; } thread_arg; int connect_proxy_chain ( - int sock, - unsigned int target_ip, - unsigned short target_port, - proxy_data * pd, - unsigned int proxy_count, - chain_type ct, - unsigned int max_chain ); + int sock, + ip_type target_ip, + unsigned short target_port, + proxy_data * pd, + unsigned int proxy_count, + chain_type ct, + unsigned int max_chain ); int proxychains_write_log(char *str,...); struct hostent* proxy_gethostbyname(const char *name); diff --git a/src/libproxychains.c b/src/libproxychains.c index fb75364..f9c3faf 100644 --- a/src/libproxychains.c +++ b/src/libproxychains.c @@ -62,7 +62,7 @@ static void init_lib(void); static void init_lib(void) { - proxychains_write_log("[proxychains v3.2] DLL init\n"); + proxychains_write_log(LOG_PREFIX "DLL init\n"); get_chain_data(proxychains_pd, &proxychains_proxy_count, &proxychains_ct); true_connect = (connect_t) dlsym(RTLD_NEXT, "connect"); @@ -200,21 +200,27 @@ static inline void get_chain_data( if(buff[0] != '\n' && buff[strspn(buff," ")]!='#') { if(list) { memset(&pd[count], 0, sizeof(proxy_data)); - pd[count].ps=PLAY_STATE; - port_n=0; - sscanf(buff,"%s %s %d %s %s", type,host,&port_n, - pd[count].user,pd[count].pass); - pd[count].ip=inet_addr(host); - pd[count].port=htons((unsigned short)port_n); - if(!strcmp(type,"http")) { - pd[count].pt=HTTP_TYPE; - }else if(!strcmp(type,"socks4")) { - pd[count].pt=SOCKS4_TYPE; - }else if(!strcmp(type,"socks5")) { - pd[count].pt=SOCKS5_TYPE; - }else continue; - if( pd[count].ip && (int) pd[count].ip != -1 && port_n) + pd[count].ps = PLAY_STATE; + port_n = 0; + + sscanf(buff,"%s %s %d %s %s", type, host, &port_n, + pd[count].user, pd[count].pass); + + pd[count].ip.as_int = (uint32_t) inet_addr(host); + pd[count].port = htons((unsigned short)port_n); + + if(!strcmp(type,"http")) { + pd[count].pt = HTTP_TYPE; + } else if(!strcmp(type,"socks4")) { + pd[count].pt = SOCKS4_TYPE; + } else if(!strcmp(type,"socks5")) { + pd[count].pt = SOCKS5_TYPE; + } else + continue; + + if(pd[count].ip.as_int && port_n && + (int) pd[count].ip.as_int != (uint32_t) -1) if(++count==MAX_CHAIN) break; } else { @@ -226,13 +232,11 @@ static inline void get_chain_data( *ct=STRICT_TYPE; } else if(strstr(buff,"dynamic_chain")) { *ct=DYNAMIC_TYPE; - }else if(strstr(buff,"tcp_read_time_out")){ + } else if(strstr(buff,"tcp_read_time_out")){ sscanf(buff,"%s %d",user,&tcp_read_time_out) ; - }else if(strstr(buff,"tcp_connect_time_out")){ + } else if(strstr(buff,"tcp_connect_time_out")){ sscanf(buff,"%s %d",user,&tcp_connect_time_out) ; - } - else if(strstr(buff,"localnet")) - { + } else if(strstr(buff,"localnet")) { if (sscanf(buff,"%s %21[^/]/%15s", user, local_in_addr_port, local_netmask) < 3) { fprintf(stderr, "localnet format error"); @@ -276,15 +280,14 @@ static inline void get_chain_data( { fprintf(stderr, "# of localnet exceed %d.\n", MAX_LOCALNET); } - } - else if(strstr(buff,"chain_len")){ + } else if(strstr(buff,"chain_len")){ char *pc;int len; pc=strchr(buff,'='); len=atoi(++pc); proxychains_max_chain=(len?len:1); - }else if(strstr(buff,"quiet_mode")){ + } else if(strstr(buff,"quiet_mode")){ proxychains_quiet_mode=1; - }else if(strstr(buff,"proxy_dns")){ + } else if(strstr(buff,"proxy_dns")){ proxychains_resolver=1; } } @@ -301,6 +304,7 @@ int connect (int sock, const struct sockaddr *addr, unsigned int len) { int socktype=0, flags=0, ret=0; socklen_t optlen = 0; + ip_type dest_ip; #ifdef DEBUG char str[256]; #endif @@ -335,20 +339,24 @@ int connect (int sock, const struct sockaddr *addr, unsigned int len) } } - flags=fcntl(sock, F_GETFL, 0); + flags = fcntl(sock, F_GETFL, 0); if(flags & O_NONBLOCK) fcntl(sock, F_SETFL, !O_NONBLOCK); - ret=connect_proxy_chain( + + dest_ip.as_int = SOCKADDR(*addr); + + ret = connect_proxy_chain( sock, - SOCKADDR(*addr), + dest_ip, SOCKPORT(*addr), proxychains_pd, proxychains_proxy_count, proxychains_ct, proxychains_max_chain ); + fcntl(sock, F_SETFL, flags); - if(ret!=SUCCESS) - errno=ECONNREFUSED; + if(ret != SUCCESS) + errno = ECONNREFUSED; return ret; } From 4cb2cf3416898294b1d0e0dc60312d8405df52ef Mon Sep 17 00:00:00 2001 From: rofl0r Date: Sun, 6 Nov 2011 15:18:50 +0100 Subject: [PATCH 04/18] fix index algo --- src/core.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/core.c b/src/core.c index 1d0cde7..f8a0122 100644 --- a/src/core.c +++ b/src/core.c @@ -55,12 +55,14 @@ uint32_t dalias_hash(char* s) { uint32_t index_from_internal_ip(ip_type internalip) { ip_type tmp = internalip; uint32_t ret; - ret = tmp.octet[3] + tmp.octet[2] << 8 + tmp.octet[1] << 16; + ret = tmp.octet[3] + (tmp.octet[2] << 8) + (tmp.octet[1] << 16); + ret -= 1; return ret; } in_addr_t make_internal_ip(uint32_t index) { ip_type ret; + index++; // so we can start at .0.0.1 if(index > 0xFFFFFF) return (in_addr_t) -1; ret.octet[0] = 224; ret.octet[1] = (index & 0xFF0000) >> 16; From d5ae1f92026a0613ae8794ab8681fe238b4ac40e Mon Sep 17 00:00:00 2001 From: rofl0r Date: Sun, 6 Nov 2011 15:47:00 +0100 Subject: [PATCH 05/18] buff is unsigned char now --- src/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core.c b/src/core.c index f8a0122..90ec934 100644 --- a/src/core.c +++ b/src/core.c @@ -368,7 +368,7 @@ static int tunnel_to(int sock, ip_type ip, unsigned short port, proxy_type pt,ch goto err; if (buff[0] != 5 || (buff[1] != 0 && buff[1] != 2)) { - if(buff[0] == 5 && buff[1] ==(char)0xFF) + if(buff[0] == 5 && buff[1] == 0xFF) return BLOCKED; else goto err; From 41e73ab58d2fa2bf047b93fd88d65e4a888836e6 Mon Sep 17 00:00:00 2001 From: rofl0r Date: Sun, 6 Nov 2011 17:46:11 +0100 Subject: [PATCH 06/18] fix realloc and add a layer of threadsafety upon dns-list accesses --- Makefile | 4 +-- src/core.c | 70 +++++++++++++++++++++++++++++++------------- src/core.h | 4 +++ src/libproxychains.c | 3 ++ 4 files changed, 58 insertions(+), 23 deletions(-) diff --git a/Makefile b/Makefile index 4623adb..6222f48 100644 --- a/Makefile +++ b/Makefile @@ -16,8 +16,8 @@ SRCS = $(sort $(wildcard src/*.c)) OBJS = $(SRCS:.c=.o) LOBJS = $(OBJS:.o=.lo) -CFLAGS += -Wall -O0 -g -std=c99 -D_GNU_SOURCE -pipe -LDFLAGS = -shared -fPIC -ldl +CFLAGS += -Wall -O0 -g -std=c99 -D_GNU_SOURCE -pipe -DTHREAD_SAFE +LDFLAGS = -shared -fPIC -ldl -lpthread INC = PIC = -fPIC -O0 AR = $(CROSS_COMPILE)ar diff --git a/src/core.c b/src/core.c index 90ec934..5dac349 100644 --- a/src/core.c +++ b/src/core.c @@ -4,9 +4,9 @@ begin : Tue May 14 2002 copyright : netcreature (C) 2002 email : netcreature@users.sourceforge.net - ***************************************************************************/ -/* GPL */ -/*************************************************************************** + *************************************************************************** + * GPL * + *************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * @@ -33,6 +33,11 @@ #include #include #include +#ifdef THREAD_SAFE +#include +pthread_mutex_t internal_ips_lock; +#endif + #include "core.h" #include "common.h" @@ -60,6 +65,20 @@ uint32_t index_from_internal_ip(ip_type internalip) { return ret; } +char* string_from_internal_ip(ip_type internalip) { + char* res = NULL; +#ifdef THREAD_SAFE + pthread_mutex_lock(&internal_ips_lock); +#endif + uint32_t index = index_from_internal_ip(internalip); + if(index < internal_ips.counter) + res = internal_ips.list[index]->string; +#ifdef THREAD_SAFE + pthread_mutex_unlock(&internal_ips_lock); +#endif + return res; +} + in_addr_t make_internal_ip(uint32_t index) { ip_type ret; index++; // so we can start at .0.0.1 @@ -234,7 +253,6 @@ static int tunnel_to(int sock, ip_type ip, unsigned short port, proxy_type pt,ch #ifdef DEBUG PDEBUG("tunnel_to()\n"); #endif - uint32_t index = INVALID_INDEX; char* dns_name = NULL; size_t dns_len = 0; @@ -242,9 +260,7 @@ static int tunnel_to(int sock, ip_type ip, unsigned short port, proxy_type pt,ch // the range 224-255.* is reserved, and it won't go outside (unless the app does some other stuff with // the results returned from gethostbyname et al.) if(ip.octet[0] == 224) { - index = index_from_internal_ip(ip); - if(index > internal_ips.counter) goto err; - dns_name = internal_ips.list[index]->string; + dns_name = string_from_internal_ip(ip); if(!dns_name) goto err; dns_len = strlen(dns_name); if(!dns_len) goto err; @@ -560,10 +576,8 @@ static int chain_step(int ns, proxy_data *pfrom, proxy_data *pto) PDEBUG("chain_step()\n"); #endif if(pto->ip.octet[0] == 224) { - index = index_from_internal_ip(pto->ip); - if(index < internal_ips.counter) - hostname = internal_ips.list[index]->string; - else goto usenumericip; + hostname = string_from_internal_ip(pto->ip); + if(!hostname) goto usenumericip; } else { usenumericip: hostname = inet_ntoa(*(struct in_addr*)&pto->ip); @@ -722,7 +736,7 @@ error_strict: return -1; } - +// TODO: all those buffers aren't threadsafe, but since no memory allocation happens there shouldnt be any segfaults static struct hostent hostent_space; static in_addr_t resolved_addr; static char* resolved_addr_p[2]; @@ -732,6 +746,7 @@ struct hostent* proxy_gethostbyname(const char *name) { 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 void* new_mem; size_t l; @@ -762,35 +777,43 @@ struct hostent* proxy_gethostbyname(const char *name) hash = dalias_hash((char*) name); +#ifdef THREAD_SAFE + pthread_mutex_lock(&internal_ips_lock); +#endif + if(internal_ips.counter) { for( i = 0; i < internal_ips.counter; i++) { if(internal_ips.list[i]->hash == hash) { resolved_addr = make_internal_ip(i); + printf("got cached ip for %s\n", name); goto have_ip; } } } if(internal_ips.capa < internal_ips.counter + 1) { - new_mem = realloc(internal_ips.list, internal_ips.capa + 16); + printf("realloc\n"); + new_mem = realloc(internal_ips.list, (internal_ips.capa + 16) * sizeof(void*)); if(new_mem) { internal_ips.capa += 16; internal_ips.list = new_mem; } else { oom: proxychains_write_log("out of mem\n"); - goto err; + goto err_plus_unlock; } } resolved_addr = make_internal_ip(internal_ips.counter); - if(resolved_addr == (in_addr_t) -1) goto err; + if(resolved_addr == (in_addr_t) -1) goto err_plus_unlock; l = strlen(name); new_mem = malloc(sizeof(string_hash_tuple) + l + 1); if(!new_mem) goto oom; + printf("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); @@ -801,16 +824,21 @@ struct hostent* proxy_gethostbyname(const char *name) have_ip: - //strncpy(addr_name, name, sizeof(addr_name)); +#ifdef THREAD_SAFE + pthread_mutex_unlock(&internal_ips_lock); +#endif + + + strncpy(addr_name, name, sizeof(addr_name)); hostent_space.h_name = addr_name; hostent_space.h_length = sizeof (in_addr_t); return &hostent_space; - -err_dns: - proxychains_write_log("|DNS-response|: %s does not exist\n", name); - perror("err_dns"); -err: + +err_plus_unlock: +#ifdef THREAD_SAFE + pthread_mutex_unlock(&internal_ips_lock); +#endif return NULL; } int proxy_getaddrinfo(const char *node, const char *service, diff --git a/src/core.h b/src/core.h index 0b65020..1ec41c5 100644 --- a/src/core.h +++ b/src/core.h @@ -37,6 +37,10 @@ typedef struct { } internal_ip_lookup_table; extern internal_ip_lookup_table internal_ips; +#ifdef THREAD_SAFE +#include +extern pthread_mutex_t internal_ips_lock; +#endif /*error codes*/ typedef enum { diff --git a/src/libproxychains.c b/src/libproxychains.c index f9c3faf..f32eabb 100644 --- a/src/libproxychains.c +++ b/src/libproxychains.c @@ -62,6 +62,9 @@ static void init_lib(void); static void init_lib(void) { +#ifdef THREAD_SAFE + pthread_mutex_init(&internal_ips_lock, NULL); +#endif proxychains_write_log(LOG_PREFIX "DLL init\n"); get_chain_data(proxychains_pd, &proxychains_proxy_count, &proxychains_ct); From 6ac6abd3deca47dd9e06fba58c415e0af098934e Mon Sep 17 00:00:00 2001 From: rofl0r Date: Sun, 6 Nov 2011 17:47:44 +0100 Subject: [PATCH 07/18] add possibility to search for DLL in exe's path --- src/main.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/main.c b/src/main.c index e63ecf5..b7c5581 100644 --- a/src/main.c +++ b/src/main.c @@ -41,8 +41,10 @@ int check_path(char* path) { static const char* dll_name = "libproxychains4.so"; +static char own_dir[256]; static const char* dll_dirs[] = { ".", + own_dir, LIB_DIR, "/lib", "/usr/lib", @@ -51,6 +53,17 @@ static const char* dll_dirs[] = { NULL }; +static void set_own_dir(const char* argv0) { + size_t l = strlen(argv0); + while(l && argv0[l - 1] != '/') l--; + if(l == 0) + memcpy(own_dir, ".", 2); + else { + memcpy(own_dir, argv0, l - 1); + own_dir[l] = 0; + } +} + int main(int argc, char *argv[]) { char *path = NULL; char buf[256]; @@ -114,6 +127,8 @@ int main(int argc, char *argv[]) { size_t i = 0; const char* prefix = NULL; + set_own_dir(argv[0]); + while(dll_dirs[i]) { snprintf(buf, sizeof(buf), "%s/%s", dll_dirs[i], dll_name); if(access(buf, R_OK) != -1) { From 8f3bc0934a93a078578af53ee0089b760591f2da Mon Sep 17 00:00:00 2001 From: rofl0r Date: Sun, 6 Nov 2011 17:52:32 +0100 Subject: [PATCH 08/18] do not override our CFLAGS when none are passed --- configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure b/configure index 2c938cf..9360a06 100755 --- a/configure +++ b/configure @@ -48,7 +48,7 @@ fi echo CC=$CC>config.mak echo CPPFLAGS=$CPPFLAGS>>config.mak -echo CFLAGS=$CFLAGS>>config.mak +[ -z "$CFLAGS" ] || echo CFLAGS=$CFLAGS>>config.mak echo prefix=$prefix>>config.mak echo exec_prefix=$exec_prefix>>config.mak echo bindir=$bindir>>config.mak From a6d778a0f11947ebe0e4673b043c4af892833ea5 Mon Sep 17 00:00:00 2001 From: rofl0r Date: Sun, 6 Nov 2011 23:35:57 +0100 Subject: [PATCH 09/18] cleanup debug code and remove warnings --- src/core.c | 44 +++++++++++++++++++++----------------------- src/libproxychains.c | 2 +- 2 files changed, 22 insertions(+), 24 deletions(-) diff --git a/src/core.c b/src/core.c index 5dac349..e7fe50c 100644 --- a/src/core.c +++ b/src/core.c @@ -276,10 +276,10 @@ static int tunnel_to(int sock, ip_type ip, unsigned short port, proxy_type pt,ch switch(pt) { case HTTP_TYPE: { if(!dns_len) - snprintf(buff, sizeof(buff), "CONNECT %s:%d HTTP/1.0\r\n", + snprintf((char*)buff, sizeof(buff), "CONNECT %s:%d HTTP/1.0\r\n", inet_ntoa( * (struct in_addr *) &ip.as_int), ntohs(port)); else - snprintf(buff, sizeof(buff), "CONNECT %s:%d HTTP/1.0\r\n", dns_name, ntohs(port)); + snprintf((char*)buff, sizeof(buff), "CONNECT %s:%d HTTP/1.0\r\n", dns_name, ntohs(port)); if (user[0]) { @@ -291,23 +291,22 @@ static int tunnel_to(int sock, ip_type ip, unsigned short port, proxy_type pt,ch src[ulen + 1 + passlen] = 0; encode_base_64(src,dst,512); - strcat(buff,"Proxy-Authorization: Basic "); - strcat(buff,dst); - strcat(buff,"\r\n\r\n"); + strcat((char*)buff,"Proxy-Authorization: Basic "); + strcat((char*)buff,dst); + strcat((char*)buff,"\r\n\r\n"); } else - strcat(buff,"\r\n"); + strcat((char*)buff,"\r\n"); - len = strlen(buff); + len = strlen((char*)buff); if(len != send(sock, buff, len, 0)) goto err; - memset(buff, 0, sizeof(buff)); len = 0 ; // read header byte by byte. while(len < BUFF_SIZE) { - if(1 == read_n_bytes(sock, buff+len, 1)) + if(1 == read_n_bytes(sock, (char*) (buff + len), 1)) len++; else goto err; @@ -351,10 +350,10 @@ static int tunnel_to(int sock, ip_type ip, unsigned short port, proxy_type pt,ch len += dns_len + 1; } - if((len + 8) != write_n_bytes(sock, buff, (8+len))) + if((len + 8) != write_n_bytes(sock, (char*) buff, (8+len))) goto err; - if(8 != read_n_bytes(sock,buff,8)) + if(8 != read_n_bytes(sock, (char*)buff, 8)) goto err; if (buff[0] != 0 || buff[1] != 90) @@ -369,18 +368,18 @@ static int tunnel_to(int sock, ip_type ip, unsigned short port, proxy_type pt,ch buff[1]=2; //nomber of methods buff[2]=0; // no auth method buff[3]=2; /// auth method -> username / password - if(4!=write_n_bytes(sock,buff,4)) + if(4!=write_n_bytes(sock, (char*)buff, 4)) goto err; } else { buff[0]=5; //version buff[1]=1; //nomber of methods buff[2]=0; // no auth method - if(3 != write_n_bytes(sock, buff, 3)) + if(3 != write_n_bytes(sock, (char*) buff, 3)) goto err; } - if(2 != read_n_bytes(sock, buff, 2)) + if(2 != read_n_bytes(sock, (char*) buff, 2)) goto err; if (buff[0] != 5 || (buff[1] != 0 && buff[1] != 2)) { @@ -438,10 +437,10 @@ static int tunnel_to(int sock, ip_type ip, unsigned short port, proxy_type pt,ch buff_iter += 2; - if(buff_iter != write_n_bytes(sock, buff, buff_iter)) + if(buff_iter != write_n_bytes(sock, (char*)buff, buff_iter)) goto err; - if(4 != read_n_bytes(sock,buff,4)) + if(4 != read_n_bytes(sock, (char*)buff, 4)) goto err; if (buff[0] != 5 || buff[1] != 0) @@ -459,7 +458,7 @@ static int tunnel_to(int sock, ip_type ip, unsigned short port, proxy_type pt,ch goto err; } - if(len + 2 != read_n_bytes(sock, buff, len+2)) + if(len + 2 != read_n_bytes(sock, (char*) buff, len+2)) goto err; return SUCCESS; @@ -571,7 +570,6 @@ static int chain_step(int ns, proxy_data *pfrom, proxy_data *pto) { int retcode=-1; char* hostname; - uint32_t index; #ifdef DEBUG PDEBUG("chain_step()\n"); #endif @@ -741,7 +739,7 @@ static struct hostent hostent_space; static in_addr_t resolved_addr; static char* resolved_addr_p[2]; static char addr_name[1024*8]; -static const ip_type local_host = {127, 0, 0, 1}; +static const ip_type local_host = {{127, 0, 0, 1}}; struct hostent* proxy_gethostbyname(const char *name) { char buff[256]; @@ -751,7 +749,7 @@ struct hostent* proxy_gethostbyname(const char *name) size_t l; struct hostent* hp; - + resolved_addr_p[0] = (char*) &resolved_addr; resolved_addr_p[1] = NULL; @@ -785,14 +783,14 @@ struct hostent* proxy_gethostbyname(const char *name) for( i = 0; i < internal_ips.counter; i++) { if(internal_ips.list[i]->hash == hash) { resolved_addr = make_internal_ip(i); - printf("got cached ip for %s\n", name); + PDEBUG("got cached ip for %s\n", name); goto have_ip; } } } if(internal_ips.capa < internal_ips.counter + 1) { - printf("realloc\n"); + PDEBUG("realloc\n"); new_mem = realloc(internal_ips.list, (internal_ips.capa + 16) * sizeof(void*)); if(new_mem) { internal_ips.capa += 16; @@ -812,7 +810,7 @@ struct hostent* proxy_gethostbyname(const char *name) if(!new_mem) goto oom; - printf("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; diff --git a/src/libproxychains.c b/src/libproxychains.c index f32eabb..b1ef2fd 100644 --- a/src/libproxychains.c +++ b/src/libproxychains.c @@ -223,7 +223,7 @@ static inline void get_chain_data( continue; if(pd[count].ip.as_int && port_n && - (int) pd[count].ip.as_int != (uint32_t) -1) + pd[count].ip.as_int != (uint32_t) -1) if(++count==MAX_CHAIN) break; } else { From 08d6feace80ef0b83bc9ce6c7d933ad00c6f0dae Mon Sep 17 00:00:00 2001 From: rofl0r Date: Mon, 7 Nov 2011 00:09:46 +0100 Subject: [PATCH 10/18] fix SOCKSv4a --- src/core.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/core.c b/src/core.c index e7fe50c..423fe93 100644 --- a/src/core.c +++ b/src/core.c @@ -342,7 +342,10 @@ static int tunnel_to(int sock, ip_type ip, unsigned short port, proxy_type pt,ch memcpy(&buff[4], &ip, 4); // dest host len = ulen + 1; // username if(len > 1) - memcpy(&buff[8], user, ulen + 1); + memcpy(&buff[8], user, len); + else { + buff[8] = 0; + } // do socksv4a dns resolution on the server if(dns_len) { From 16fa60a705759be0caf8f0949f35990bd48ba155 Mon Sep 17 00:00:00 2001 From: rofl0r Date: Mon, 7 Nov 2011 04:11:20 +0100 Subject: [PATCH 11/18] oh wait. checking the hash is not enough. --- src/core.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/core.c b/src/core.c index 423fe93..04278fb 100644 --- a/src/core.c +++ b/src/core.c @@ -782,9 +782,10 @@ struct hostent* proxy_gethostbyname(const char *name) pthread_mutex_lock(&internal_ips_lock); #endif + // 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) { + if(internal_ips.list[i]->hash == hash && !strcmp(name, internal_ips.list[i]->string)) { resolved_addr = make_internal_ip(i); PDEBUG("got cached ip for %s\n", name); goto have_ip; @@ -792,6 +793,7 @@ struct hostent* proxy_gethostbyname(const char *name) } } + // grow list if needed. if(internal_ips.capa < internal_ips.counter + 1) { PDEBUG("realloc\n"); new_mem = realloc(internal_ips.list, (internal_ips.capa + 16) * sizeof(void*)); From 0845d1c0441eaedb0de6ad168583089dece8e6b8 Mon Sep 17 00:00:00 2001 From: rofl0r Date: Mon, 7 Nov 2011 17:07:00 +0100 Subject: [PATCH 12/18] fix potential buffer overflow (exists in vanilla 3.1 as well) --- src/core.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/src/core.c b/src/core.c index 04278fb..bb1488c 100644 --- a/src/core.c +++ b/src/core.c @@ -269,6 +269,11 @@ static int tunnel_to(int sock, ip_type ip, unsigned short port, proxy_type pt,ch size_t ulen = strlen(user); size_t passlen = strlen(pass); + if(ulen > 0xFF || passlen > 0xFF || dns_len > 0xFF) { + proxychains_write_log(LOG_PREFIX "error: maximum size of 255 for user/pass or domain name!\n"); + goto err; + } + int len; unsigned char buff[BUFF_SIZE]; //memset (buff, 0, sizeof(buff)); @@ -276,27 +281,29 @@ static int tunnel_to(int sock, ip_type ip, unsigned short port, proxy_type pt,ch switch(pt) { case HTTP_TYPE: { if(!dns_len) - snprintf((char*)buff, sizeof(buff), "CONNECT %s:%d HTTP/1.0\r\n", - inet_ntoa( * (struct in_addr *) &ip.as_int), ntohs(port)); - else - snprintf((char*)buff, sizeof(buff), "CONNECT %s:%d HTTP/1.0\r\n", dns_name, ntohs(port)); + dns_name = inet_ntoa( * (struct in_addr *) &ip.as_int); + + snprintf((char*)buff, sizeof(buff), "CONNECT %s:%d HTTP/1.0\r\n", dns_name, ntohs(port)); if (user[0]) { - char src[256]; - char dst[512]; + #define HTTP_AUTH_MAX ((0xFF * 2) + 1 + 1) + // 2 * 0xff: username and pass, plus 1 for ':' and 1 for zero terminator. + char src[HTTP_AUTH_MAX]; + char dst[(4 * HTTP_AUTH_MAX)]; + memcpy(src, user, ulen); memcpy(src + ulen, ":", 1); memcpy(src + ulen + 1, pass, passlen); src[ulen + 1 + passlen] = 0; - encode_base_64(src,dst,512); + encode_base_64(src, dst, sizeof(dst)); strcat((char*)buff,"Proxy-Authorization: Basic "); - strcat((char*)buff,dst); - strcat((char*)buff,"\r\n\r\n"); + strcat((char*)buff, dst); + strcat((char*)buff, "\r\n\r\n"); } else - strcat((char*)buff,"\r\n"); + strcat((char*)buff, "\r\n"); len = strlen((char*)buff); From 3bd07fca00fcb47ac77ccf417d64217f82130dcb Mon Sep 17 00:00:00 2001 From: rofl0r Date: Mon, 14 Nov 2011 01:57:54 +0100 Subject: [PATCH 13/18] updated README --- README | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/README b/README index c3ffdfd..c07f104 100644 --- a/README +++ b/README @@ -1,6 +1,15 @@ -ProxyChains ver 3.1 README +ProxyChains ver 4.0 README ========================== +*********** ATTENTION *********** + +this program works only on dynamically linked programs. +also both proxychains and the program to call must use +the same dynamic linker (i.e. same libc) + +********************************* + + This is Unix version only. How to mess with sources - How to Install : read INSTALL !!!!!! @@ -10,7 +19,19 @@ to follow through proxy (or proxy chain). It is a kind of proxifier. It acts like sockscap / permeo / eborder driver ( intercepts TCP calls ) It is FREE. -This version (3.x) introduces support for DNS resolving through proxy +Changelog: +---------- + +Version (4.x) removes the dnsresolver script which required a dynamically +linked "dig" binary to be present with remote DNS lookup. +this speeds up any operation involving DNS, as the old script had to use TCP. +additionally it allows to use .onion urls when used with TOR. +also it removed the broken autoconf build system with a simple Makefile. +there's a ./configure script though for convenience. +it also adds support for a config file passed via command line switches/ +environment variables. + +Version (3.x) introduces support for DNS resolving through proxy it supports SOCKS4, SOCKS5 and HTTP CONNECT proxy servers. Auth-types: socks - "user/pass" , http - "basic". @@ -38,7 +59,10 @@ Some cool features: * You can use it with servers, like squid, sendmail, or whatever. * DNS resolving through proxy. + Configuration: +-------------- + proxychains looks for config file in following order: 1) file listed in environment variable ${PROXYCHAINS_CONF_FILE} or provided as a -f argument to proxychains script or binary. From c3a0f677fbc78859de0d3e4b61b694c151b23ef1 Mon Sep 17 00:00:00 2001 From: rofl0r Date: Tue, 17 Jan 2012 16:09:55 +0100 Subject: [PATCH 14/18] fix signedness of hashfunc --- src/core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/core.c b/src/core.c index bb1488c..17cc66d 100644 --- a/src/core.c +++ b/src/core.c @@ -48,7 +48,8 @@ extern int proxychains_quiet_mode; internal_ip_lookup_table internal_ips = {0, 0, NULL}; -uint32_t dalias_hash(char* s) { +uint32_t dalias_hash(char* s0) { + unsigned char* s = (void*) s0; uint_fast32_t h = 0; while (*s) { h = 16*h + *s++; From 150e6241826d61bac4f63622a9f1ba1249e1468e Mon Sep 17 00:00:00 2001 From: rofl0r Date: Tue, 24 Jan 2012 07:14:45 +0100 Subject: [PATCH 15/18] add proper feature tests for putenv, getenv --- src/main.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main.c b/src/main.c index b7c5581..b126d9d 100644 --- a/src/main.c +++ b/src/main.c @@ -14,7 +14,10 @@ * (at your option) any later version. * * * ***************************************************************************/ - +#undef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 200809L +#undef _XOPEN_SOURCE +#define _XOPEN_SOURCE 700 #include #include #include From e5f3422b16ac6ece63a32c74f831bf05dc155795 Mon Sep 17 00:00:00 2001 From: rofl0r Date: Tue, 24 Jan 2012 07:29:04 +0100 Subject: [PATCH 16/18] prevent configure-generated config to always overwrite CFLAGS in env --- configure | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/configure b/configure index 9360a06..3e40c67 100755 --- a/configure +++ b/configure @@ -46,9 +46,9 @@ if [ ! $CC ] ; then CC=cc fi -echo CC=$CC>config.mak -echo CPPFLAGS=$CPPFLAGS>>config.mak -[ -z "$CFLAGS" ] || echo CFLAGS=$CFLAGS>>config.mak +echo CC?=$CC>config.mak +[ -z "$CPPFLAGS" ] || echo CPPFLAGS?=$CPPFLAGS>>config.mak +[ -z "$CFLAGS" ] || echo USER_CFLAGS?=$CFLAGS>>config.mak echo prefix=$prefix>>config.mak echo exec_prefix=$exec_prefix>>config.mak echo bindir=$bindir>>config.mak From b20106ce2eaa32f3b6763641bf676299774ea374 Mon Sep 17 00:00:00 2001 From: rofl0r Date: Tue, 24 Jan 2012 07:29:34 +0100 Subject: [PATCH 17/18] make Makefile simpler and more correct --- Makefile | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/Makefile b/Makefile index 6222f48..0703782 100644 --- a/Makefile +++ b/Makefile @@ -14,12 +14,12 @@ libdir = $(prefix)/lib SRCS = $(sort $(wildcard src/*.c)) OBJS = $(SRCS:.c=.o) -LOBJS = $(OBJS:.o=.lo) +LOBJS = src/core.o src/libproxychains.o CFLAGS += -Wall -O0 -g -std=c99 -D_GNU_SOURCE -pipe -DTHREAD_SAFE LDFLAGS = -shared -fPIC -ldl -lpthread INC = -PIC = -fPIC -O0 +PIC = -fPIC AR = $(CROSS_COMPILE)ar RANLIB = $(CROSS_COMPILE)ranlib @@ -30,9 +30,9 @@ ALL_LIBS = $(SHARED_LIBS) PXCHAINS = proxychains4 ALL_TOOLS = $(PXCHAINS) - -include config.mak +CFLAGS+=$(USER_CFLAGS) CFLAGS_MAIN=-DLIB_DIR=\"$(libdir)\" @@ -40,19 +40,16 @@ all: $(ALL_LIBS) $(ALL_TOOLS) #install: $(ALL_LIBS:lib/%=$(DESTDIR)$(libdir)/%) $(DESTDIR)$(LDSO_PATHNAME) install: - install -D -m 755 $(PXCHAINS) $(bindir)/$(PXCHAINS) - install -D -m 644 $(LDSO_PATHNAME) $(libdir) - install -D -m 644 src/proxychains.conf $(prefix)/etc + install -D -m 755 $(ALL_TOOLS) $(bindir)/ + install -D -m 644 $(ALL_LIBS) $(libdir)/ + install -D -m 644 src/proxychains.conf $(prefix)/etc/ clean: + rm -f $(ALL_LIBS) + rm -f $(ALL_TOOLS) rm -f $(OBJS) - rm -f $(LOBJS) - rm -f $(ALL_LIBS) lib/*.[ao] lib/*.so %.o: %.c - $(CC) $(CFLAGS) $(CFLAGS_MAIN) $(INC) -c -o $@ $< - -%.lo: %.c $(CC) $(CFLAGS) $(CFLAGS_MAIN) $(INC) $(PIC) -c -o $@ $< $(LDSO_PATHNAME): $(LOBJS) From 8fd0d95bc3b79626893b30e76a62dfa62e754b8e Mon Sep 17 00:00:00 2001 From: rofl0r Date: Tue, 24 Jan 2012 08:26:37 +0100 Subject: [PATCH 18/18] add quiet mode to proxychains launcher this will be passed on to the DLL via a env variable - additionally, now everything prints to stderr - fixes a bug which would print DLL init even in quiet mode - fixed a couple of bugs in argv parsing --- src/common.h | 1 + src/libproxychains.c | 11 +++++++---- src/main.c | 42 ++++++++++++++++++++++++++---------------- 3 files changed, 34 insertions(+), 20 deletions(-) diff --git a/src/common.h b/src/common.h index 5ba648c..ecfc33c 100644 --- a/src/common.h +++ b/src/common.h @@ -1,3 +1,4 @@ #define PROXYCHAINS_CONF_FILE_ENV_VAR "PROXYCHAINS_CONF_FILE" +#define PROXYCHAINS_QUIET_MODE_ENV_VAR "PROXYCHAINS_QUIET_MODE" #define PROXYCHAINS_CONF_FILE "proxychains.conf" #define LOG_PREFIX "[proxychains] " diff --git a/src/libproxychains.c b/src/libproxychains.c index b1ef2fd..2e7b1cc 100644 --- a/src/libproxychains.c +++ b/src/libproxychains.c @@ -65,9 +65,11 @@ static void init_lib(void) #ifdef THREAD_SAFE pthread_mutex_init(&internal_ips_lock, NULL); #endif + /* read the config file */ + get_chain_data(proxychains_pd, &proxychains_proxy_count, &proxychains_ct); + proxychains_write_log(LOG_PREFIX "DLL init\n"); - get_chain_data(proxychains_pd, &proxychains_proxy_count, &proxychains_ct); true_connect = (connect_t) dlsym(RTLD_NEXT, "connect"); if (!true_connect) { @@ -180,8 +182,6 @@ static inline void get_chain_data( tcp_connect_time_out = 10*1000; *ct = DYNAMIC_TYPE; - env = NULL; - /* * Get path to configuration file from env this file has priority * if it's defined. @@ -190,7 +190,7 @@ static inline void get_chain_data( snprintf(buff,256,"%s/.proxychains/proxychains.conf",getenv("HOME")); - if(!(file=fopen(env,"r"))) + if(!env || (!(file=fopen(env,"r")))) if(!(file=fopen("./proxychains.conf","r"))) if(!(file=fopen(buff,"r"))) if(!(file=fopen("/etc/proxychains.conf","r"))) @@ -198,6 +198,9 @@ static inline void get_chain_data( perror("Can't locate proxychains.conf"); exit(1); } + + env = getenv(PROXYCHAINS_QUIET_MODE_ENV_VAR); + if(env && *env == '1') proxychains_quiet_mode = 1; while(fgets(buff,sizeof(buff),file)) { if(buff[0] != '\n' && buff[strspn(buff," ")]!='#') { diff --git a/src/main.c b/src/main.c index b126d9d..aad499c 100644 --- a/src/main.c +++ b/src/main.c @@ -31,10 +31,13 @@ extern int optind, opterr, optopt; #include "common.h" -static void usage(char** argv) { - printf("\nUsage: %s [h] [f] config_file program_name [arguments]\n" - "\t for example : proxychains telnet somehost.com\n" - "More help in README file\n", argv[0]); +static int usage(char** argv) { + printf( "\nUsage:\t%s -q -f config_file program_name [arguments]\n" + "\t-q makes proxychains quiet - this overrides the config setting\n" + "\t-t allows to manually specify a configfile to use\n" + "\tfor example : proxychains telnet somehost.com\n" + "More help in README file\n\n", argv[0]); + return EXIT_FAILURE; } int check_path(char* path) { @@ -73,25 +76,30 @@ int main(int argc, char *argv[]) { char pbuf[256]; int opt; int start_argv = 1; + int quiet = 0; + + if(argc == 1) return usage(argv); - while ((opt = getopt(argc, argv, "hf:")) != -1) { + while ((opt = getopt(argc, argv, "qf:")) != -1) { switch (opt) { - case 'h': - usage(argv); - return EXIT_SUCCESS; + case 'q': + quiet = 1; + start_argv++; + break; case 'f': path = (char *)optarg; if(!path) { - printf("error: no path supplied.\n"); - return(EXIT_FAILURE); + fprintf(stderr, "error: no path supplied.\n"); + return EXIT_FAILURE; } - start_argv = 3; + start_argv += 2; break; default: /* '?' */ - usage(argv); - exit(EXIT_FAILURE); + return usage(argv); } } + + if(start_argv >= argc) return usage(argv); /* check if path of config file has not been passed via command line */ if(!path) { @@ -120,10 +128,12 @@ int main(int argc, char *argv[]) { have: - printf(LOG_PREFIX "config file found: %s\n", path); + if(!quiet) fprintf(stderr, LOG_PREFIX "config file found: %s\n", path); /* Set PROXYCHAINS_CONF_FILE to get proxychains lib to use new config file. */ setenv(PROXYCHAINS_CONF_FILE_ENV_VAR, path, 1); + + if(quiet) setenv(PROXYCHAINS_QUIET_MODE_ENV_VAR, "1", 1); // search DLL @@ -142,10 +152,10 @@ int main(int argc, char *argv[]) { } if(!prefix) { - printf("couldnt locate %s\n", dll_name); + fprintf(stderr, "couldnt locate %s\n", dll_name); return EXIT_FAILURE; } - printf(LOG_PREFIX "preloading %s/%s\n", prefix, dll_name); + if(!quiet) fprintf(stderr, LOG_PREFIX "preloading %s/%s\n", prefix, dll_name); snprintf(buf, sizeof(buf), "LD_PRELOAD=%s/%s", prefix, dll_name);