mirror of
https://github.com/rofl0r/proxychains-ng
synced 2026-05-13 17:03:07 +08:00
Compare commits
27 Commits
v4.16
...
3a33be6330
@@ -1,4 +1,5 @@
|
||||
proxychains4
|
||||
proxychains4-daemon
|
||||
*.bz2
|
||||
*.xz
|
||||
*.o
|
||||
|
||||
@@ -11,7 +11,8 @@ bindir = $(exec_prefix)/bin
|
||||
prefix = /usr/local/
|
||||
includedir = $(prefix)/include
|
||||
libdir = $(prefix)/lib
|
||||
sysconfdir=$(prefix)/etc
|
||||
sysconfdir = $(prefix)/etc
|
||||
zshcompletiondir = $(prefix)/share/zsh/site-functions
|
||||
|
||||
OBJS = src/common.o src/main.o
|
||||
|
||||
@@ -48,6 +49,7 @@ PXCHAINS = proxychains4
|
||||
PXCHAINS_D = proxychains4-daemon
|
||||
ALL_TOOLS = $(PXCHAINS) $(PXCHAINS_D)
|
||||
ALL_CONFIGS = src/proxychains.conf
|
||||
ZSH_COMPLETION = completions/zsh/_proxychains4
|
||||
|
||||
-include config.mak
|
||||
|
||||
@@ -68,9 +70,13 @@ $(DESTDIR)$(libdir)/%: %
|
||||
$(DESTDIR)$(sysconfdir)/%: src/%
|
||||
$(INSTALL) -D -m 644 $< $@
|
||||
|
||||
$(DESTDIR)$(zshcompletiondir)/%: completions/zsh/%
|
||||
$(INSTALL) -D -m 644 $< $@
|
||||
|
||||
install-libs: $(ALL_LIBS:%=$(DESTDIR)$(libdir)/%)
|
||||
install-tools: $(ALL_TOOLS:%=$(DESTDIR)$(bindir)/%)
|
||||
install-config: $(ALL_CONFIGS:src/%=$(DESTDIR)$(sysconfdir)/%)
|
||||
install-zsh-completion: $(ZSH_COMPLETION:completions/zsh/%=$(DESTDIR)$(zshcompletiondir)/%)
|
||||
|
||||
clean:
|
||||
rm -f $(ALL_LIBS)
|
||||
@@ -87,14 +93,14 @@ src/version.o: src/version.h
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) $(CFLAGS_MAIN) $(INC) $(PIC) -c -o $@ $<
|
||||
|
||||
$(LDSO_PATHNAME): $(LOBJS)
|
||||
$(CC) $(LDFLAGS) $(LD_SET_SONAME)$(LDSO_PATHNAME) $(USER_LDFLAGS) \
|
||||
-shared -o $@ $^ $(SOCKET_LIBS)
|
||||
$(CC) $(LDFLAGS) $(FAT_LDFLAGS) $(LD_SET_SONAME)$(LDSO_PATHNAME) \
|
||||
$(USER_LDFLAGS) -shared -o $@ $^ $(SOCKET_LIBS)
|
||||
|
||||
$(PXCHAINS): $(OBJS)
|
||||
$(CC) $^ $(USER_LDFLAGS) $(LIBDL) -o $@
|
||||
$(CC) $^ $(FAT_BIN_LDFLAGS) $(USER_LDFLAGS) $(LIBDL) -o $@
|
||||
|
||||
$(PXCHAINS_D): $(DOBJS)
|
||||
$(CC) $^ $(USER_LDFLAGS) -o $@
|
||||
$(CC) $^ $(FAT_BIN_LDFLAGS) $(USER_LDFLAGS) -o $@
|
||||
|
||||
|
||||
.PHONY: all clean install install-config install-libs install-tools
|
||||
.PHONY: all clean install install-config install-libs install-tools install-zsh-completion
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
ProxyChains-NG ver 4.16 README
|
||||
ProxyChains-NG ver 4.17 README
|
||||
=============================
|
||||
|
||||
ProxyChains is a UNIX program, that hooks network-related libc functions
|
||||
@@ -52,6 +52,15 @@ ProxyChains-NG ver 4.16 README
|
||||
|
||||
Changelog:
|
||||
----------
|
||||
Version 4.17
|
||||
- add hook for close_range function, fixing newer versions of openssh
|
||||
- fat-binary-m1 option for mac
|
||||
- fix DNS error handling in proxy_dns_old
|
||||
- simplify init code
|
||||
- fix openbsd preloading
|
||||
- fix double-close in multithreaded apps
|
||||
- various improvements to configure script
|
||||
|
||||
Version 4.16
|
||||
- fix regression in configure script linker flag detection
|
||||
- remove 10 year old workaround for wrong glibc getnameinfo signature
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
#compdef proxychains4
|
||||
|
||||
_arguments \
|
||||
'(- : *)--help[More help in README file]' \
|
||||
'-q[makes proxychains quiet - this overrides the config setting]' \
|
||||
'-f[allows one to manually specify a configfile to use]: :_files' \
|
||||
'(-)1: :{_command_names -e}' \
|
||||
'*:: :_normal'
|
||||
@@ -86,6 +86,8 @@ usage() {
|
||||
echo " if set to yes ignores CVE-2015-3887 and makes it possible"
|
||||
echo " to preload from current dir (possibly insecure, but handy)"
|
||||
echo "--fat-binary : build for both i386 and x86_64 architectures on 64-bit Macs"
|
||||
echo "--fat-binary-m1 : build for both arm64e and x86_64 architectures on M1 Macs"
|
||||
echo "--fat-binary-m2 : build for arm64, arm64e and x86_64 architectures on M2+ Macs"
|
||||
echo "--hookmethod=dlsym|dyld hook method for osx. default: auto"
|
||||
echo " if OSX >= 12 is detected, dyld method will be used if auto."
|
||||
echo "--help : show this text"
|
||||
@@ -100,6 +102,8 @@ spliteq() {
|
||||
}
|
||||
|
||||
fat_binary=
|
||||
fat_binary_m1=
|
||||
fat_binary_m2=
|
||||
ignore_cve=no
|
||||
hookmethod=auto
|
||||
|
||||
@@ -115,6 +119,8 @@ parsearg() {
|
||||
--ignore-cve=*) ignore_cve=`spliteq $1`;;
|
||||
--hookmethod=*) hookmethod=`spliteq $1`;;
|
||||
--fat-binary) fat_binary=1;;
|
||||
--fat-binary-m1) fat_binary_m1=1;;
|
||||
--fat-binary-m2) fat_binary_m2=1;;
|
||||
--help) usage;;
|
||||
esac
|
||||
}
|
||||
@@ -174,6 +180,24 @@ ishaiku() {
|
||||
}
|
||||
|
||||
check_compile 'whether C compiler works' '' 'int main() {return 0;}' || fail 'error: install a C compiler and library'
|
||||
check_compile 'whether libc headers are complete' '' '#include <netdb.h>\nint main() {return 0;}' || fail 'error: necessary libc headers are not installed'
|
||||
check_compile 'whether C compiler understands -Wno-unknown-pragmas' '-Wno-unknown-pragmas' 'int main() {return 0;}'
|
||||
|
||||
if ! check_compile 'whether getnameinfo() servlen argument is POSIX compliant (socklen_t)' "-DGN_NODELEN_T=socklen_t -DGN_SERVLEN_T=socklen_t -DGN_FLAGS_T=int" \
|
||||
'#define _GNU_SOURCE\n#include <netdb.h>\nint getnameinfo(const struct sockaddr *, socklen_t, char *, socklen_t, char *, socklen_t, int);int main() {\nreturn 0;}' ; then
|
||||
# GLIBC < 2.14
|
||||
if ! check_compile 'whether getnameinfo() flags argument is unsigned' "-DGN_NODELEN_T=socklen_t -DGN_SERVLEN_T=socklen_t -DGN_FLAGS_T=unsigned" \
|
||||
'#define _GNU_SOURCE\n#include <netdb.h>\nint getnameinfo(const struct sockaddr *, socklen_t, char *, socklen_t, char *, socklen_t, unsigned);int main() {\nreturn 0;}' ; then
|
||||
if ! check_compile 'whether getnameinfo() servlen argument is size_t' "-DGN_NODELEN_T=socklen_t -DGN_SERVLEN_T=size_t -DGN_FLAGS_T=int" \
|
||||
'#define _GNU_SOURCE\n#include <netdb.h>\nint getnameinfo(const struct sockaddr *, socklen_t, char *, socklen_t, char *, size_t, int);int main() {\nreturn 0;}' ; then
|
||||
# OpenBSD & FreeBSD
|
||||
if ! check_compile 'whether getnameinfo() servlen and nodelen argument is size_t' "-DGN_NODELEN_T=size_t -DGN_SERVLEN_T=size_t -DGN_FLAGS_T=int" \
|
||||
'#define _GNU_SOURCE\n#include <netdb.h>\nint getnameinfo(const struct sockaddr *, socklen_t, char *, size_t, char *, size_t, int);int main() {\nreturn 0;}' ; then
|
||||
fail "failed to detect getnameinfo signature"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
check_compile 'whether we have GNU-style getservbyname_r()' "-DHAVE_GNU_GETSERVBYNAME_R" \
|
||||
'#define _GNU_SOURCE\n#include <netdb.h>\nint main() {\nstruct servent *se = 0;struct servent se_buf;char buf[1024];\ngetservbyname_r("foo", (void*) 0, &se_buf, buf, sizeof(buf), &se);\nreturn 0;}'
|
||||
@@ -259,7 +283,20 @@ if ismac ; then
|
||||
if ismac64 && [ "$fat_binary" = 1 ] ; then
|
||||
echo "Configuring a fat binary for i386 and x86_64"
|
||||
echo "MAC_CFLAGS+=-arch i386 -arch x86_64">>config.mak
|
||||
echo "LDFLAGS+=-arch i386 -arch x86_64">>config.mak
|
||||
echo "FAT_LDFLAGS=-arch i386 -arch x86_64">>config.mak
|
||||
echo "FAT_BIN_LDFLAGS=-arch i386 -arch x86_64">>config.mak
|
||||
fi
|
||||
if [ "$fat_binary_m1" = 1 ] ; then
|
||||
echo "Configuring a fat binary for arm64[e] and x86_64"
|
||||
echo "MAC_CFLAGS+=-arch arm64 -arch arm64e -arch x86_64">>config.mak
|
||||
echo "FAT_LDFLAGS=-arch arm64 -arch arm64e -arch x86_64">>config.mak
|
||||
echo "FAT_BIN_LDFLAGS=-arch arm64 -arch x86_64">>config.mak
|
||||
fi
|
||||
if [ "$fat_binary_m2" = 1 ] ; then
|
||||
echo "Configuring a fat binary for arm64[e] and x86_64"
|
||||
echo "MAC_CFLAGS+=-arch arm64 -arch arm64e -arch x86_64">>config.mak
|
||||
echo "FAT_LDFLAGS=-arch arm64 -arch arm64e -arch x86_64">>config.mak
|
||||
echo "FAT_BIN_LDFLAGS=-arch arm64 -arch arm64e -arch x86_64">>config.mak
|
||||
fi
|
||||
elif isbsd ; then
|
||||
echo LIBDL=>>config.mak
|
||||
@@ -274,3 +311,6 @@ elif ishaiku ; then
|
||||
fi
|
||||
|
||||
echo "Done, now run $make_cmd && $make_cmd install"
|
||||
if [ "$fat_binary_m2" = 1 ] ; then
|
||||
echo "Don't forget to run csrutil disable and sudo nvram boot-args=-arm64e_preview_abi"
|
||||
fi
|
||||
|
||||
+33
-34
@@ -462,8 +462,10 @@ static int start_chain(int *fd, proxy_data * pd, char *begin_mark) {
|
||||
error1:
|
||||
proxychains_write_log(TP " timeout\n");
|
||||
error:
|
||||
if(*fd != -1)
|
||||
if(*fd != -1) {
|
||||
close(*fd);
|
||||
*fd = -1;
|
||||
}
|
||||
return SOCKET_ERROR;
|
||||
}
|
||||
|
||||
@@ -520,9 +522,9 @@ 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 retcode = -1;
|
||||
char *hostname;
|
||||
char *hostname, *errmsg = 0;
|
||||
char hostname_buf[MSG_LEN_MAX];
|
||||
char ip_buf[INET6_ADDRSTRLEN];
|
||||
int v6 = pto->ip.is_v6;
|
||||
@@ -536,31 +538,34 @@ static int chain_step(int ns, proxy_data * pfrom, proxy_data * pto) {
|
||||
usenumericip:
|
||||
if(!inet_ntop(v6?AF_INET6:AF_INET,pto->ip.addr.v6,ip_buf,sizeof ip_buf)) {
|
||||
pto->ps = DOWN_STATE;
|
||||
proxychains_write_log("<--ip conversion error!\n");
|
||||
close(ns);
|
||||
return SOCKET_ERROR;
|
||||
errmsg = "<--ip conversion error!\n";
|
||||
retcode = SOCKET_ERROR;
|
||||
goto err;
|
||||
}
|
||||
hostname = ip_buf;
|
||||
}
|
||||
|
||||
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);
|
||||
switch (retcode) {
|
||||
case SUCCESS:
|
||||
pto->ps = BUSY_STATE;
|
||||
break;
|
||||
case BLOCKED:
|
||||
pto->ps = BLOCKED_STATE;
|
||||
proxychains_write_log("<--denied\n");
|
||||
close(ns);
|
||||
break;
|
||||
errmsg = "<--denied\n";
|
||||
goto err;
|
||||
case SOCKET_ERROR:
|
||||
pto->ps = DOWN_STATE;
|
||||
proxychains_write_log("<--socket error or timeout!\n");
|
||||
close(ns);
|
||||
break;
|
||||
errmsg = "<--socket error or timeout!\n";
|
||||
goto err;
|
||||
}
|
||||
return retcode;
|
||||
err:
|
||||
if(errmsg) proxychains_write_log(errmsg);
|
||||
if(*ns != -1) close(*ns);
|
||||
*ns = -1;
|
||||
return retcode;
|
||||
}
|
||||
|
||||
int connect_proxy_chain(int sock, ip_type target_ip,
|
||||
@@ -596,7 +601,7 @@ int connect_proxy_chain(int sock, ip_type target_ip,
|
||||
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)) {
|
||||
PDEBUG("GOTO AGAIN 1\n");
|
||||
goto again;
|
||||
}
|
||||
@@ -605,7 +610,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))
|
||||
goto error;
|
||||
break;
|
||||
|
||||
@@ -643,7 +648,7 @@ int connect_proxy_chain(int sock, ip_type target_ip,
|
||||
/* Try from the beginning to where we started */
|
||||
offset = 0;
|
||||
continue;
|
||||
} else if(SUCCESS != chain_step(ns, p1, p2)) {
|
||||
} else if(SUCCESS != chain_step(&ns, p1, p2)) {
|
||||
PDEBUG("GOTO AGAIN 1\n");
|
||||
goto again;
|
||||
} else
|
||||
@@ -655,7 +660,7 @@ int connect_proxy_chain(int sock, ip_type target_ip,
|
||||
p3->port = target_port;
|
||||
proxychains_proxy_offset = offset+1;
|
||||
PDEBUG("pd_offset = %d, curr_len = %d\n", proxychains_proxy_offset, curr_len);
|
||||
if(SUCCESS != chain_step(ns, p1, p3))
|
||||
if(SUCCESS != chain_step(&ns, p1, p3))
|
||||
goto error;
|
||||
break;
|
||||
|
||||
@@ -673,7 +678,7 @@ int connect_proxy_chain(int sock, ip_type target_ip,
|
||||
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)) {
|
||||
PDEBUG("chain_step failed\n");
|
||||
goto error_strict;
|
||||
}
|
||||
@@ -682,7 +687,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))
|
||||
goto error;
|
||||
break;
|
||||
|
||||
@@ -698,7 +703,7 @@ int connect_proxy_chain(int sock, ip_type target_ip,
|
||||
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)) {
|
||||
PDEBUG("GOTO AGAIN 2\n");
|
||||
goto again;
|
||||
}
|
||||
@@ -707,7 +712,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))
|
||||
goto error;
|
||||
|
||||
}
|
||||
@@ -824,7 +829,8 @@ struct hostent* proxy_gethostbyname_old(const char *name)
|
||||
close(pipe_fd[0]);
|
||||
got_buff:
|
||||
l = strlen(buff);
|
||||
if(l && buff[l-1] == '\n') buff[l-1] = 0;
|
||||
if (!l) goto err_dns;
|
||||
if (buff[l-1] == '\n') buff[l-1] = 0;
|
||||
addr = inet_addr(buff);
|
||||
if (addr == (in_addr_t) (-1))
|
||||
goto err_dns;
|
||||
@@ -839,8 +845,7 @@ got_buff:
|
||||
name, inet_ntoa(*(struct in_addr*)&addr));
|
||||
return &hostent_space;
|
||||
err_dns:
|
||||
proxychains_write_log("|DNS-response|: %s does not exist\n", name);
|
||||
perror("err_dns");
|
||||
proxychains_write_log("|DNS-response|: %s lookup error\n", name);
|
||||
err:
|
||||
return NULL;
|
||||
}
|
||||
@@ -969,12 +974,13 @@ int proxy_getaddrinfo(const char *node, const char *service, const struct addrin
|
||||
node?node:"",service?service:"",hints?(int)hints->ai_flags:0);
|
||||
|
||||
space = calloc(1, sizeof(struct addrinfo_data));
|
||||
if(!space) goto err1;
|
||||
if(!space) return EAI_MEMORY;
|
||||
|
||||
if(node && !my_inet_aton(node, space)) {
|
||||
/* some folks (nmap) use getaddrinfo() with AI_NUMERICHOST to check whether a string
|
||||
containing a numeric ip was passed. we must return failure in that case. */
|
||||
if(hints && (hints->ai_flags & AI_NUMERICHOST)) {
|
||||
err_nn:
|
||||
free(space);
|
||||
return EAI_NONAME;
|
||||
}
|
||||
@@ -987,13 +993,13 @@ int proxy_getaddrinfo(const char *node, const char *service, const struct addrin
|
||||
memcpy(&((struct sockaddr_in *) &space->sockaddr_space)->sin_addr,
|
||||
*(hp->h_addr_list), sizeof(in_addr_t));
|
||||
else
|
||||
goto err2;
|
||||
goto err_nn;
|
||||
} else if(node) {
|
||||
af = ((struct sockaddr_in *) &space->sockaddr_space)->sin_family;
|
||||
} else if(!node && !(hints->ai_flags & AI_PASSIVE)) {
|
||||
af = ((struct sockaddr_in *) &space->sockaddr_space)->sin_family = AF_INET;
|
||||
memcpy(&((struct sockaddr_in *) &space->sockaddr_space)->sin_addr,
|
||||
(char[]){127,0,0,1}, 4);
|
||||
"\177\0\0\1", 4);
|
||||
}
|
||||
if(service) mygetservbyname_r(service, NULL, &se_buf, buf, sizeof(buf), &se);
|
||||
|
||||
@@ -1026,12 +1032,5 @@ int proxy_getaddrinfo(const char *node, const char *service, const struct addrin
|
||||
#endif
|
||||
p->ai_flags = (AI_V4MAPPED | AI_ADDRCONFIG);
|
||||
}
|
||||
|
||||
goto out;
|
||||
err2:
|
||||
free(space);
|
||||
err1:
|
||||
return 1;
|
||||
out:
|
||||
return 0;
|
||||
}
|
||||
|
||||
+8
-6
@@ -24,6 +24,7 @@
|
||||
#ifndef __CORE_HEADER
|
||||
#define __CORE_HEADER
|
||||
#define MAX_LOCALNET 64
|
||||
#define MAX_REMOTENET 64
|
||||
#define MAX_DNAT 64
|
||||
|
||||
#include "ip_type.h"
|
||||
@@ -77,7 +78,7 @@ typedef struct {
|
||||
unsigned char in6_prefix;
|
||||
};
|
||||
};
|
||||
} localaddr_arg;
|
||||
} addr_arg;
|
||||
|
||||
typedef struct {
|
||||
struct in_addr orig_dst, new_dst;
|
||||
@@ -100,16 +101,17 @@ int connect_proxy_chain (int sock, ip_type target_ip, unsigned short target_port
|
||||
void proxychains_write_log(char *str, ...);
|
||||
|
||||
typedef int (*close_t)(int);
|
||||
typedef int (*close_range_t)(unsigned, unsigned, int);
|
||||
typedef int (*connect_t)(int, const struct sockaddr *, socklen_t);
|
||||
typedef struct hostent* (*gethostbyname_t)(const char *);
|
||||
typedef int (*freeaddrinfo_t)(struct addrinfo *);
|
||||
typedef void (*freeaddrinfo_t)(struct addrinfo *);
|
||||
typedef struct hostent *(*gethostbyaddr_t) (const void *, socklen_t, int);
|
||||
|
||||
typedef int (*getaddrinfo_t)(const char *, const char *, const struct addrinfo *,
|
||||
typedef int (*getaddrinfo_t)(const char *, const char *, const struct addrinfo *,
|
||||
struct addrinfo **);
|
||||
|
||||
typedef int (*getnameinfo_t) (const struct sockaddr *, socklen_t, char *,
|
||||
socklen_t, char *, socklen_t, int);
|
||||
typedef int (*getnameinfo_t) (const struct sockaddr *, socklen_t, char *,
|
||||
GN_NODELEN_T, char *, GN_SERVLEN_T, GN_FLAGS_T);
|
||||
|
||||
typedef ssize_t (*sendto_t) (int sockfd, const void *buf, size_t len, int flags,
|
||||
const struct sockaddr *dest_addr, socklen_t addrlen);
|
||||
@@ -133,7 +135,7 @@ struct gethostbyname_data {
|
||||
struct hostent* proxy_gethostbyname(const char *name, struct gethostbyname_data *data);
|
||||
struct hostent* proxy_gethostbyname_old(const char *name);
|
||||
|
||||
int proxy_getaddrinfo(const char *node, const char *service,
|
||||
int proxy_getaddrinfo(const char *node, const char *service,
|
||||
const struct addrinfo *hints, struct addrinfo **res);
|
||||
void proxy_freeaddrinfo(struct addrinfo *res);
|
||||
|
||||
|
||||
+209
-23
@@ -56,6 +56,7 @@ connect_t true___xnet_connect;
|
||||
#endif
|
||||
|
||||
close_t true_close;
|
||||
close_range_t true_close_range;
|
||||
connect_t true_connect;
|
||||
gethostbyname_t true_gethostbyname;
|
||||
getaddrinfo_t true_getaddrinfo;
|
||||
@@ -74,8 +75,10 @@ int proxychains_got_chain_data = 0;
|
||||
unsigned int proxychains_max_chain = 1;
|
||||
int proxychains_quiet_mode = 0;
|
||||
enum dns_lookup_flavor proxychains_resolver = DNSLF_LIBC;
|
||||
localaddr_arg localnet_addr[MAX_LOCALNET];
|
||||
addr_arg localnet_addr[MAX_LOCALNET];
|
||||
addr_arg remotenet_addr[MAX_REMOTENET];
|
||||
size_t num_localnet_addr = 0;
|
||||
size_t num_remotenet_addr = 0;
|
||||
dnat_arg dnats[MAX_DNAT];
|
||||
size_t num_dnats = 0;
|
||||
unsigned int remote_dns_subnet = 224;
|
||||
@@ -86,13 +89,14 @@ static int init_l = 0;
|
||||
|
||||
static void get_chain_data(proxy_data * pd, unsigned int *proxy_count, chain_type * ct);
|
||||
|
||||
static void* load_sym(char* symname, void* proxyfunc) {
|
||||
|
||||
static void* load_sym(char* symname, void* proxyfunc, int is_mandatory) {
|
||||
void *funcptr = dlsym(RTLD_NEXT, symname);
|
||||
|
||||
if(!funcptr) {
|
||||
if(is_mandatory && !funcptr) {
|
||||
fprintf(stderr, "Cannot load symbol '%s' %s\n", symname, dlerror());
|
||||
exit(1);
|
||||
} else if (!funcptr) {
|
||||
return funcptr;
|
||||
} else {
|
||||
PDEBUG("loaded symbol '%s'" " real addr %p wrapped addr %p\n", symname, funcptr, proxyfunc);
|
||||
}
|
||||
@@ -103,17 +107,22 @@ static void* load_sym(char* symname, void* proxyfunc) {
|
||||
return funcptr;
|
||||
}
|
||||
|
||||
#define INIT() init_lib_wrapper(__FUNCTION__)
|
||||
|
||||
|
||||
#include "allocator_thread.h"
|
||||
|
||||
const char *proxychains_get_version(void);
|
||||
|
||||
static void setup_hooks(void);
|
||||
|
||||
typedef struct {
|
||||
unsigned int first, last, flags;
|
||||
} close_range_args_t;
|
||||
|
||||
/* If there is some `close` or `close_range` system call before do_init,
|
||||
we buffer it, and actually execute them in do_init. */
|
||||
static int close_fds[16];
|
||||
static int close_fds_cnt = 0;
|
||||
static close_range_args_t close_range_buffer[16];
|
||||
static int close_range_buffer_cnt = 0;
|
||||
|
||||
static unsigned get_rand_seed(void) {
|
||||
#ifdef HAVE_CLOCK_GETTIME
|
||||
@@ -126,18 +135,28 @@ static unsigned get_rand_seed(void) {
|
||||
}
|
||||
|
||||
static void do_init(void) {
|
||||
char *env;
|
||||
|
||||
srand(get_rand_seed());
|
||||
core_initialize();
|
||||
|
||||
/* read the config file */
|
||||
get_chain_data(proxychains_pd, &proxychains_proxy_count, &proxychains_ct);
|
||||
DUMP_PROXY_CHAIN(proxychains_pd, proxychains_proxy_count);
|
||||
env = getenv(PROXYCHAINS_QUIET_MODE_ENV_VAR);
|
||||
if(env && *env == '1')
|
||||
proxychains_quiet_mode = 1;
|
||||
|
||||
proxychains_write_log(LOG_PREFIX "DLL init: proxychains-ng %s\n", proxychains_get_version());
|
||||
|
||||
setup_hooks();
|
||||
|
||||
/* read the config file */
|
||||
get_chain_data(proxychains_pd, &proxychains_proxy_count, &proxychains_ct);
|
||||
DUMP_PROXY_CHAIN(proxychains_pd, proxychains_proxy_count);
|
||||
|
||||
while(close_fds_cnt) true_close(close_fds[--close_fds_cnt]);
|
||||
while(close_range_buffer_cnt) {
|
||||
int i = --close_range_buffer_cnt;
|
||||
true_close_range(close_range_buffer[i].first, close_range_buffer[i].last, close_range_buffer[i].flags);
|
||||
}
|
||||
init_l = 1;
|
||||
|
||||
rdns_init(proxychains_resolver);
|
||||
@@ -151,16 +170,19 @@ static void init_lib_wrapper(const char* caller) {
|
||||
pthread_once(&init_once, do_init);
|
||||
}
|
||||
|
||||
/* if we use gcc >= 3, we can instruct the dynamic loader
|
||||
/* if we use gcc >= 3, we can instruct the dynamic loader
|
||||
* to call init_lib at link time. otherwise it gets loaded
|
||||
* lazily, which has the disadvantage that there's a potential
|
||||
* race condition if 2 threads call it before init_l is set
|
||||
* race condition if 2 threads call it before init_l is set
|
||||
* and PTHREAD support was disabled */
|
||||
#if __GNUC__ > 2
|
||||
#if __GNUC__+0 > 2
|
||||
__attribute__((constructor))
|
||||
static void gcc_init(void) {
|
||||
INIT();
|
||||
init_lib_wrapper(__FUNCTION__);
|
||||
}
|
||||
#define INIT() do {} while(0)
|
||||
#else
|
||||
#define INIT() init_lib_wrapper(__FUNCTION__)
|
||||
#endif
|
||||
|
||||
|
||||
@@ -271,6 +293,7 @@ static void get_chain_data(proxy_data * pd, unsigned int *proxy_count, chain_typ
|
||||
char buf[1024], type[1024], host[1024], user[1024];
|
||||
char *buff, *env, *p;
|
||||
char local_addr_port[64], local_addr[64], local_netmask[32];
|
||||
char remote_addr_port[64], remote_addr[64], remote_netmask[32];
|
||||
char dnat_orig_addr_port[32], dnat_new_addr_port[32];
|
||||
char dnat_orig_addr[32], dnat_orig_port[32], dnat_new_addr[32], dnat_new_port[32];
|
||||
char rdnsd_addr[32], rdnsd_port[8];
|
||||
@@ -293,10 +316,6 @@ static void get_chain_data(proxy_data * pd, unsigned int *proxy_count, chain_typ
|
||||
exit(1);
|
||||
}
|
||||
|
||||
env = getenv(PROXYCHAINS_QUIET_MODE_ENV_VAR);
|
||||
if(env && *env == '1')
|
||||
proxychains_quiet_mode = 1;
|
||||
|
||||
while(fgets(buf, sizeof(buf), file)) {
|
||||
buff = buf;
|
||||
/* remove leading whitespace */
|
||||
@@ -335,7 +354,7 @@ static void get_chain_data(proxy_data * pd, unsigned int *proxy_count, chain_typ
|
||||
if(*ct == STRICT_TYPE && proxychains_resolver >= DNSLF_RDNS_START && count > 0) {
|
||||
/* we can allow dns hostnames for all but the first proxy in the list if chaintype is strict, as remote lookup can be done */
|
||||
rdns_init(proxychains_resolver);
|
||||
ip_type4 internal_ip = at_get_ip_for_host(host, strlen(host));
|
||||
ip_type4 internal_ip = rdns_get_ip_for_host(host, strlen(host));
|
||||
pd[count].ip.is_v6 = 0;
|
||||
host_ip->addr.v4 = internal_ip;
|
||||
if(internal_ip.as_int == IPT4_INVALID.as_int)
|
||||
@@ -459,6 +478,81 @@ inv_host:
|
||||
} else {
|
||||
fprintf(stderr, "# of localnet exceed %d.\n", MAX_LOCALNET);
|
||||
}
|
||||
} else if(STR_STARTSWITH(buff, "remotenet")) {
|
||||
char colon, extra, right_bracket[2];
|
||||
unsigned short remote_port = 0, remote_prefix;
|
||||
int remote_family, n, valid;
|
||||
if(sscanf(buff, "%s %53[^/]/%15s%c", user, remote_addr_port, remote_netmask, &extra) != 3) {
|
||||
fprintf(stderr, "remotenet format error");
|
||||
exit(1);
|
||||
}
|
||||
p = strchr(remote_addr_port, ':');
|
||||
if(!p || p == strrchr(remote_addr_port, ':')) {
|
||||
remote_family = AF_INET;
|
||||
n = sscanf(remote_addr_port, "%15[^:]%c%5hu%c", remote_addr, &colon, &remote_port, &extra);
|
||||
valid = n == 1 || (n == 3 && colon == ':');
|
||||
} else if(remote_addr_port[0] == '[') {
|
||||
remote_family = AF_INET6;
|
||||
n = sscanf(remote_addr_port, "[%45[^][]%1[]]%c%5hu%c", remote_addr, right_bracket, &colon, &remote_port, &extra);
|
||||
valid = n == 2 || (n == 4 && colon == ':');
|
||||
} else {
|
||||
remote_family = AF_INET6;
|
||||
valid = sscanf(remote_addr_port, "%45[^][]%c", remote_addr, &extra) == 1;
|
||||
}
|
||||
if(!valid) {
|
||||
fprintf(stderr, "remotenet address or port error\n");
|
||||
exit(1);
|
||||
}
|
||||
if(remote_port) {
|
||||
PDEBUG("added remotenet: netaddr=%s, port=%u, netmask=%s\n",
|
||||
remote_addr, remote_port, remote_netmask);
|
||||
} else {
|
||||
PDEBUG("added remotenet: netaddr=%s, netmask=%s\n",
|
||||
remote_addr, remote_netmask);
|
||||
}
|
||||
if(num_remotenet_addr < MAX_REMOTENET) {
|
||||
remotenet_addr[num_remotenet_addr].family = remote_family;
|
||||
remotenet_addr[num_remotenet_addr].port = remote_port;
|
||||
valid = 0;
|
||||
if (remote_family == AF_INET) {
|
||||
valid =
|
||||
inet_pton(remote_family, remote_addr,
|
||||
&remotenet_addr[num_remotenet_addr].in_addr) > 0;
|
||||
} else if(remote_family == AF_INET6) {
|
||||
valid =
|
||||
inet_pton(remote_family, remote_addr,
|
||||
&remotenet_addr[num_remotenet_addr].in6_addr) > 0;
|
||||
}
|
||||
if(!valid) {
|
||||
fprintf(stderr, "remotenet address error\n");
|
||||
exit(1);
|
||||
}
|
||||
if(remote_family == AF_INET && strchr(remote_netmask, '.')) {
|
||||
valid =
|
||||
inet_pton(remote_family, remote_netmask,
|
||||
&remotenet_addr[num_remotenet_addr].in_mask) > 0;
|
||||
} else {
|
||||
valid = sscanf(remote_netmask, "%hu%c", &remote_prefix, &extra) == 1;
|
||||
if (valid) {
|
||||
if(remote_family == AF_INET && remote_prefix <= 32) {
|
||||
remotenet_addr[num_remotenet_addr].in_mask.s_addr =
|
||||
htonl(0xFFFFFFFFu << (32u - remote_prefix));
|
||||
} else if(remote_family == AF_INET6 && remote_prefix <= 128) {
|
||||
remotenet_addr[num_remotenet_addr].in6_prefix =
|
||||
remote_prefix;
|
||||
} else {
|
||||
valid = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!valid) {
|
||||
fprintf(stderr, "remotenet netmask error\n");
|
||||
exit(1);
|
||||
}
|
||||
++num_remotenet_addr;
|
||||
} else {
|
||||
fprintf(stderr, "# of remotenet exceed %d.\n", MAX_REMOTENET);
|
||||
}
|
||||
} else if(STR_STARTSWITH(buff, "chain_len")) {
|
||||
char *pc;
|
||||
int len;
|
||||
@@ -587,6 +681,69 @@ static int is_v4inv6(const struct in6_addr *a) {
|
||||
return !memcmp(a->s6_addr, "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12);
|
||||
}
|
||||
|
||||
static void intsort(int *a, int n) {
|
||||
int i, j, s;
|
||||
for(i=0; i<n; ++i)
|
||||
for(j=i+1; j<n; ++j)
|
||||
if(a[j] < a[i]) {
|
||||
s = a[i];
|
||||
a[i] = a[j];
|
||||
a[j] = s;
|
||||
}
|
||||
}
|
||||
|
||||
/* Warning: Linux manual says the third arg is `unsigned int`, but unistd.h says `int`. */
|
||||
HOOKFUNC(int, close_range, unsigned first, unsigned last, int flags) {
|
||||
if(true_close_range == NULL) {
|
||||
fprintf(stderr, "Calling close_range, but this platform does not provide this system call. ");
|
||||
return -1;
|
||||
}
|
||||
if(!init_l) {
|
||||
/* push back to cache, and delay the execution. */
|
||||
if(close_range_buffer_cnt >= (sizeof close_range_buffer / sizeof close_range_buffer[0])) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
int i = close_range_buffer_cnt++;
|
||||
close_range_buffer[i].first = first;
|
||||
close_range_buffer[i].last = last;
|
||||
close_range_buffer[i].flags = flags;
|
||||
return errno = 0;
|
||||
}
|
||||
if(proxychains_resolver != DNSLF_RDNS_THREAD) return true_close_range(first, last, flags);
|
||||
|
||||
/* prevent rude programs (like ssh) from closing our pipes */
|
||||
int res = 0, uerrno = 0, i;
|
||||
int protected_fds[] = {req_pipefd[0], req_pipefd[1], resp_pipefd[0], resp_pipefd[1]};
|
||||
intsort(protected_fds, 4);
|
||||
/* We are skipping protected_fds while calling true_close_range()
|
||||
* If protected_fds cut the range into some sub-ranges, we close sub-ranges BEFORE cut point in the loop.
|
||||
* [first, cut1-1] , [cut1+1, cut2-1] , [cut2+1, cut3-1]
|
||||
* Finally, we delete the remaining sub-range, outside the loop. [cut3+1, tail]
|
||||
*/
|
||||
int next_fd_to_close = first;
|
||||
for(i = 0; i < 4; ++i) {
|
||||
if(protected_fds[i] < first || protected_fds[i] > last)
|
||||
continue;
|
||||
int prev = (i == 0 || protected_fds[i-1] < first) ? first : protected_fds[i-1]+1;
|
||||
if(prev != protected_fds[i]) {
|
||||
if(-1 == true_close_range(prev, protected_fds[i]-1, flags)) {
|
||||
res = -1;
|
||||
uerrno = errno;
|
||||
}
|
||||
}
|
||||
next_fd_to_close = protected_fds[i]+1;
|
||||
}
|
||||
if(next_fd_to_close <= last) {
|
||||
if(-1 == true_close_range(next_fd_to_close, last, flags)) {
|
||||
res = -1;
|
||||
uerrno = errno;
|
||||
}
|
||||
}
|
||||
errno = uerrno;
|
||||
return res;
|
||||
}
|
||||
|
||||
HOOKFUNC(int, connect, int sock, const struct sockaddr *addr, unsigned int len) {
|
||||
INIT();
|
||||
PFUNC();
|
||||
@@ -670,6 +827,31 @@ HOOKFUNC(int, connect, int sock, const struct sockaddr *addr, unsigned int len)
|
||||
return true_connect(sock, addr, len);
|
||||
}
|
||||
|
||||
int remote_connect = (remote_dns_connect||num_remotenet_addr==0);
|
||||
for(i = 0; i < num_remotenet_addr && !remote_connect; i++) {
|
||||
if (remotenet_addr[i].port && remotenet_addr[i].port != port)
|
||||
continue;
|
||||
if (remotenet_addr[i].family != (v6 ? AF_INET6 : AF_INET))
|
||||
continue;
|
||||
if (v6) {
|
||||
size_t prefix_bytes = remotenet_addr[i].in6_prefix / CHAR_BIT;
|
||||
size_t prefix_bits = remotenet_addr[i].in6_prefix % CHAR_BIT;
|
||||
if (prefix_bytes && memcmp(p_addr_in6->s6_addr, remotenet_addr[i].in6_addr.s6_addr, prefix_bytes) != 0)
|
||||
continue;
|
||||
if (prefix_bits && (p_addr_in6->s6_addr[prefix_bytes] ^ remotenet_addr[i].in6_addr.s6_addr[prefix_bytes]) >> (CHAR_BIT - prefix_bits))
|
||||
continue;
|
||||
} else {
|
||||
if((p_addr_in->s_addr ^ remotenet_addr[i].in_addr.s_addr) & remotenet_addr[i].in_mask.s_addr)
|
||||
continue;
|
||||
}
|
||||
remote_connect = 1;
|
||||
}
|
||||
|
||||
if( !remote_connect ) {
|
||||
PDEBUG("accessing non-remotenet using true_connect\n");
|
||||
return true_connect(sock, addr, len);
|
||||
}
|
||||
|
||||
flags = fcntl(sock, F_GETFL, 0);
|
||||
if(flags & O_NONBLOCK)
|
||||
fcntl(sock, F_SETFL, !O_NONBLOCK);
|
||||
@@ -688,7 +870,7 @@ HOOKFUNC(int, connect, int sock, const struct sockaddr *addr, unsigned int len)
|
||||
}
|
||||
|
||||
#ifdef IS_SOLARIS
|
||||
HOOKFUNC(int, __xnet_connect, int sock, const struct sockaddr *addr, unsigned int len)
|
||||
HOOKFUNC(int, __xnet_connect, int sock, const struct sockaddr *addr, unsigned int len) {
|
||||
return connect(sock, addr, len);
|
||||
}
|
||||
#endif
|
||||
@@ -729,8 +911,8 @@ HOOKFUNC(void, freeaddrinfo, struct addrinfo *res) {
|
||||
}
|
||||
|
||||
HOOKFUNC(int, getnameinfo, const struct sockaddr *sa, socklen_t salen,
|
||||
char *host, socklen_t hostlen, char *serv,
|
||||
socklen_t servlen, int flags)
|
||||
char *host, GN_NODELEN_T hostlen, char *serv,
|
||||
GN_SERVLEN_T servlen, GN_FLAGS_T flags)
|
||||
{
|
||||
INIT();
|
||||
PFUNC();
|
||||
@@ -825,8 +1007,11 @@ HOOKFUNC(ssize_t, sendto, int sockfd, const void *buf, size_t len, int flags,
|
||||
|
||||
#ifdef MONTEREY_HOOKING
|
||||
#define SETUP_SYM(X) do { if (! true_ ## X ) true_ ## X = &X; } while(0)
|
||||
#define SETUP_SYM_OPTIONAL(X)
|
||||
#else
|
||||
#define SETUP_SYM(X) do { if (! true_ ## X ) true_ ## X = load_sym( # X, X ); } while(0)
|
||||
#define SETUP_SYM_IMPL(X, IS_MANDATORY) do { if (! true_ ## X ) true_ ## X = load_sym( # X, X, IS_MANDATORY ); } while(0)
|
||||
#define SETUP_SYM(X) SETUP_SYM_IMPL(X, 1)
|
||||
#define SETUP_SYM_OPTIONAL(X) SETUP_SYM_IMPL(X, 0)
|
||||
#endif
|
||||
|
||||
static void setup_hooks(void) {
|
||||
@@ -841,6 +1026,7 @@ static void setup_hooks(void) {
|
||||
SETUP_SYM(__xnet_connect);
|
||||
#endif
|
||||
SETUP_SYM(close);
|
||||
SETUP_SYM_OPTIONAL(close_range);
|
||||
}
|
||||
|
||||
#ifdef MONTEREY_HOOKING
|
||||
|
||||
+9
-5
@@ -135,16 +135,20 @@ int main(int argc, char *argv[]) {
|
||||
if(!quiet)
|
||||
fprintf(stderr, LOG_PREFIX "preloading %s/%s\n", prefix, dll_name);
|
||||
|
||||
#if defined(IS_MAC) || defined(IS_OPENBSD)
|
||||
#define LD_PRELOAD_SEP ":"
|
||||
#else
|
||||
/* Dynlinkers for Linux and most BSDs seem to support space
|
||||
as LD_PRELOAD separator, with colon added only recently.
|
||||
We use the old syntax for maximum compat */
|
||||
#define LD_PRELOAD_SEP " "
|
||||
#endif
|
||||
|
||||
#ifdef IS_MAC
|
||||
putenv("DYLD_FORCE_FLAT_NAMESPACE=1");
|
||||
#define LD_PRELOAD_ENV "DYLD_INSERT_LIBRARIES"
|
||||
#define LD_PRELOAD_SEP ":"
|
||||
#else
|
||||
#define LD_PRELOAD_ENV "LD_PRELOAD"
|
||||
/* all historic implementations of BSD and linux dynlinkers seem to support
|
||||
space as LD_PRELOAD separator, with colon added only recently.
|
||||
we use the old syntax for maximum compat */
|
||||
#define LD_PRELOAD_SEP " "
|
||||
#endif
|
||||
char *old_val = getenv(LD_PRELOAD_ENV);
|
||||
snprintf(buf, sizeof(buf), LD_PRELOAD_ENV "=%s/%s%s%s",
|
||||
|
||||
+20
-6
@@ -79,12 +79,12 @@ proxy_dns
|
||||
# we use the reserved 224.x.x.x range by default,
|
||||
# if the proxified app does a DNS request, we will return an IP from that range.
|
||||
# on further accesses to this ip we will send the saved DNS name to the proxy.
|
||||
# in case some control-freak app checks the returned ip, and denies to
|
||||
# in case some control-freak app checks the returned ip, and denies to
|
||||
# connect, you can use another subnet, e.g. 10.x.x.x or 127.x.x.x.
|
||||
# of course you should make sure that the proxified app does not need
|
||||
# *real* access to this subnet.
|
||||
# *real* access to this subnet.
|
||||
# i.e. dont use the same subnet then in the localnet section
|
||||
#remote_dns_subnet 127
|
||||
#remote_dns_subnet 127
|
||||
#remote_dns_subnet 10
|
||||
remote_dns_subnet 224
|
||||
|
||||
@@ -109,7 +109,7 @@ tcp_connect_time_out 8000
|
||||
|
||||
## RFC6890 Loopback address range
|
||||
## if you enable this, you have to make sure remote_dns_subnet is not 127
|
||||
## you'll need to enable it if you want to use an application that
|
||||
## you'll need to enable it if you want to use an application that
|
||||
## connects to localhost.
|
||||
# localnet 127.0.0.0/255.0.0.0
|
||||
# localnet ::1/128
|
||||
@@ -119,6 +119,20 @@ tcp_connect_time_out 8000
|
||||
# localnet 172.16.0.0/255.240.0.0
|
||||
# localnet 192.168.0.0/255.255.0.0
|
||||
|
||||
### Examples for remotenet that will use a proxy to connect
|
||||
## only remotenet ranges except localnet ranges will use a proxy to connect.
|
||||
## default(means all connections except localnet ranges will use a proxy):
|
||||
## remotenet ::/0
|
||||
## remotenet 0.0.0.0/0.0.0.0
|
||||
|
||||
## Connections to 31.13.94.36 with port 80 and 443 will use a proxy:
|
||||
# remotenet 31.13.94.36:80/255.255.255.255
|
||||
# remotenet 31.13.94.36:443/255.255.255.255
|
||||
|
||||
## Connections to anywhere with port 25 will use a proxy:
|
||||
# remotenet 0.0.0.0:25/0.0.0.0
|
||||
# remotenet [::]:25/0
|
||||
|
||||
### Examples for dnat
|
||||
## Trying to proxy connections to destinations which are dnatted,
|
||||
## will result in proxying connections to the new given destinations.
|
||||
@@ -147,8 +161,8 @@ tcp_connect_time_out 8000
|
||||
# socks5 192.168.67.78 1080 lamer secret
|
||||
# http 192.168.89.3 8080 justu hidden
|
||||
# socks4 192.168.1.49 1080
|
||||
# http 192.168.39.93 8080
|
||||
#
|
||||
# http 192.168.39.93 8080
|
||||
#
|
||||
#
|
||||
# proxy types: http, socks4, socks5, raw
|
||||
# * raw: The traffic is simply forwarded to the proxy without modification.
|
||||
|
||||
Reference in New Issue
Block a user