pull/22/merge
crass 2013-06-25 17:05:13 -07:00
commit fd81555ad9
10 changed files with 496 additions and 135 deletions

View File

@ -18,7 +18,7 @@ OBJS = $(SRCS:.c=.o)
LOBJS = src/nameinfo.o \
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
src/hostentdb.o src/hash.o src/debug.o
CFLAGS += -Wall -O0 -g -std=c99 -D_GNU_SOURCE -pipe
NO_AS_NEEDED = -Wl,--no-as-needed

View File

@ -10,6 +10,7 @@
#include <stddef.h>
#include <errno.h>
#include "allocator_thread.h"
#include "core.h"
#include "shm.h"
#include "debug.h"
#include "ip_type.h"
@ -17,6 +18,8 @@
#include "hash.h"
#include "stringdump.h"
extern proxy_chain_list *proxychains_chain_list;
/* stuff for our internal translation table */
typedef struct {
@ -52,13 +55,12 @@ char *string_from_internal_ip(ip_type internalip) {
return res;
}
extern unsigned int remote_dns_subnet;
ip_type make_internal_ip(uint32_t index) {
ip_type ret;
index++; // so we can start at .0.0.1
if(index > 0xFFFFFF)
return ip_type_invalid;
ret.octet[0] = remote_dns_subnet & 0xFF;
ret.octet[0] = proxychains_chain_list->remote_dns_subnet & 0xFF;
ret.octet[1] = (index & 0xFF0000) >> 16;
ret.octet[2] = (index & 0xFF00) >> 8;
ret.octet[3] = index & 0xFF;

View File

@ -3,6 +3,26 @@
#include <unistd.h>
#include <stdio.h>
const char *proxy_type_strmap[] = {
"http",
"socks4",
"socks5",
};
const char *chain_type_strmap[] = {
"dynamic_chain",
"strict_chain",
"random_chain",
"round_robin_chain",
};
const char *proxy_state_strmap[] = {
"play",
"down",
"blocked",
"busy",
};
// stolen from libulz (C) rofl0r
void pc_stringfromipv4(unsigned char *ip_buf_4_bytes, char *outbuf_16_bytes) {
unsigned char *p;

View File

@ -2,8 +2,10 @@
#define COMMON_H
#define PROXYCHAINS_CONF_FILE_ENV_VAR "PROXYCHAINS_CONF_FILE"
#define PROXYCHAINS_CHAIN_ENV_VAR "PROXYCHAINS_CHAIN"
#define PROXYCHAINS_QUIET_MODE_ENV_VAR "PROXYCHAINS_QUIET_MODE"
#define PROXYCHAINS_CONF_FILE "proxychains.conf"
#define PROXYCHAINS_DEFAULT_CHAIN "ProxyList"
#define LOG_PREFIX "[proxychains] "
#ifndef SYSCONFDIR
#define SYSCONFDIR "/etc"
@ -11,6 +13,10 @@
#include <stddef.h>
extern const char *proxy_type_strmap[];
extern const char *chain_type_strmap[];
extern const char *proxy_state_strmap[];
char *get_config_path(char* default_path, char* pbuf, size_t bufsize);
void pc_stringfromipv4(unsigned char *ip_buf_4_bytes, char *outbuf_16_bytes);

View File

@ -40,10 +40,8 @@
#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;
extern proxy_chain_list *proxychains_chain_list;
static int poll_retry(struct pollfd *fds, nfds_t nfsd, int timeout) {
int ret;
@ -130,7 +128,7 @@ static int write_n_bytes(int fd, char *buff, size_t size) {
}
}
static int read_n_bytes(int fd, char *buff, size_t size) {
static int read_n_bytes(int fd, char *buff, size_t size, int read_time_out) {
int ready;
size_t i;
struct pollfd pfd[1];
@ -139,14 +137,14 @@ static int read_n_bytes(int fd, char *buff, size_t size) {
pfd[0].events = POLLIN;
for(i = 0; i < size; i++) {
pfd[0].revents = 0;
ready = poll_retry(pfd, 1, tcp_read_time_out);
ready = poll_retry(pfd, 1, read_time_out);
if(ready != 1 || !(pfd[0].revents & POLLIN) || 1 != read(fd, &buff[i], 1))
return -1;
}
return (int) size;
}
static int timed_connect(int sock, const struct sockaddr *addr, socklen_t len) {
static int timed_connect(int sock, const struct sockaddr *addr, socklen_t len, int connect_time_out) {
int ret, value;
socklen_t value_len;
struct pollfd pfd[1];
@ -159,7 +157,7 @@ static int timed_connect(int sock, const struct sockaddr *addr, socklen_t len) {
PDEBUG("\nconnect ret=%d\n", ret);
if(ret == -1 && errno == EINPROGRESS) {
ret = poll_retry(pfd, 1, tcp_connect_time_out);
ret = poll_retry(pfd, 1, connect_time_out);
PDEBUG("\npoll ret=%d\n", ret);
if(ret == 1) {
value_len = sizeof(socklen_t);
@ -187,7 +185,7 @@ static int timed_connect(int sock, const struct sockaddr *addr, socklen_t len) {
#define INVALID_INDEX 0xFFFFFFFFU
static int tunnel_to(int sock, ip_type ip, unsigned short port, proxy_type pt, char *user, char *pass) {
static int tunnel_to(int sock, ip_type ip, unsigned short port, proxy_type pt, char *user, char *pass, int read_time_out) {
char *dns_name = NULL;
char hostnamebuf[MSG_LEN_MAX];
size_t dns_len = 0;
@ -198,7 +196,7 @@ static int tunnel_to(int sock, ip_type ip, unsigned short port, proxy_type pt, c
// 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.)
// the hardcoded number 224 can now be changed using the config option remote_dns_subnet to i.e. 127
if(ip.octet[0] == remote_dns_subnet) {
if(ip.octet[0] == proxychains_chain_list->remote_dns_subnet) {
dns_len = at_get_host_for_ip(ip, hostnamebuf);
if(!dns_len) goto err;
else dns_name = hostnamebuf;
@ -206,8 +204,8 @@ static int tunnel_to(int sock, ip_type ip, unsigned short port, proxy_type pt, c
PDEBUG("host dns %s\n", dns_name ? dns_name : "<NULL>");
size_t ulen = strlen(user);
size_t passlen = strlen(pass);
size_t ulen = (user) ? strlen(user) : 0;
size_t passlen = (pass) ? strlen(pass) : 0;
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");
@ -230,7 +228,7 @@ static int tunnel_to(int sock, ip_type ip, unsigned short port, proxy_type pt, c
snprintf((char *) buff, sizeof(buff), "CONNECT %s:%d HTTP/1.0\r\n", dns_name,
ntohs(port));
if(user[0]) {
if(ulen) {
#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];
@ -256,7 +254,7 @@ static int tunnel_to(int sock, ip_type ip, unsigned short port, proxy_type pt, c
len = 0;
// read header byte by byte.
while(len < BUFF_SIZE) {
if(1 == read_n_bytes(sock, (char *) (buff + len), 1))
if(1 == read_n_bytes(sock, (char *) (buff + len), 1, read_time_out))
len++;
else
goto err;
@ -267,8 +265,10 @@ static int tunnel_to(int sock, ip_type ip, unsigned short port, proxy_type pt, c
}
// 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'))
if(len == BUFF_SIZE || !(buff[9] == '2' && buff[10] == '0' && buff[11] == '0')) {
PDEBUG("HTTP proxy blocked: buff=\"%s\"\n", buff);
return BLOCKED;
}
return SUCCESS;
}
@ -301,7 +301,7 @@ static int tunnel_to(int sock, ip_type ip, unsigned short port, proxy_type pt, c
if((len + 8) != write_n_bytes(sock, (char *) buff, (8 + len)))
goto err;
if(8 != read_n_bytes(sock, (char *) buff, 8))
if(8 != read_n_bytes(sock, (char *) buff, 8, read_time_out))
goto err;
if(buff[0] != 0 || buff[1] != 90)
@ -311,9 +311,9 @@ static int tunnel_to(int sock, ip_type ip, unsigned short port, proxy_type pt, c
}
break;
case SOCKS5_TYPE:{
if(user) {
if(ulen) {
buff[0] = 5; //version
buff[1] = 2; //nomber of methods
buff[1] = 2; //number of methods
buff[2] = 0; // no auth method
buff[3] = 2; /// auth method -> username / password
if(4 != write_n_bytes(sock, (char *) buff, 4))
@ -326,7 +326,7 @@ static int tunnel_to(int sock, ip_type ip, unsigned short port, proxy_type pt, c
goto err;
}
if(2 != read_n_bytes(sock, (char *) buff, 2))
if(2 != read_n_bytes(sock, (char *) buff, 2, read_time_out))
goto err;
if(buff[0] != 5 || (buff[1] != 0 && buff[1] != 2)) {
@ -356,7 +356,7 @@ static int tunnel_to(int sock, ip_type ip, unsigned short port, proxy_type pt, c
goto err;
if(2 != read_n_bytes(sock, in, 2))
if(2 != read_n_bytes(sock, in, 2, read_time_out))
goto err;
if(in[0] != 1 || in[1] != 0) {
if(in[0] != 1)
@ -388,7 +388,7 @@ static int tunnel_to(int sock, ip_type ip, unsigned short port, proxy_type pt, c
if(buff_iter != write_n_bytes(sock, (char *) buff, buff_iter))
goto err;
if(4 != read_n_bytes(sock, (char *) buff, 4))
if(4 != read_n_bytes(sock, (char *) buff, 4, read_time_out))
goto err;
if(buff[0] != 5 || buff[1] != 0)
@ -404,14 +404,14 @@ static int tunnel_to(int sock, ip_type ip, unsigned short port, proxy_type pt, c
break;
case 3:
len = 0;
if(1 != read_n_bytes(sock, (char *) &len, 1))
if(1 != read_n_bytes(sock, (char *) &len, 1, read_time_out))
goto err;
break;
default:
goto err;
}
if(len + 2 != read_n_bytes(sock, (char *) buff, len + 2))
if(len + 2 != read_n_bytes(sock, (char *) buff, len + 2, read_time_out))
goto err;
return SUCCESS;
@ -427,8 +427,9 @@ static int tunnel_to(int sock, ip_type ip, unsigned short port, proxy_type pt, c
#define DT "Dynamic chain"
#define ST "Strict chain"
#define RT "Random chain"
#define RRT "Round Robin chain"
static int start_chain(int *fd, proxy_data * pd, char *begin_mark) {
static int start_chain(int *fd, proxy_data * pd, char *begin_mark, int connect_time_out) {
struct sockaddr_in addr;
char ip_buf[16];
@ -444,7 +445,7 @@ static int start_chain(int *fd, proxy_data * pd, char *begin_mark) {
addr.sin_family = AF_INET;
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))) {
if(timed_connect(*fd, (struct sockaddr *) &addr, sizeof(addr), connect_time_out)) {
pd->ps = DOWN_STATE;
goto error1;
}
@ -511,7 +512,7 @@ static unsigned int calc_alive(proxy_data * pd, unsigned int proxy_count) {
}
static int chain_step(int ns, proxy_data * pfrom, proxy_data * pto) {
static int chain_step(int ns, proxy_data * pfrom, proxy_data * pto, int read_time_out) {
int retcode = -1;
char *hostname;
char hostname_buf[MSG_LEN_MAX];
@ -519,7 +520,7 @@ static int chain_step(int ns, proxy_data * pfrom, proxy_data * pto) {
PFUNC();
if(pto->ip.octet[0] == remote_dns_subnet) {
if(pto->ip.octet[0] == proxychains_chain_list->remote_dns_subnet) {
if(!at_get_host_for_ip(pto->ip, hostname_buf)) goto usenumericip;
else hostname = hostname_buf;
} else {
@ -529,7 +530,7 @@ static int chain_step(int ns, proxy_data * pfrom, proxy_data * pto) {
}
proxychains_write_log(TP " %s:%d ", hostname, htons(pto->port));
retcode = tunnel_to(ns, pto->ip, pto->port, pfrom->pt, pfrom->user, pfrom->pass);
retcode = tunnel_to(ns, pto->ip, pto->port, pfrom->pt, pfrom->user, pfrom->pass, read_time_out);
switch (retcode) {
case SUCCESS:
pto->ps = BUSY_STATE;
@ -549,20 +550,30 @@ static int chain_step(int ns, proxy_data * pfrom, proxy_data * pto) {
}
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) {
unsigned short target_port,
proxy_chain *pc) {
proxy_data p4;
proxy_data *p1, *p2, *p3;
int ns = -1;
int rc = -1;
unsigned int offset = 0;
unsigned int alive_count = 0;
unsigned int curr_len = 0;
unsigned int curr_pos = 0;
unsigned int looped = 0; // went back to start of list in RR mode
proxy_data * pd = pc->pd;
unsigned int proxy_count = pc->count;
chain_type ct = pc->ct;
unsigned int max_chain = pc->max_chain;
p3 = &p4;
PFUNC();
again:
rc = -1;
DUMP_PROXY_CHAIN(pc);
switch (ct) {
case DYNAMIC_TYPE:
@ -571,12 +582,12 @@ int connect_proxy_chain(int sock, ip_type target_ip,
do {
if(!(p1 = select_proxy(FIFOLY, pd, proxy_count, &offset)))
goto error_more;
} while(SUCCESS != start_chain(&ns, p1, DT) && offset < proxy_count);
} while(SUCCESS != start_chain(&ns, p1, DT, pc->tcp_connect_time_out) && offset < proxy_count);
for(;;) {
p2 = select_proxy(FIFOLY, pd, proxy_count, &offset);
if(!p2)
break;
if(SUCCESS != chain_step(ns, p1, p2)) {
if(SUCCESS != chain_step(ns, p1, p2, pc->tcp_read_time_out)) {
PDEBUG("GOTO AGAIN 1\n");
goto again;
}
@ -585,7 +596,53 @@ int connect_proxy_chain(int sock, ip_type target_ip,
//proxychains_write_log(TP);
p3->ip = target_ip;
p3->port = target_port;
if(SUCCESS != chain_step(ns, p1, p3))
if(SUCCESS != chain_step(ns, p1, p3, pc->tcp_read_time_out))
goto error;
break;
case ROUND_ROBIN_TYPE:
alive_count = calc_alive(pd, proxy_count);
curr_pos = offset = pc->offset;
if(alive_count < max_chain)
goto error_more;
PDEBUG("1:rr_offset = %d, curr_pos = %d\n", offset, curr_pos);
/* Check from current RR offset til end */
for (;rc != SUCCESS;) {
if (!(p1 = select_proxy(FIFOLY, pd, proxy_count, &offset))) {
/* We've receached the end of the list, go to the start */
offset = 0;
looped++;
continue;
} else if (looped && rc > 0 && offset >= curr_pos) {
PDEBUG("GOTO MORE PROXIES 0\n");
/* We've gone back to the start and now past our starting position */
pc->offset = 0;
goto error_more;
}
PDEBUG("2:rr_offset = %d\n", offset);
rc=start_chain(&ns, p1, RRT, pc->tcp_connect_time_out);
}
/* Create rest of chain using RR */
for(curr_len = 1; curr_len < max_chain;) {
PDEBUG("3:rr_offset = %d, curr_len = %d, max_chain = %d\n", offset, curr_len, max_chain);
p2 = select_proxy(FIFOLY, pd, proxy_count, &offset);
if(!p2) {
/* Try from the beginning to where we started */
offset = 0;
continue;
} else if(SUCCESS != chain_step(ns, p1, p2, pc->tcp_read_time_out)) {
PDEBUG("GOTO AGAIN 1\n");
goto again;
} else
p1 = p2;
curr_len++;
}
//proxychains_write_log(TP);
p3->ip = target_ip;
p3->port = target_port;
pc->offset = offset+1;
PDEBUG("pd_offset = %d, curr_len = %d\n", pc->offset, curr_len);
if(SUCCESS != chain_step(ns, p1, p3, pc->tcp_read_time_out))
goto error;
break;
@ -596,14 +653,14 @@ int connect_proxy_chain(int sock, ip_type target_ip,
PDEBUG("select_proxy failed\n");
goto error_strict;
}
if(SUCCESS != start_chain(&ns, p1, ST)) {
if(SUCCESS != start_chain(&ns, p1, ST, pc->tcp_connect_time_out)) {
PDEBUG("start_chain failed\n");
goto error_strict;
}
while(offset < proxy_count) {
if(!(p2 = select_proxy(FIFOLY, pd, proxy_count, &offset)))
break;
if(SUCCESS != chain_step(ns, p1, p2)) {
if(SUCCESS != chain_step(ns, p1, p2, pc->tcp_read_time_out)) {
PDEBUG("chain_step failed\n");
goto error_strict;
}
@ -612,7 +669,7 @@ int connect_proxy_chain(int sock, ip_type target_ip,
//proxychains_write_log(TP);
p3->ip = target_ip;
p3->port = target_port;
if(SUCCESS != chain_step(ns, p1, p3))
if(SUCCESS != chain_step(ns, p1, p3, pc->tcp_read_time_out))
goto error;
break;
@ -624,11 +681,11 @@ int connect_proxy_chain(int sock, ip_type target_ip,
do {
if(!(p1 = select_proxy(RANDOMLY, pd, proxy_count, &offset)))
goto error_more;
} while(SUCCESS != start_chain(&ns, p1, RT) && offset < max_chain);
} while(SUCCESS != start_chain(&ns, p1, RT, pc->tcp_connect_time_out) && offset < max_chain);
while(++curr_len < max_chain) {
if(!(p2 = select_proxy(RANDOMLY, pd, proxy_count, &offset)))
goto error_more;
if(SUCCESS != chain_step(ns, p1, p2)) {
if(SUCCESS != chain_step(ns, p1, p2, pc->tcp_read_time_out)) {
PDEBUG("GOTO AGAIN 2\n");
goto again;
}
@ -637,9 +694,12 @@ int connect_proxy_chain(int sock, ip_type target_ip,
//proxychains_write_log(TP);
p3->ip = target_ip;
p3->port = target_port;
if(SUCCESS != chain_step(ns, p1, p3))
if(SUCCESS != chain_step(ns, p1, p3, pc->tcp_read_time_out))
goto error;
default:
/* This should never happen */
proxychains_write_log("\nUnhandled chain type %d. This should never happen!\n", ct);
goto error;
}
proxychains_write_log(TP " OK\n");

View File

@ -25,6 +25,8 @@
#define __CORE_HEADER
#define BUFF_SIZE 8*1024 // used to read responses from proxies.
#define MAX_LOCALNET 64
#define MAX_CHAIN_LISTS 64
#define MAX_CHAIN 512
#include "ip_type.h"
@ -47,8 +49,10 @@ typedef enum {
typedef enum {
DYNAMIC_TYPE,
STRICT_TYPE,
RANDOM_TYPE}
chain_type;
RANDOM_TYPE,
ROUND_ROBIN_TYPE,
MAX_CHAIN_TYPE
} chain_type;
typedef enum {
PLAY_STATE,
@ -76,9 +80,31 @@ typedef struct {
char pass[256];
} proxy_data;
typedef struct {
char *name;
chain_type ct;
proxy_data *pd;
unsigned int count;
unsigned int offset;
unsigned int max_chain;
int tcp_read_time_out;
int tcp_connect_time_out;
} proxy_chain;
typedef struct {
chain_type ct;
proxy_chain *pc[MAX_CHAIN_LISTS];
unsigned int count;
localaddr_arg localnet_addr[MAX_LOCALNET];
size_t num_localnet_addr;
int remote_dns_subnet; // -1 means no remote dns
int tcp_read_time_out;
int tcp_connect_time_out;
proxy_chain *selected;
} proxy_chain_list;
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 );
proxy_chain *pc );
void proxychains_write_log(char *str, ...);

62
src/debug.c Normal file
View File

@ -0,0 +1,62 @@
#ifdef DEBUG
# include <string.h>
# include "core.h"
# include "common.h"
# include "debug.h"
void DUMP_PROXY_DATA_LIST_PREFIX(proxy_data *plist, unsigned int count, const char* prefix) {
char ip_buf[16], buff[48] = {'\0'};
strcat(strcat(buff, prefix), "PDATA:");
for (; count; plist++, count--) {
pc_stringfromipv4(&plist->ip.octet[0], ip_buf);
PDEBUG("%s[%s] %s %s:%d", buff, proxy_state_strmap[plist->ps],
proxy_type_strmap[plist->pt],
ip_buf, htons(plist->port));
if (*plist->user || *plist->pass) {
PSTDERR(" [u=%s,p=%s]", plist->user, plist->pass);
}
PSTDERR("\n");
}
}
void DUMP_PROXY_DATA_LIST(proxy_data *plist, unsigned int count) {
DUMP_PROXY_DATA_LIST_PREFIX(plist, count, "PDATA:");
}
void DUMP_PROXY_CHAIN_PREFIX(proxy_chain *pchain, const char* prefix) {
char buff[32] = {'\0'};
strcat(strcat(buff, prefix), "PCHAIN:");
prefix = buff;
PDEBUG("%s[name: \"%s\"]\n", prefix, pchain->name);
PDEBUG("%schain type: %s\n", prefix, chain_type_strmap[pchain->ct]);
PDEBUG("%stcp_read_time_out: %d\n", prefix, pchain->tcp_read_time_out);
PDEBUG("%stcp_connect_time_out: %d\n", prefix, pchain->tcp_connect_time_out);
PDEBUG("%smax_chain: %d\n", prefix, pchain->max_chain);
PDEBUG("%soffset: %d\n", prefix, pchain->offset);
PDEBUG("%scount: %d\n", prefix, pchain->count);
DUMP_PROXY_DATA_LIST_PREFIX(pchain->pd, pchain->count, prefix);
}
void DUMP_PROXY_CHAIN(proxy_chain *pchain) {
DUMP_PROXY_CHAIN_PREFIX(pchain, "");
}
void DUMP_PROXY_CHAIN_LIST(proxy_chain_list *pc_list) {
const char *prefix = "PCLIST:";
int i = 0;
PDEBUG("%schain type (default): %s\n", prefix, chain_type_strmap[pc_list->ct]);
PDEBUG("%stcp_read_time_out: %d\n", prefix, pc_list->tcp_read_time_out);
PDEBUG("%stcp_connect_time_out: %d\n", prefix, pc_list->tcp_connect_time_out);
PDEBUG("%sremote_dns_subnet: %d\n", prefix, pc_list->remote_dns_subnet);
PDEBUG("%sselected chain: %s\n", prefix, (pc_list->selected)?pc_list->selected->name:NULL);
PDEBUG("%snum_localnet_addr: %u\n", prefix, (unsigned int)pc_list->num_localnet_addr);
PDEBUG("%schain list count: %d\n", prefix, pc_list->count);
for (; i < pc_list->count; i++) {
//~ DUMP_PROXY_CHAIN(pc_list->pc[i]);
DUMP_PROXY_CHAIN_PREFIX(pc_list->pc[i], prefix);
}
}
#endif

View File

@ -3,9 +3,19 @@
#ifdef DEBUG
# include <stdio.h>
# define PDEBUG(fmt, args...) do { dprintf(2,"DEBUG:"fmt, ## args); } while(0)
# define PSTDERR(fmt, args...) do { dprintf(2,fmt, ## args); } while(0)
# define PDEBUG(fmt, args...) PSTDERR("DEBUG:"fmt, ## args)
# include "core.h"
void DUMP_PROXY_DATA_LIST(proxy_data *plist, unsigned int count);
void DUMP_PROXY_CHAIN(proxy_chain *pchain);
void DUMP_PROXY_CHAIN_LIST(proxy_chain_list *pc_list);
#else
# define PDEBUG(fmt, args...) do {} while (0)
# define DUMP_PROXY_DATA_LIST(args...) do {} while (0)
# define DUMP_PROXY_CHAIN(args...) do {} while (0)
# define DUMP_PROXY_CHAIN_LIST(args...) do {} while (0)
#endif
# define PFUNC() do { PDEBUG("pid[%d]:%s\n", getpid(), __FUNCTION__); } while(0)

View File

@ -43,7 +43,6 @@
#define SOCKADDR_2(x) (satosin(x)->sin_addr)
#define SOCKPORT(x) (satosin(x)->sin_port)
#define SOCKFAMILY(x) (satosin(x)->sin_family)
#define MAX_CHAIN 512
close_t true_close;
connect_t true_connect;
@ -53,24 +52,20 @@ freeaddrinfo_t true_freeaddrinfo;
getnameinfo_t true_getnameinfo;
gethostbyaddr_t true_gethostbyaddr;
int tcp_read_time_out;
int tcp_connect_time_out;
chain_type proxychains_ct;
proxy_data proxychains_pd[MAX_CHAIN];
unsigned int proxychains_proxy_count = 0;
int proxychains_got_chain_data = 0;
unsigned int proxychains_max_chain = 1;
int proxychains_quiet_mode = 0;
int proxychains_resolver = 0;
localaddr_arg localnet_addr[MAX_LOCALNET];
size_t num_localnet_addr = 0;
unsigned int remote_dns_subnet = 224;
proxy_chain_list *proxychains_chain_list = NULL;
pthread_once_t init_once = PTHREAD_ONCE_INIT;
static int init_l = 0;
static inline void get_chain_data(proxy_data * pd, unsigned int *proxy_count, chain_type * ct);
static inline void get_chain_data(proxy_chain_list *pc_list);
static inline int get_chain_type(char *buff, chain_type *ct);
int proxy_chain_list_load(proxy_chain_list *pc_list);
int proxy_chain_load_pdata(proxy_chain *pc, proxy_data *pd_list, int count);
proxy_chain* proxy_chain_list_set_selected(proxy_chain_list *pc_list, const char *chain_name);
static void* load_sym(char* symname, void* proxyfunc) {
@ -103,8 +98,7 @@ static void do_init(void) {
core_initialize();
at_init();
/* read the config file */
get_chain_data(proxychains_pd, &proxychains_proxy_count, &proxychains_ct);
proxy_chain_list_load(proxychains_chain_list);
proxychains_write_log(LOG_PREFIX "DLL init\n");
@ -151,21 +145,19 @@ static void gcc_init(void) {
#endif
/* get configuration from config file */
static void get_chain_data(proxy_data * pd, unsigned int *proxy_count, chain_type * ct) {
static void get_chain_data(proxy_chain_list *pc_list) {
static int got_chain_data = 0;
int count = 0, port_n = 0, list = 0;
char buff[1024], type[1024], host[1024], user[1024];
char buff[1024], type[1024], host[1024], label[1024];
char *env;
char local_in_addr_port[32];
char local_in_addr[32], local_in_port[32], local_netmask[32];
FILE *file = NULL;
proxy_chain *pc_curr = NULL;
proxy_data pd_list[MAX_CHAIN];
if(proxychains_got_chain_data)
if(got_chain_data)
return;
//Some defaults
tcp_read_time_out = 4 * 1000;
tcp_connect_time_out = 10 * 1000;
*ct = DYNAMIC_TYPE;
env = get_config_path(getenv(PROXYCHAINS_CONF_FILE_ENV_VAR), buff, sizeof(buff));
if( ( file = fopen(env, "r") ) == NULL )
@ -181,58 +173,107 @@ static void get_chain_data(proxy_data * pd, unsigned int *proxy_count, chain_typ
while(fgets(buff, sizeof(buff), file)) {
if(buff[0] != '\n' && buff[strspn(buff, " ")] != '#') {
/* proxylist has to come last */
if(list) {
if(list && (buff[0] != '[')) {
if(count >= MAX_CHAIN)
break;
memset(&pd[count], 0, sizeof(proxy_data));
memset(&pd_list[count], 0, sizeof(proxy_data));
pd[count].ps = PLAY_STATE;
pd_list[count].ps = PLAY_STATE;
port_n = 0;
sscanf(buff, "%s %s %d %s %s", type, host, &port_n, pd[count].user, pd[count].pass);
in_addr_t host_ip = inet_addr(host);
if(host_ip == INADDR_NONE) {
fprintf(stderr, "proxy %s has invalid value or is not numeric\n", host);
exit(1);
}
pd[count].ip.as_int = (uint32_t) host_ip;
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 && pd[count].ip.as_int != (uint32_t) - 1)
count++;
} else {
if(strstr(buff, "[ProxyList]")) {
list = 1;
} else if(strstr(buff, "random_chain")) {
*ct = RANDOM_TYPE;
} else if(strstr(buff, "strict_chain")) {
*ct = STRICT_TYPE;
} else if(strstr(buff, "dynamic_chain")) {
*ct = DYNAMIC_TYPE;
} else if(strstr(buff, "tcp_read_time_out")) {
sscanf(buff, "%s %d", user, &tcp_read_time_out);
if(strstr(buff, "tcp_read_time_out")) {
sscanf(buff, "%s %d", label, &pc_curr->tcp_read_time_out);
} else if(strstr(buff, "tcp_connect_time_out")) {
sscanf(buff, "%s %d", user, &tcp_connect_time_out);
sscanf(buff, "%s %d", label, &pc_curr->tcp_connect_time_out);
} else if(strstr(buff, "chain_len")) {
char *pc;
int len = 1;
pc = strchr(buff, '=');
if ((pc=strchr(buff, '=')) == NULL) {
fprintf(stderr, "Warning: chain_len must use '='\n");
} else
len = atoi(++pc);
pc_curr->max_chain = len;
} else if(!get_chain_type(buff, &pc_curr->ct)) {
;
} else {
pd_list[count].user[0] = pd_list[count].pass[0] = '\0';
sscanf(buff, "%s %s %d %s %s", type, host, &port_n, pd_list[count].user, pd_list[count].pass);
in_addr_t host_ip = inet_addr(host);
if(host_ip == INADDR_NONE) {
fprintf(stderr, "proxy %s has invalid value or is not numeric\n", host);
exit(1);
}
pd_list[count].ip.as_int = (uint32_t) host_ip;
pd_list[count].port = htons((unsigned short) port_n);
if(!strcmp(type, "http")) {
pd_list[count].pt = HTTP_TYPE;
} else if(!strcmp(type, "socks4")) {
pd_list[count].pt = SOCKS4_TYPE;
} else if(!strcmp(type, "socks5")) {
pd_list[count].pt = SOCKS5_TYPE;
} else
continue;
if(pd_list[count].ip.as_int && port_n && pd_list[count].ip.as_int != (uint32_t) - 1)
count++;
}
} else {
char *s1, *s2;
if((s1=(strstr(buff, "["))+1) && (s1 < (s2=strstr(buff, "]")))) {
/* If have a previous chain stored in the temp chain, copy
to global lists. */
if (count) {
proxy_chain_load_pdata(pc_curr, pd_list, count);
count = 0;
}
PDEBUG("Parsing chain: %s\n", buff);
if (pc_list->count >= MAX_CHAIN_LISTS) {
proxychains_write_log(LOG_PREFIX "Warning more than %d lists defined in configfile, skipping any more list definitions.\n", MAX_CHAIN_LISTS);
continue;
}
/* Create new proxy list */
pc_curr = pc_list->pc[pc_list->count++] = (proxy_chain*)malloc(sizeof(proxy_chain));
if (pc_curr == NULL) {
proxychains_write_log(LOG_PREFIX "Error failed to allocate proxy chain object\n");
exit(1);
}
pc_curr->ct = DYNAMIC_TYPE;
pc_curr->count = 0;
pc_curr->offset = 0;
pc_curr->max_chain = 1;
pc_curr->tcp_read_time_out = pc_list->tcp_read_time_out;
pc_curr->tcp_connect_time_out = pc_list->tcp_connect_time_out;
pc_curr->name = (char*)malloc(sizeof(char)*(s2-s1));
if (pc_curr->name == NULL) {
proxychains_write_log(LOG_PREFIX "Error failed to allocate proxy chain name string\n");
exit(1);
}
strncpy(pc_curr->name, s1, s2-s1);
list = 1;
} else if(!get_chain_type(buff, &pc_list->ct)) {
;
} else if(strstr(buff, "tcp_read_time_out")) {
sscanf(buff, "%s %d", label, &pc_list->tcp_read_time_out);
} else if(strstr(buff, "tcp_connect_time_out")) {
sscanf(buff, "%s %d", label, &pc_list->tcp_connect_time_out);
} else if(strstr(buff, "remote_dns_subnet")) {
sscanf(buff, "%s %d", user, &remote_dns_subnet);
if(remote_dns_subnet >= 256) {
sscanf(buff, "%s %d", label, &pc_list->remote_dns_subnet);
if(pc_list->remote_dns_subnet >= 256) {
fprintf(stderr,
"remote_dns_subnet: invalid value. requires a number between 0 and 255.\n");
exit(1);
}
} else if(strstr(buff, "localnet")) {
if(sscanf(buff, "%s %21[^/]/%15s", user, local_in_addr_port, local_netmask) < 3) {
localaddr_arg *laddr_a = &pc_list->localnet_addr[pc_list->num_localnet_addr];
if(sscanf(buff, "%s %21[^/]/%15s", label, local_in_addr_port, local_netmask) < 3) {
fprintf(stderr, "localnet format error");
exit(1);
}
@ -246,38 +287,27 @@ static void get_chain_data(proxy_data * pd, unsigned int *proxy_count, chain_typ
PDEBUG("added localnet: netaddr=%s, port=%s, netmask=%s\n",
local_in_addr, local_in_port, local_netmask);
}
if(num_localnet_addr < MAX_LOCALNET) {
if(pc_list->num_localnet_addr < MAX_LOCALNET) {
int error;
error =
inet_pton(AF_INET, local_in_addr,
&localnet_addr[num_localnet_addr].in_addr);
error = inet_pton(AF_INET, local_in_addr, &laddr_a->in_addr);
if(error <= 0) {
fprintf(stderr, "localnet address error\n");
exit(1);
}
error =
inet_pton(AF_INET, local_netmask,
&localnet_addr[num_localnet_addr].netmask);
error = inet_pton(AF_INET, local_netmask, &laddr_a->netmask);
if(error <= 0) {
fprintf(stderr, "localnet netmask error\n");
exit(1);
}
if(local_in_port[0]) {
localnet_addr[num_localnet_addr].port =
(short) atoi(local_in_port);
laddr_a->port = (short) atoi(local_in_port);
} else {
localnet_addr[num_localnet_addr].port = 0;
laddr_a->port = 0;
}
++num_localnet_addr;
++pc_list->num_localnet_addr;
} else {
fprintf(stderr, "# of localnet exceed %d.\n", MAX_LOCALNET);
}
} 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")) {
proxychains_quiet_mode = 1;
} else if(strstr(buff, "proxy_dns")) {
@ -286,9 +316,88 @@ static void get_chain_data(proxy_data * pd, unsigned int *proxy_count, chain_typ
}
}
}
/* If have a previous chain stored in the temp chain, copy
to global lists. This is needed for the last defined chain. */
if (count) {
proxy_chain_load_pdata(pc_curr, pd_list, count);
count = 0;
}
fclose(file);
*proxy_count = count;
proxychains_got_chain_data = 1;
//~ *proxy_count = count;
got_chain_data = 1;
}
int get_chain_type(char *buff, chain_type *ct) {
int i = 0;
for (; i < MAX_CHAIN_TYPE; i++) {
if (strstr(buff, chain_type_strmap[i])) {
*ct = i;
return 0;
}
}
return 1;
}
int proxy_chain_list_load(proxy_chain_list *pc_list) {
char *env = NULL;
/* Create global library data */
proxychains_chain_list = (proxy_chain_list*)malloc(sizeof(proxy_chain_list));
if (proxychains_chain_list == NULL) {
proxychains_write_log(LOG_PREFIX "Error failed to allocate proxy list object\n");
exit(1);
}
/* Initialize proxychain library data */
proxychains_chain_list->remote_dns_subnet = -1; // -1 means no remote dns
//~ proxychains_chain_list->pc = NULL;
proxychains_chain_list->count = 0;
//~ proxychains_chain_list->localnet_addr = NULL;
proxychains_chain_list->num_localnet_addr = 0;
proxychains_chain_list->tcp_read_time_out = 4 * 1000;
proxychains_chain_list->tcp_connect_time_out = 10 * 1000;
//~ proxychains_chain_list->chain_selection = PROXYCHAINS_DEFAULT_CHAIN;
proxychains_chain_list->selected = NULL;
/* read the config file */
get_chain_data(proxychains_chain_list);
PDEBUG("Finished loading chain data\n");
DUMP_PROXY_CHAIN_LIST(proxychains_chain_list);
//~ DUMP_PROXY_CHAIN(proxychains_chain_list->pc[0]);
env = getenv(PROXYCHAINS_CHAIN_ENV_VAR);
if(!env)
env = PROXYCHAINS_DEFAULT_CHAIN;
if (!proxy_chain_list_set_selected(proxychains_chain_list, env)) {
proxychains_write_log(LOG_PREFIX "Error chain list \"%s\" not found\n", env);
exit(1);
}
return 0;
}
int proxy_chain_load_pdata(proxy_chain *pc, proxy_data *pd_list, int count) {
pc->count = count;
pc->pd = (proxy_data*)malloc(sizeof(proxy_data)*count);
if (pc->pd == NULL) {
proxychains_write_log(LOG_PREFIX "Error failed to allocate proxy data list for \"%s\" chain\n", pc->name);
exit(1);
}
memcpy(pc->pd, pd_list, sizeof(proxy_data)*count);
return 0;
}
proxy_chain* proxy_chain_list_set_selected(proxy_chain_list *pc_list, const char *chain_name) {
int i = 0;
for (; i < pc_list->count; i++) {
if (!strcmp(chain_name, pc_list->pc[i]->name)) {
pc_list->selected = pc_list->pc[i];
return pc_list->pc[i];
}
}
return NULL;
}
/******* HOOK FUNCTIONS *******/
@ -332,12 +441,12 @@ int connect(int sock, const struct sockaddr *addr, unsigned int len) {
#endif
// check if connect called from proxydns
remote_dns_connect = (ntohl(p_addr_in->s_addr) >> 24 == remote_dns_subnet);
remote_dns_connect = (ntohl(p_addr_in->s_addr) >> 24 == proxychains_chain_list->remote_dns_subnet);
for(i = 0; i < num_localnet_addr && !remote_dns_connect; i++) {
if((localnet_addr[i].in_addr.s_addr & localnet_addr[i].netmask.s_addr)
== (p_addr_in->s_addr & localnet_addr[i].netmask.s_addr)) {
if(!localnet_addr[i].port || localnet_addr[i].port == port) {
for(i = 0; i < proxychains_chain_list->num_localnet_addr && !remote_dns_connect; i++) {
if((proxychains_chain_list->localnet_addr[i].in_addr.s_addr & proxychains_chain_list->localnet_addr[i].netmask.s_addr)
== (p_addr_in->s_addr & proxychains_chain_list->localnet_addr[i].netmask.s_addr)) {
if(!proxychains_chain_list->localnet_addr[i].port || proxychains_chain_list->localnet_addr[i].port == port) {
PDEBUG("accessing localnet using true_connect\n");
return true_connect(sock, addr, len);
}
@ -353,7 +462,7 @@ int connect(int sock, const struct sockaddr *addr, unsigned int len) {
ret = connect_proxy_chain(sock,
dest_ip,
SOCKPORT(*addr),
proxychains_pd, proxychains_proxy_count, proxychains_ct, proxychains_max_chain);
proxychains_chain_list->selected);
fcntl(sock, F_SETFL, flags);
if(ret != SUCCESS)

View File

@ -22,13 +22,27 @@ strict_chain
# all proxies must be online to play in chain
# otherwise EINTR is returned to the app
#
#round_robin_chain
#
# Round Robin - Each connection will be done via chained proxies
# of chain_len length
# all proxies chained in the order as they appear in the list
# at least one proxy must be online to play in chain
# (dead proxies are skipped).
# the start of the current proxy chain is the proxy after the last
# proxy in the previously invoked proxy chain.
# if the end of the proxy chain is reached while looking for proxies
# start at the beginning again.
# otherwise EINTR is returned to the app
# These semantics are not guaranteed in a multithreaded environment.
#
#random_chain
#
# Random - Each connection will be done via random proxy
# (or proxy chain, see chain_len) from the list.
# this option is good to test your IDS :)
# Make sense only if random_chain
# Make sense only if random_chain or round_robin_chain
#chain_len = 2
# Quiet mode (no output from library)
@ -93,7 +107,59 @@ tcp_connect_time_out 8000
#
# proxy types: http, socks4, socks5
# ( auth types supported: "basic"-http "user/pass"-socks )
# Select the list you want to use by setting the PROXYCHAINS_CHAIN envvar to
# the name of the list. If the envvar is not set, the default chain is
# "ProxyList".
#
# Example 1: Your corporate network admin is the BOFH. You're not officially
# allowed access to the internet. But you've found a sequence of proxies
# setup to connect the various internal networks, with one of them having
# internet access.
# [LetMeOut]
# strict_chain
# socks5 192.168.89.2 1080
# http 172.16.30.10 8080
# http 10.10.5.4 80
#
# Example 2: Suppose you have access to several fast caching proxies and you
# want to load balance connections across them. Since they're fast, they
# shouldn't need large timeouts. If one of them happens to go down, it will
# be removed from the active list and each connect() will use the next proxy,
# going back to the beginning once the end is reached.
# [LoadBalanceList]
# round_robin_chain
# max_chain = 1
# tcp_read_time_out 2000
# tcp_connect_time_out 1000
# http 192.168.89.2 8080
# http 192.168.89.3 8080
# http 192.168.89.4 8080
# http 192.168.89.5 8080
#
# Example 3: We're doing some scraping again the wishes of our target, so we
# come at him from all sides. But since we're using random free proxies found
# on the web, many of the proxies are slow an unreliable. Give a larger
# timeout to account for this. The broken/dead ones will be removed as they
# are encountered and we'll cycle through each live proxy sequentially per
# connect().
# [AvoidDetection]
# round_robin_chain
# max_chain = 1
# tcp_read_time_out 20000
# tcp_connect_time_out 10000
# http 91.106.83.204 80
# http 178.237.184.222 3128
# http 109.207.61.164 8090
# http 190.75.178.219 8080
# http 168.63.43.185 3128
# http 193.95.90.194 3128
# http 54.214.237.232 80
# http 81.169.166.83 80
# http 201.85.50.249 80
# http 173.192.81.137 8080
# http 79.127.101.96 8080
[ProxyList]
# add proxy here ...
# meanwile