1
0
mirror of https://github.com/rofl0r/proxychains-ng synced 2026-05-14 01:12:34 +08:00

Compare commits

...

46 Commits

15 changed files with 521 additions and 158 deletions
+1
View File
@@ -1,4 +1,5 @@
proxychains4 proxychains4
proxychains4-daemon
*.bz2 *.bz2
*.xz *.xz
*.o *.o
+14 -9
View File
@@ -11,7 +11,8 @@ bindir = $(exec_prefix)/bin
prefix = /usr/local/ prefix = /usr/local/
includedir = $(prefix)/include includedir = $(prefix)/include
libdir = $(prefix)/lib libdir = $(prefix)/lib
sysconfdir=$(prefix)/etc sysconfdir = $(prefix)/etc
zshcompletiondir = $(prefix)/share/zsh/site-functions
OBJS = src/common.o src/main.o OBJS = src/common.o src/main.o
@@ -19,7 +20,7 @@ DOBJS = src/daemon/hsearch.o \
src/daemon/sblist.o src/daemon/sblist_delete.o \ src/daemon/sblist.o src/daemon/sblist_delete.o \
src/daemon/daemon.o src/daemon/udpserver.o src/daemon/daemon.o src/daemon/udpserver.o
LOBJS = src/nameinfo.o src/version.o \ LOBJS = src/version.o \
src/core.o src/common.o src/libproxychains.o \ src/core.o src/common.o src/libproxychains.o \
src/allocator_thread.o src/rdns.o \ src/allocator_thread.o src/rdns.o \
src/hostsreader.o src/hash.o src/debug.o src/hostsreader.o src/hash.o src/debug.o
@@ -29,8 +30,7 @@ GENH = src/version.h
CFLAGS += -Wall -O0 -g -std=c99 -D_GNU_SOURCE -pipe CFLAGS += -Wall -O0 -g -std=c99 -D_GNU_SOURCE -pipe
NO_AS_NEEDED = -Wl,--no-as-needed NO_AS_NEEDED = -Wl,--no-as-needed
LIBDL = -ldl LDFLAGS = -fPIC $(NO_AS_NEEDED) $(LIBDL) $(PTHREAD)
LDFLAGS = -fPIC $(NO_AS_NEEDED) $(LIBDL) -lpthread
INC = INC =
PIC = -fPIC PIC = -fPIC
AR = $(CROSS_COMPILE)ar AR = $(CROSS_COMPILE)ar
@@ -49,6 +49,7 @@ PXCHAINS = proxychains4
PXCHAINS_D = proxychains4-daemon PXCHAINS_D = proxychains4-daemon
ALL_TOOLS = $(PXCHAINS) $(PXCHAINS_D) ALL_TOOLS = $(PXCHAINS) $(PXCHAINS_D)
ALL_CONFIGS = src/proxychains.conf ALL_CONFIGS = src/proxychains.conf
ZSH_COMPLETION = completions/zsh/_proxychains4
-include config.mak -include config.mak
@@ -69,9 +70,13 @@ $(DESTDIR)$(libdir)/%: %
$(DESTDIR)$(sysconfdir)/%: src/% $(DESTDIR)$(sysconfdir)/%: src/%
$(INSTALL) -D -m 644 $< $@ $(INSTALL) -D -m 644 $< $@
$(DESTDIR)$(zshcompletiondir)/%: completions/zsh/%
$(INSTALL) -D -m 644 $< $@
install-libs: $(ALL_LIBS:%=$(DESTDIR)$(libdir)/%) install-libs: $(ALL_LIBS:%=$(DESTDIR)$(libdir)/%)
install-tools: $(ALL_TOOLS:%=$(DESTDIR)$(bindir)/%) install-tools: $(ALL_TOOLS:%=$(DESTDIR)$(bindir)/%)
install-config: $(ALL_CONFIGS:src/%=$(DESTDIR)$(sysconfdir)/%) install-config: $(ALL_CONFIGS:src/%=$(DESTDIR)$(sysconfdir)/%)
install-zsh-completion: $(ZSH_COMPLETION:completions/zsh/%=$(DESTDIR)$(zshcompletiondir)/%)
clean: clean:
rm -f $(ALL_LIBS) rm -f $(ALL_LIBS)
@@ -88,14 +93,14 @@ src/version.o: src/version.h
$(CC) $(CPPFLAGS) $(CFLAGS) $(CFLAGS_MAIN) $(INC) $(PIC) -c -o $@ $< $(CC) $(CPPFLAGS) $(CFLAGS) $(CFLAGS_MAIN) $(INC) $(PIC) -c -o $@ $<
$(LDSO_PATHNAME): $(LOBJS) $(LDSO_PATHNAME): $(LOBJS)
$(CC) $(LDFLAGS) $(LD_SET_SONAME)$(LDSO_PATHNAME) $(USER_LDFLAGS) \ $(CC) $(LDFLAGS) $(FAT_LDFLAGS) $(LD_SET_SONAME)$(LDSO_PATHNAME) \
-shared -o $@ $^ $(SOCKET_LIBS) $(USER_LDFLAGS) -shared -o $@ $^ $(SOCKET_LIBS)
$(PXCHAINS): $(OBJS) $(PXCHAINS): $(OBJS)
$(CC) $^ $(USER_LDFLAGS) $(LIBDL) -o $@ $(CC) $^ $(FAT_BIN_LDFLAGS) $(USER_LDFLAGS) $(LIBDL) -o $@
$(PXCHAINS_D): $(DOBJS) $(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
+41 -2
View File
@@ -1,4 +1,4 @@
ProxyChains-NG ver 4.14 README ProxyChains-NG ver 4.17 README
============================= =============================
ProxyChains is a UNIX program, that hooks network-related libc functions ProxyChains is a UNIX program, that hooks network-related libc functions
@@ -52,6 +52,36 @@ ProxyChains-NG ver 4.14 README
Changelog: 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
- support for new DYLD hooking method for OSX Monterey
- netbsd compilation fix
- support IPv6 localnets
- more user-friendly error message when execvp fails
- proxy_getaddrinfo(): fill in ai_socktype if requested
Version 4.15
- fix configure script for buggy binutils version
- initialize rand_seed with nano-second granularity
- add support for numeric ipv6 in getaddrinfo
- fix bug in getaddrinfo when node is null and !passive
- add dnat feature
- add raw proxy type
- add haiku support
- add proxy_dns_old to emulate proxychains 3.1 behaviour
- add new proxy_dns_daemon feature (experimental)
- various other fixes
Version 4.14 Version 4.14
- allow alternative proto://user:pass@ip:port syntax for proxylist - allow alternative proto://user:pass@ip:port syntax for proxylist
- fix endless loop in round robin mode when all proxies are down (#147) - fix endless loop in round robin mode when all proxies are down (#147)
@@ -233,10 +263,19 @@ Known Problems:
there are unconfirmed reports that it works as root though. there are unconfirmed reports that it works as root though.
musl libc is unaffected from the bug. musl libc is unaffected from the bug.
Useful links
------------
the following sites may prove useful to check for leaks:
https://ipfighter.com/
https://browserleaks.com/webrtc
https://dnsleaktest.com
http://check.torproject.org - tor specific
http://ifconfig.me - can be used via curl
http://ifconfig.io/
Community: Community:
---------- ----------
#proxychains on irc.freenode.net #proxychains on irc.libera.chat
Donations: Donations:
---------- ----------
+1 -1
View File
@@ -1 +1 @@
4.14 4.17
+8
View File
@@ -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'
Vendored
+94 -8
View File
@@ -19,18 +19,29 @@ check_compile() {
printf "checking %s ... " "$1" printf "checking %s ... " "$1"
printf "$3" > "$tmpc" printf "$3" > "$tmpc"
local res=0 local res=0
$CC $OUR_CPPFLAGS $CPPFLAGS $2 $CFLAGS "$tmpc" -o /dev/null >/dev/null 2>&1 \ $CC $OUR_CPPFLAGS $CPPFLAGS $2 $CFLAGS "$tmpc" -o "$tmpc".out >/dev/null 2>&1 \
|| res=1 || res=1
test x$res = x0 && \ test x$res = x0 && \
{ printf "yes\n" ; test x"$2" = x || OUR_CPPFLAGS="$OUR_CPPFLAGS $2" ; } \ { printf "yes\n" ; test x"$2" = x || OUR_CPPFLAGS="$OUR_CPPFLAGS $2" ; } \
|| printf "no\n" || printf "no\n"
rm -f "$tmpc".out
return $res return $res
} }
get_define() {
$CC $OUR_CPPFLAGS $CPPFLAGS $CFLAGS -dM -E - </dev/null | grep "$1"
}
get_define_stripped() {
local output=$(get_define "$1")
test "$?" = 0 || return 1
printf "%s\n" "$output" | sed 's/^.* .* //'
}
check_define() { check_define() {
printf "checking whether \$CC defines %s ... " "$1" printf "checking whether \$CC defines %s ... " "$1"
local res=1 local res=1
$CC $OUR_CPPFLAGS $CPPFLAGS $CFLAGS -dM -E - </dev/null | grep "$1" >/dev/null && res=0 get_define "$1" >/dev/null && res=0
test x$res = x0 && printf "yes\n" || printf "no\n" test x$res = x0 && printf "yes\n" || printf "no\n"
return $res return $res
} }
@@ -49,7 +60,10 @@ check_compile_run() {
check_link_silent() { check_link_silent() {
printf "$2" > "$tmpc" printf "$2" > "$tmpc"
$CC $OUR_CPPFLAGS $CPPFLAGS $1 $CFLAGS "$tmpc" -o /dev/null >/dev/null 2>&1 local res=0
$CC $OUR_CPPFLAGS $CPPFLAGS $1 $CFLAGS "$tmpc" -o "$tmpc".out >/dev/null 2>&1 || res=1
rm -f "$tmpc".out
return $res
} }
check_link() { check_link() {
@@ -70,8 +84,12 @@ usage() {
echo "--sysconfdir=/path default: $prefix/etc" echo "--sysconfdir=/path default: $prefix/etc"
echo "--ignore-cve default: no" echo "--ignore-cve default: no"
echo " if set to yes ignores CVE-2015-3887 and makes it possible" echo " if set to yes ignores CVE-2015-3887 and makes it possible"
echo " to preload from current dir (insecure)" 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 : 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" echo "--help : show this text"
exit 1 exit 1
} }
@@ -84,7 +102,11 @@ spliteq() {
} }
fat_binary= fat_binary=
fat_binary_m1=
fat_binary_m2=
ignore_cve=no ignore_cve=no
hookmethod=auto
parsearg() { parsearg() {
case "$1" in case "$1" in
--prefix=*) prefix=`spliteq $1`;; --prefix=*) prefix=`spliteq $1`;;
@@ -95,7 +117,10 @@ parsearg() {
--sysconfdir=*) sysconfdir=`spliteq $1`;; --sysconfdir=*) sysconfdir=`spliteq $1`;;
--ignore-cve) ignore_cve=1;; --ignore-cve) ignore_cve=1;;
--ignore-cve=*) ignore_cve=`spliteq $1`;; --ignore-cve=*) ignore_cve=`spliteq $1`;;
--hookmethod=*) hookmethod=`spliteq $1`;;
--fat-binary) fat_binary=1;; --fat-binary) fat_binary=1;;
--fat-binary-m1) fat_binary_m1=1;;
--fat-binary-m2) fat_binary_m2=1;;
--help) usage;; --help) usage;;
esac esac
} }
@@ -151,10 +176,29 @@ issolaris() {
} }
haiku_detected=false haiku_detected=false
ishaiku() { ishaiku() {
$haiku_detected $haiku_detected
} }
check_compile 'whether C compiler works' '' 'int main() {return 0;}' || fail 'error: install a C compiler and library' 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;}'
check_compile 'whether C compiler understands -Werror=implicit-function-declaration' '-Werror=implicit-function-declaration' '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" \ 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;}' '#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;}'
@@ -165,11 +209,19 @@ check_compile 'whether we have pipe2() and O_CLOEXEC' "-DHAVE_PIPE2" \
check_compile 'whether we have SOCK_CLOEXEC' "-DHAVE_SOCK_CLOEXEC" \ check_compile 'whether we have SOCK_CLOEXEC' "-DHAVE_SOCK_CLOEXEC" \
'#define _GNU_SOURCE\n#include <sys/socket.h>\nint main() {\nreturn socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC, 0);}' '#define _GNU_SOURCE\n#include <sys/socket.h>\nint main() {\nreturn socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC, 0);}'
check_compile 'whether we have clock_gettime' "-DHAVE_CLOCK_GETTIME" \
'#define _GNU_SOURCE\n#include <time.h>\nint main() {\nstruct timespec now;clock_gettime(CLOCK_REALTIME, &now);\nreturn now.tv_sec ^ now.tv_nsec;}'
check_define __APPLE__ && { check_define __APPLE__ && {
mac_detected=true mac_detected=true
check_define __x86_64__ && mac_64=true check_define __x86_64__ && mac_64=true
if test "$hookmethod" = auto ; then
osver=$(get_define_stripped __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ 2>/dev/null)
test "$osver" -gt $((120000 - 1)) && hookmethod=dyld
fi
} }
check_define __FreeBSD__ && bsd_detected=true check_define __FreeBSD__ && bsd_detected=true
check_define __NetBSD__ && bsd_detected=true
check_define __OpenBSD__ && { check_define __OpenBSD__ && {
bsd_detected=true bsd_detected=true
echo "CFLAGS+=-DIS_OPENBSD">>config.mak echo "CFLAGS+=-DIS_OPENBSD">>config.mak
@@ -199,7 +251,7 @@ check_link "whether we can use -Wl,--no-as-needed" "-Wl,--no-as-needed" \
LD_SONAME_FLAG= LD_SONAME_FLAG=
printf "checking what's the option to use in linker to set library name ... " printf "checking what's the option to use in linker to set library name ... "
for o in --soname -h -soname -install_name; do for o in --soname -h -soname -install_name; do
check_link_silent "-shared -Wl,$o,libconftest.so" "void test_func(int a) {}" && LD_SONAME_FLAG=$o && break check_link_silent "-shared -Wl,$o,libconftest.so" "void test_func(void) {}" && LD_SONAME_FLAG=$o && break
done done
if [ -z "$LD_SONAME_FLAG" ]; then if [ -z "$LD_SONAME_FLAG" ]; then
printf '\ncannot find an option to set library name\n' printf '\ncannot find an option to set library name\n'
@@ -208,14 +260,45 @@ fi
echo "$LD_SONAME_FLAG" echo "$LD_SONAME_FLAG"
echo "LD_SET_SONAME = -Wl,$LD_SONAME_FLAG," >> config.mak echo "LD_SET_SONAME = -Wl,$LD_SONAME_FLAG," >> config.mak
if check_link "checking whether we can use -ldl" "-ldl" \
"int main(){return 0;}" ; then
echo "LIBDL = -ldl" >> config.mak
fi
if check_link "checking whether we can use -lpthread" "-lpthread" \
"int main(){return 0;}" ; then
echo "PTHREAD = -lpthread" >> config.mak
else
check_link "checking whether we can use -pthread" "-pthread" \
"int main(){return 0;}" || fail "no pthread support detected"
echo "PTHREAD = -pthread" >> config.mak
fi
make_cmd=make make_cmd=make
if ismac ; then if ismac ; then
echo LDSO_SUFFIX=dylib>>config.mak echo LDSO_SUFFIX=dylib>>config.mak
echo MAC_CFLAGS+=-DIS_MAC=1>>config.mak echo MAC_CFLAGS+=-DIS_MAC=1>>config.mak
if test "$hookmethod" = dyld ; then
echo "using Monterey style DYLD hooking"
echo "CFLAGS+=-DMONTEREY_HOOKING">>config.mak
fi
if ismac64 && [ "$fat_binary" = 1 ] ; then if ismac64 && [ "$fat_binary" = 1 ] ; then
echo "Configuring a fat binary for i386 and x86_64" echo "Configuring a fat binary for i386 and x86_64"
echo MAC_CFLAGS+=-arch i386 -arch x86_64>>config.mak 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 fi
elif isbsd ; then elif isbsd ; then
echo LIBDL=>>config.mak echo LIBDL=>>config.mak
@@ -230,3 +313,6 @@ elif ishaiku ; then
fi fi
echo "Done, now run $make_cmd && $make_cmd install" 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
+35 -34
View File
@@ -462,8 +462,10 @@ static int start_chain(int *fd, proxy_data * pd, char *begin_mark) {
error1: error1:
proxychains_write_log(TP " timeout\n"); proxychains_write_log(TP " timeout\n");
error: error:
if(*fd != -1) if(*fd != -1) {
close(*fd); close(*fd);
*fd = -1;
}
return SOCKET_ERROR; 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; int retcode = -1;
char *hostname; char *hostname, *errmsg = 0;
char hostname_buf[MSG_LEN_MAX]; char hostname_buf[MSG_LEN_MAX];
char ip_buf[INET6_ADDRSTRLEN]; char ip_buf[INET6_ADDRSTRLEN];
int v6 = pto->ip.is_v6; int v6 = pto->ip.is_v6;
@@ -536,31 +538,34 @@ static int chain_step(int ns, proxy_data * pfrom, proxy_data * pto) {
usenumericip: usenumericip:
if(!inet_ntop(v6?AF_INET6:AF_INET,pto->ip.addr.v6,ip_buf,sizeof ip_buf)) { if(!inet_ntop(v6?AF_INET6:AF_INET,pto->ip.addr.v6,ip_buf,sizeof ip_buf)) {
pto->ps = DOWN_STATE; pto->ps = DOWN_STATE;
proxychains_write_log("<--ip conversion error!\n"); errmsg = "<--ip conversion error!\n";
close(ns); retcode = SOCKET_ERROR;
return SOCKET_ERROR; goto err;
} }
hostname = ip_buf; hostname = ip_buf;
} }
proxychains_write_log(TP " %s:%d ", hostname, htons(pto->port)); 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) { switch (retcode) {
case SUCCESS: case SUCCESS:
pto->ps = BUSY_STATE; pto->ps = BUSY_STATE;
break; break;
case BLOCKED: case BLOCKED:
pto->ps = BLOCKED_STATE; pto->ps = BLOCKED_STATE;
proxychains_write_log("<--denied\n"); errmsg = "<--denied\n";
close(ns); goto err;
break;
case SOCKET_ERROR: case SOCKET_ERROR:
pto->ps = DOWN_STATE; pto->ps = DOWN_STATE;
proxychains_write_log("<--socket error or timeout!\n"); errmsg = "<--socket error or timeout!\n";
close(ns); goto err;
break;
} }
return retcode; 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, 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); p2 = select_proxy(FIFOLY, pd, proxy_count, &offset);
if(!p2) if(!p2)
break; break;
if(SUCCESS != chain_step(ns, p1, p2)) { if(SUCCESS != chain_step(&ns, p1, p2)) {
PDEBUG("GOTO AGAIN 1\n"); PDEBUG("GOTO AGAIN 1\n");
goto again; goto again;
} }
@@ -605,7 +610,7 @@ int connect_proxy_chain(int sock, ip_type target_ip,
//proxychains_write_log(TP); //proxychains_write_log(TP);
p3->ip = target_ip; p3->ip = target_ip;
p3->port = target_port; p3->port = target_port;
if(SUCCESS != chain_step(ns, p1, p3)) if(SUCCESS != chain_step(&ns, p1, p3))
goto error; goto error;
break; break;
@@ -643,7 +648,7 @@ int connect_proxy_chain(int sock, ip_type target_ip,
/* Try from the beginning to where we started */ /* Try from the beginning to where we started */
offset = 0; offset = 0;
continue; continue;
} else if(SUCCESS != chain_step(ns, p1, p2)) { } else if(SUCCESS != chain_step(&ns, p1, p2)) {
PDEBUG("GOTO AGAIN 1\n"); PDEBUG("GOTO AGAIN 1\n");
goto again; goto again;
} else } else
@@ -655,7 +660,7 @@ int connect_proxy_chain(int sock, ip_type target_ip,
p3->port = target_port; p3->port = target_port;
proxychains_proxy_offset = offset+1; proxychains_proxy_offset = offset+1;
PDEBUG("pd_offset = %d, curr_len = %d\n", proxychains_proxy_offset, curr_len); 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; goto error;
break; break;
@@ -673,7 +678,7 @@ int connect_proxy_chain(int sock, ip_type target_ip,
while(offset < proxy_count) { while(offset < proxy_count) {
if(!(p2 = select_proxy(FIFOLY, pd, proxy_count, &offset))) if(!(p2 = select_proxy(FIFOLY, pd, proxy_count, &offset)))
break; break;
if(SUCCESS != chain_step(ns, p1, p2)) { if(SUCCESS != chain_step(&ns, p1, p2)) {
PDEBUG("chain_step failed\n"); PDEBUG("chain_step failed\n");
goto error_strict; goto error_strict;
} }
@@ -682,7 +687,7 @@ int connect_proxy_chain(int sock, ip_type target_ip,
//proxychains_write_log(TP); //proxychains_write_log(TP);
p3->ip = target_ip; p3->ip = target_ip;
p3->port = target_port; p3->port = target_port;
if(SUCCESS != chain_step(ns, p1, p3)) if(SUCCESS != chain_step(&ns, p1, p3))
goto error; goto error;
break; break;
@@ -698,7 +703,7 @@ int connect_proxy_chain(int sock, ip_type target_ip,
while(++curr_len < max_chain) { while(++curr_len < max_chain) {
if(!(p2 = select_proxy(RANDOMLY, pd, proxy_count, &offset))) if(!(p2 = select_proxy(RANDOMLY, pd, proxy_count, &offset)))
goto error_more; goto error_more;
if(SUCCESS != chain_step(ns, p1, p2)) { if(SUCCESS != chain_step(&ns, p1, p2)) {
PDEBUG("GOTO AGAIN 2\n"); PDEBUG("GOTO AGAIN 2\n");
goto again; goto again;
} }
@@ -707,7 +712,7 @@ int connect_proxy_chain(int sock, ip_type target_ip,
//proxychains_write_log(TP); //proxychains_write_log(TP);
p3->ip = target_ip; p3->ip = target_ip;
p3->port = target_port; p3->port = target_port;
if(SUCCESS != chain_step(ns, p1, p3)) if(SUCCESS != chain_step(&ns, p1, p3))
goto error; goto error;
} }
@@ -824,7 +829,8 @@ struct hostent* proxy_gethostbyname_old(const char *name)
close(pipe_fd[0]); close(pipe_fd[0]);
got_buff: got_buff:
l = strlen(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); addr = inet_addr(buff);
if (addr == (in_addr_t) (-1)) if (addr == (in_addr_t) (-1))
goto err_dns; goto err_dns;
@@ -839,8 +845,7 @@ got_buff:
name, inet_ntoa(*(struct in_addr*)&addr)); name, inet_ntoa(*(struct in_addr*)&addr));
return &hostent_space; return &hostent_space;
err_dns: err_dns:
proxychains_write_log("|DNS-response|: %s does not exist\n", name); proxychains_write_log("|DNS-response|: %s lookup error\n", name);
perror("err_dns");
err: err:
return NULL; 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); node?node:"",service?service:"",hints?(int)hints->ai_flags:0);
space = calloc(1, sizeof(struct addrinfo_data)); space = calloc(1, sizeof(struct addrinfo_data));
if(!space) goto err1; if(!space) return EAI_MEMORY;
if(node && !my_inet_aton(node, space)) { if(node && !my_inet_aton(node, space)) {
/* some folks (nmap) use getaddrinfo() with AI_NUMERICHOST to check whether a string /* 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. */ containing a numeric ip was passed. we must return failure in that case. */
if(hints && (hints->ai_flags & AI_NUMERICHOST)) { if(hints && (hints->ai_flags & AI_NUMERICHOST)) {
err_nn:
free(space); free(space);
return EAI_NONAME; 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, memcpy(&((struct sockaddr_in *) &space->sockaddr_space)->sin_addr,
*(hp->h_addr_list), sizeof(in_addr_t)); *(hp->h_addr_list), sizeof(in_addr_t));
else else
goto err2; goto err_nn;
} else if(node) { } else if(node) {
af = ((struct sockaddr_in *) &space->sockaddr_space)->sin_family; af = ((struct sockaddr_in *) &space->sockaddr_space)->sin_family;
} else if(!node && !(hints->ai_flags & AI_PASSIVE)) { } else if(!node && !(hints->ai_flags & AI_PASSIVE)) {
af = ((struct sockaddr_in *) &space->sockaddr_space)->sin_family = AF_INET; af = ((struct sockaddr_in *) &space->sockaddr_space)->sin_family = AF_INET;
memcpy(&((struct sockaddr_in *) &space->sockaddr_space)->sin_addr, 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); if(service) mygetservbyname_r(service, NULL, &se_buf, buf, sizeof(buf), &se);
@@ -1018,18 +1024,13 @@ int proxy_getaddrinfo(const char *node, const char *service, const struct addrin
p->ai_socktype = hints->ai_socktype; p->ai_socktype = hints->ai_socktype;
p->ai_flags = hints->ai_flags; p->ai_flags = hints->ai_flags;
p->ai_protocol = hints->ai_protocol; p->ai_protocol = hints->ai_protocol;
if(!p->ai_socktype && p->ai_protocol == IPPROTO_TCP)
p->ai_socktype = SOCK_STREAM;
} else { } else {
#ifndef AI_V4MAPPED #ifndef AI_V4MAPPED
#define AI_V4MAPPED 0 #define AI_V4MAPPED 0
#endif #endif
p->ai_flags = (AI_V4MAPPED | AI_ADDRCONFIG); p->ai_flags = (AI_V4MAPPED | AI_ADDRCONFIG);
} }
goto out;
err2:
free(space);
err1:
return 1;
out:
return 0; return 0;
} }
+14 -3
View File
@@ -65,8 +65,18 @@ typedef enum {
} select_type; } select_type;
typedef struct { typedef struct {
struct in_addr in_addr, netmask; sa_family_t family;
unsigned short port; unsigned short port;
union {
struct {
struct in_addr in_addr;
struct in_addr in_mask;
};
struct {
struct in6_addr in6_addr;
unsigned char in6_prefix;
};
};
} localaddr_arg; } localaddr_arg;
typedef struct { typedef struct {
@@ -90,16 +100,17 @@ int connect_proxy_chain (int sock, ip_type target_ip, unsigned short target_port
void proxychains_write_log(char *str, ...); void proxychains_write_log(char *str, ...);
typedef int (*close_t)(int); typedef int (*close_t)(int);
typedef int (*close_range_t)(unsigned, unsigned, int);
typedef int (*connect_t)(int, const struct sockaddr *, socklen_t); typedef int (*connect_t)(int, const struct sockaddr *, socklen_t);
typedef struct hostent* (*gethostbyname_t)(const char *); 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 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 **); struct addrinfo **);
typedef int (*getnameinfo_t) (const struct sockaddr *, socklen_t, char *, typedef int (*getnameinfo_t) (const struct sockaddr *, socklen_t, char *,
socklen_t, char *, socklen_t, int); 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, typedef ssize_t (*sendto_t) (int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen); const struct sockaddr *dest_addr, socklen_t addrlen);
+1
View File
@@ -5,6 +5,7 @@
*/ */
#undef _GNU_SOURCE
#define _GNU_SOURCE #define _GNU_SOURCE
#include <unistd.h> #include <unistd.h>
#define _POSIX_C_SOURCE 200809L #define _POSIX_C_SOURCE 200809L
+248 -78
View File
@@ -22,6 +22,7 @@
#include <unistd.h> #include <unistd.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <limits.h>
#include <ctype.h> #include <ctype.h>
#include <errno.h> #include <errno.h>
#include <assert.h> #include <assert.h>
@@ -55,6 +56,7 @@ connect_t true___xnet_connect;
#endif #endif
close_t true_close; close_t true_close;
close_range_t true_close_range;
connect_t true_connect; connect_t true_connect;
gethostbyname_t true_gethostbyname; gethostbyname_t true_gethostbyname;
getaddrinfo_t true_getaddrinfo; getaddrinfo_t true_getaddrinfo;
@@ -85,13 +87,14 @@ static int init_l = 0;
static void get_chain_data(proxy_data * pd, unsigned int *proxy_count, chain_type * ct); 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); void *funcptr = dlsym(RTLD_NEXT, symname);
if(!funcptr) { if(is_mandatory && !funcptr) {
fprintf(stderr, "Cannot load symbol '%s' %s\n", symname, dlerror()); fprintf(stderr, "Cannot load symbol '%s' %s\n", symname, dlerror());
exit(1); exit(1);
} else if (!funcptr) {
return funcptr;
} else { } else {
PDEBUG("loaded symbol '%s'" " real addr %p wrapped addr %p\n", symname, funcptr, proxyfunc); PDEBUG("loaded symbol '%s'" " real addr %p wrapped addr %p\n", symname, funcptr, proxyfunc);
} }
@@ -102,44 +105,56 @@ static void* load_sym(char* symname, void* proxyfunc) {
return funcptr; return funcptr;
} }
#define INIT() init_lib_wrapper(__FUNCTION__)
#define SETUP_SYM(X) do { if (! true_ ## X ) true_ ## X = load_sym( # X, X ); } while(0)
#include "allocator_thread.h" #include "allocator_thread.h"
const char *proxychains_get_version(void); const char *proxychains_get_version(void);
static void setup_hooks(void) { static void setup_hooks(void);
SETUP_SYM(connect);
SETUP_SYM(sendto);
SETUP_SYM(gethostbyname);
SETUP_SYM(getaddrinfo);
SETUP_SYM(freeaddrinfo);
SETUP_SYM(gethostbyaddr);
SETUP_SYM(getnameinfo);
#ifdef IS_SOLARIS
SETUP_SYM(__xnet_connect);
#endif
SETUP_SYM(close);
}
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[16];
static int close_fds_cnt = 0; 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
struct timespec now;
clock_gettime(CLOCK_REALTIME, &now);
return now.tv_sec ^ now.tv_nsec;
#else
return time(NULL);
#endif
}
static void do_init(void) { static void do_init(void) {
srand(time(NULL)); char *env;
srand(get_rand_seed());
core_initialize(); core_initialize();
/* read the config file */ env = getenv(PROXYCHAINS_QUIET_MODE_ENV_VAR);
get_chain_data(proxychains_pd, &proxychains_proxy_count, &proxychains_ct); if(env && *env == '1')
DUMP_PROXY_CHAIN(proxychains_pd, proxychains_proxy_count); proxychains_quiet_mode = 1;
proxychains_write_log(LOG_PREFIX "DLL init: proxychains-ng %s\n", proxychains_get_version()); proxychains_write_log(LOG_PREFIX "DLL init: proxychains-ng %s\n", proxychains_get_version());
setup_hooks(); 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_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; init_l = 1;
rdns_init(proxychains_resolver); rdns_init(proxychains_resolver);
@@ -153,16 +168,19 @@ static void init_lib_wrapper(const char* caller) {
pthread_once(&init_once, do_init); 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 * to call init_lib at link time. otherwise it gets loaded
* lazily, which has the disadvantage that there's a potential * 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 */ * and PTHREAD support was disabled */
#if __GNUC__ > 2 #if __GNUC__+0 > 2
__attribute__((constructor)) __attribute__((constructor))
static void gcc_init(void) { static void gcc_init(void) {
INIT(); init_lib_wrapper(__FUNCTION__);
} }
#define INIT() do {} while(0)
#else
#define INIT() init_lib_wrapper(__FUNCTION__)
#endif #endif
@@ -223,7 +241,7 @@ static int proxy_from_string(const char *proxystring,
ul = p-u; ul = p-u;
p++; p++;
pl = at-p; pl = at-p;
if(proxytype == RS_PT_SOCKS5 && (ul > 255 || pl > 255)) if(ul > 255 || pl > 255)
return 0; return 0;
memcpy(user_buf, u, ul); memcpy(user_buf, u, ul);
user_buf[ul]=0; user_buf[ul]=0;
@@ -272,8 +290,7 @@ static void get_chain_data(proxy_data * pd, unsigned int *proxy_count, chain_typ
int count = 0, port_n = 0, list = 0; int count = 0, port_n = 0, list = 0;
char buf[1024], type[1024], host[1024], user[1024]; char buf[1024], type[1024], host[1024], user[1024];
char *buff, *env, *p; char *buff, *env, *p;
char local_in_addr_port[32]; char local_addr_port[64], local_addr[64], local_netmask[32];
char local_in_addr[32], local_in_port[32], local_netmask[32];
char dnat_orig_addr_port[32], dnat_new_addr_port[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 dnat_orig_addr[32], dnat_orig_port[32], dnat_new_addr[32], dnat_new_port[32];
char rdnsd_addr[32], rdnsd_port[8]; char rdnsd_addr[32], rdnsd_port[8];
@@ -296,10 +313,6 @@ static void get_chain_data(proxy_data * pd, unsigned int *proxy_count, chain_typ
exit(1); exit(1);
} }
env = getenv(PROXYCHAINS_QUIET_MODE_ENV_VAR);
if(env && *env == '1')
proxychains_quiet_mode = 1;
while(fgets(buf, sizeof(buf), file)) { while(fgets(buf, sizeof(buf), file)) {
buff = buf; buff = buf;
/* remove leading whitespace */ /* remove leading whitespace */
@@ -338,7 +351,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) { 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 */ /* 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); 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; pd[count].ip.is_v6 = 0;
host_ip->addr.v4 = internal_ip; host_ip->addr.v4 = internal_ip;
if(internal_ip.as_int == IPT4_INVALID.as_int) if(internal_ip.as_int == IPT4_INVALID.as_int)
@@ -388,42 +401,76 @@ inv_host:
exit(1); exit(1);
} }
} else if(STR_STARTSWITH(buff, "localnet")) { } else if(STR_STARTSWITH(buff, "localnet")) {
if(sscanf(buff, "%s %21[^/]/%15s", user, local_in_addr_port, local_netmask) < 3) { char colon, extra, right_bracket[2];
unsigned short local_port = 0, local_prefix;
int local_family, n, valid;
if(sscanf(buff, "%s %53[^/]/%15s%c", user, local_addr_port, local_netmask, &extra) != 3) {
fprintf(stderr, "localnet format error"); fprintf(stderr, "localnet format error");
exit(1); exit(1);
} }
/* clean previously used buffer */ p = strchr(local_addr_port, ':');
memset(local_in_port, 0, sizeof(local_in_port) / sizeof(local_in_port[0])); if(!p || p == strrchr(local_addr_port, ':')) {
local_family = AF_INET;
if(sscanf(local_in_addr_port, "%15[^:]:%5s", local_in_addr, local_in_port) < 2) { n = sscanf(local_addr_port, "%15[^:]%c%5hu%c", local_addr, &colon, &local_port, &extra);
PDEBUG("added localnet: netaddr=%s, netmask=%s\n", valid = n == 1 || (n == 3 && colon == ':');
local_in_addr, local_netmask); } else if(local_addr_port[0] == '[') {
local_family = AF_INET6;
n = sscanf(local_addr_port, "[%45[^][]%1[]]%c%5hu%c", local_addr, right_bracket, &colon, &local_port, &extra);
valid = n == 2 || (n == 4 && colon == ':');
} else { } else {
PDEBUG("added localnet: netaddr=%s, port=%s, netmask=%s\n", local_family = AF_INET6;
local_in_addr, local_in_port, local_netmask); valid = sscanf(local_addr_port, "%45[^][]%c", local_addr, &extra) == 1;
}
if(!valid) {
fprintf(stderr, "localnet address or port error\n");
exit(1);
}
if(local_port) {
PDEBUG("added localnet: netaddr=%s, port=%u, netmask=%s\n",
local_addr, local_port, local_netmask);
} else {
PDEBUG("added localnet: netaddr=%s, netmask=%s\n",
local_addr, local_netmask);
} }
if(num_localnet_addr < MAX_LOCALNET) { if(num_localnet_addr < MAX_LOCALNET) {
int error; localnet_addr[num_localnet_addr].family = local_family;
error = localnet_addr[num_localnet_addr].port = local_port;
inet_pton(AF_INET, local_in_addr, valid = 0;
&localnet_addr[num_localnet_addr].in_addr); if (local_family == AF_INET) {
if(error <= 0) { valid =
inet_pton(local_family, local_addr,
&localnet_addr[num_localnet_addr].in_addr) > 0;
} else if(local_family == AF_INET6) {
valid =
inet_pton(local_family, local_addr,
&localnet_addr[num_localnet_addr].in6_addr) > 0;
}
if(!valid) {
fprintf(stderr, "localnet address error\n"); fprintf(stderr, "localnet address error\n");
exit(1); exit(1);
} }
error = if(local_family == AF_INET && strchr(local_netmask, '.')) {
inet_pton(AF_INET, local_netmask, valid =
&localnet_addr[num_localnet_addr].netmask); inet_pton(local_family, local_netmask,
if(error <= 0) { &localnet_addr[num_localnet_addr].in_mask) > 0;
} else {
valid = sscanf(local_netmask, "%hu%c", &local_prefix, &extra) == 1;
if (valid) {
if(local_family == AF_INET && local_prefix <= 32) {
localnet_addr[num_localnet_addr].in_mask.s_addr =
htonl(0xFFFFFFFFu << (32u - local_prefix));
} else if(local_family == AF_INET6 && local_prefix <= 128) {
localnet_addr[num_localnet_addr].in6_prefix =
local_prefix;
} else {
valid = 0;
}
}
}
if(!valid) {
fprintf(stderr, "localnet netmask error\n"); fprintf(stderr, "localnet netmask error\n");
exit(1); exit(1);
} }
if(local_in_port[0]) {
localnet_addr[num_localnet_addr].port =
(short) atoi(local_in_port);
} else {
localnet_addr[num_localnet_addr].port = 0;
}
++num_localnet_addr; ++num_localnet_addr;
} else { } else {
fprintf(stderr, "# of localnet exceed %d.\n", MAX_LOCALNET); fprintf(stderr, "# of localnet exceed %d.\n", MAX_LOCALNET);
@@ -527,7 +574,14 @@ inv_host:
/******* HOOK FUNCTIONS *******/ /******* HOOK FUNCTIONS *******/
int close(int fd) { #define EXPAND( args...) args
#ifdef MONTEREY_HOOKING
#define HOOKFUNC(R, N, args...) R pxcng_ ## N ( EXPAND(args) )
#else
#define HOOKFUNC(R, N, args...) R N ( EXPAND(args) )
#endif
HOOKFUNC(int, close, int fd) {
if(!init_l) { if(!init_l) {
if(close_fds_cnt>=(sizeof close_fds/sizeof close_fds[0])) goto err; if(close_fds_cnt>=(sizeof close_fds/sizeof close_fds[0])) goto err;
close_fds[close_fds_cnt++] = fd; close_fds[close_fds_cnt++] = fd;
@@ -548,7 +602,71 @@ int close(int fd) {
static int is_v4inv6(const struct in6_addr *a) { 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); return !memcmp(a->s6_addr, "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12);
} }
int connect(int sock, const struct sockaddr *addr, unsigned int len) {
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(); INIT();
PFUNC(); PFUNC();
@@ -611,14 +729,24 @@ int connect(int sock, const struct sockaddr *addr, unsigned int len) {
port = dnat->new_port; port = dnat->new_port;
} }
if (!v6) for(i = 0; i < num_localnet_addr && !remote_dns_connect; i++) { 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) if (localnet_addr[i].port && localnet_addr[i].port != port)
== (p_addr_in->s_addr & localnet_addr[i].netmask.s_addr)) { continue;
if(!localnet_addr[i].port || localnet_addr[i].port == port) { if (localnet_addr[i].family != (v6 ? AF_INET6 : AF_INET))
PDEBUG("accessing localnet using true_connect\n"); continue;
return true_connect(sock, addr, len); if (v6) {
} size_t prefix_bytes = localnet_addr[i].in6_prefix / CHAR_BIT;
size_t prefix_bits = localnet_addr[i].in6_prefix % CHAR_BIT;
if (prefix_bytes && memcmp(p_addr_in6->s6_addr, localnet_addr[i].in6_addr.s6_addr, prefix_bytes) != 0)
continue;
if (prefix_bits && (p_addr_in6->s6_addr[prefix_bytes] ^ localnet_addr[i].in6_addr.s6_addr[prefix_bytes]) >> (CHAR_BIT - prefix_bits))
continue;
} else {
if((p_addr_in->s_addr ^ localnet_addr[i].in_addr.s_addr) & localnet_addr[i].in_mask.s_addr)
continue;
} }
PDEBUG("accessing localnet using true_connect\n");
return true_connect(sock, addr, len);
} }
flags = fcntl(sock, F_GETFL, 0); flags = fcntl(sock, F_GETFL, 0);
@@ -639,13 +767,13 @@ int connect(int sock, const struct sockaddr *addr, unsigned int len) {
} }
#ifdef IS_SOLARIS #ifdef IS_SOLARIS
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); return connect(sock, addr, len);
} }
#endif #endif
static struct gethostbyname_data ghbndata; static struct gethostbyname_data ghbndata;
struct hostent *gethostbyname(const char *name) { HOOKFUNC(struct hostent*, gethostbyname, const char *name) {
INIT(); INIT();
PDEBUG("gethostbyname: %s\n", name); PDEBUG("gethostbyname: %s\n", name);
@@ -659,7 +787,7 @@ struct hostent *gethostbyname(const char *name) {
return NULL; return NULL;
} }
int getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res) { HOOKFUNC(int, getaddrinfo, const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res) {
INIT(); INIT();
PDEBUG("getaddrinfo: %s %s\n", node ? node : "null", service ? service : "null"); PDEBUG("getaddrinfo: %s %s\n", node ? node : "null", service ? service : "null");
@@ -669,7 +797,7 @@ int getaddrinfo(const char *node, const char *service, const struct addrinfo *hi
return true_getaddrinfo(node, service, hints, res); return true_getaddrinfo(node, service, hints, res);
} }
void freeaddrinfo(struct addrinfo *res) { HOOKFUNC(void, freeaddrinfo, struct addrinfo *res) {
INIT(); INIT();
PDEBUG("freeaddrinfo %p \n", (void *) res); PDEBUG("freeaddrinfo %p \n", (void *) res);
@@ -679,9 +807,9 @@ void freeaddrinfo(struct addrinfo *res) {
proxy_freeaddrinfo(res); proxy_freeaddrinfo(res);
} }
int pc_getnameinfo(const struct sockaddr *sa, socklen_t salen, HOOKFUNC(int, getnameinfo, const struct sockaddr *sa, socklen_t salen,
char *host, socklen_t hostlen, char *serv, char *host, GN_NODELEN_T hostlen, char *serv,
socklen_t servlen, int flags) GN_SERVLEN_T servlen, GN_FLAGS_T flags)
{ {
INIT(); INIT();
PFUNC(); PFUNC();
@@ -723,7 +851,7 @@ int pc_getnameinfo(const struct sockaddr *sa, socklen_t salen,
return 0; return 0;
} }
struct hostent *gethostbyaddr(const void *addr, socklen_t len, int type) { HOOKFUNC(struct hostent*, gethostbyaddr, const void *addr, socklen_t len, int type) {
INIT(); INIT();
PDEBUG("TODO: proper gethostbyaddr hook\n"); PDEBUG("TODO: proper gethostbyaddr hook\n");
@@ -759,7 +887,7 @@ struct hostent *gethostbyaddr(const void *addr, socklen_t len, int type) {
# define MSG_FASTOPEN 0x20000000 # define MSG_FASTOPEN 0x20000000
#endif #endif
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, HOOKFUNC(ssize_t, sendto, int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen) { const struct sockaddr *dest_addr, socklen_t addrlen) {
INIT(); INIT();
PFUNC(); PFUNC();
@@ -773,3 +901,45 @@ ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
} }
return true_sendto(sockfd, buf, len, flags, dest_addr, addrlen); return true_sendto(sockfd, buf, len, flags, dest_addr, addrlen);
} }
#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_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) {
SETUP_SYM(connect);
SETUP_SYM(sendto);
SETUP_SYM(gethostbyname);
SETUP_SYM(getaddrinfo);
SETUP_SYM(freeaddrinfo);
SETUP_SYM(gethostbyaddr);
SETUP_SYM(getnameinfo);
#ifdef IS_SOLARIS
SETUP_SYM(__xnet_connect);
#endif
SETUP_SYM(close);
SETUP_SYM_OPTIONAL(close_range);
}
#ifdef MONTEREY_HOOKING
#define DYLD_INTERPOSE(_replacement,_replacee) \
__attribute__((used)) static struct{ const void* replacement; const void* replacee; } _interpose_##_replacee \
__attribute__((section ("__DATA,__interpose"))) = { (const void*)(unsigned long)&_replacement, (const void*)(unsigned long)&_replacee };
#define DYLD_HOOK(F) DYLD_INTERPOSE(pxcng_ ## F, F)
DYLD_HOOK(connect);
DYLD_HOOK(sendto);
DYLD_HOOK(gethostbyname);
DYLD_HOOK(getaddrinfo);
DYLD_HOOK(freeaddrinfo);
DYLD_HOOK(gethostbyaddr);
DYLD_HOOK(getnameinfo);
DYLD_HOOK(close);
#endif
+11 -6
View File
@@ -135,16 +135,20 @@ int main(int argc, char *argv[]) {
if(!quiet) if(!quiet)
fprintf(stderr, LOG_PREFIX "preloading %s/%s\n", prefix, dll_name); 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 #ifdef IS_MAC
putenv("DYLD_FORCE_FLAT_NAMESPACE=1"); putenv("DYLD_FORCE_FLAT_NAMESPACE=1");
#define LD_PRELOAD_ENV "DYLD_INSERT_LIBRARIES" #define LD_PRELOAD_ENV "DYLD_INSERT_LIBRARIES"
#define LD_PRELOAD_SEP ":"
#else #else
#define LD_PRELOAD_ENV "LD_PRELOAD" #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 #endif
char *old_val = getenv(LD_PRELOAD_ENV); char *old_val = getenv(LD_PRELOAD_ENV);
snprintf(buf, sizeof(buf), LD_PRELOAD_ENV "=%s/%s%s%s", snprintf(buf, sizeof(buf), LD_PRELOAD_ENV "=%s/%s%s%s",
@@ -154,7 +158,8 @@ int main(int argc, char *argv[]) {
old_val ? old_val : ""); old_val ? old_val : "");
putenv(buf); putenv(buf);
execvp(argv[start_argv], &argv[start_argv]); execvp(argv[start_argv], &argv[start_argv]);
perror("proxychains can't load process...."); fprintf(stderr, "proxychains: can't load process '%s'.", argv[start_argv]);
perror(" (hint: it's probably a typo)");
return EXIT_FAILURE; return EXIT_FAILURE;
} }
-13
View File
@@ -1,13 +0,0 @@
#include <sys/socket.h>
extern int pc_getnameinfo(const void *sa, socklen_t salen,
char *host, socklen_t hostlen, char *serv,
socklen_t servlen, int flags);
int getnameinfo(const void *sa, socklen_t salen,
char *host, socklen_t hostlen, char *serv,
socklen_t servlen, int flags) {
return pc_getnameinfo(sa, salen, host, hostlen, serv, servlen, flags);
}
+6 -4
View File
@@ -53,9 +53,9 @@ strict_chain
# method 1. this uses the proxychains4 style method to do remote dns: # method 1. this uses the proxychains4 style method to do remote dns:
# a thread is spawned that serves DNS requests and hands down an ip # a thread is spawned that serves DNS requests and hands down an ip
# assigned from an internal list (via remote_dns_subset). # assigned from an internal list (via remote_dns_subnet).
# this is the easiest (setup-wise) and fastest method, however on # this is the easiest (setup-wise) and fastest method, however on
# systems with buggy libcs and very complex software like webbrosers # systems with buggy libcs and very complex software like webbrowsers
# this might not work and/or cause crashes. # this might not work and/or cause crashes.
proxy_dns proxy_dns
@@ -94,7 +94,7 @@ tcp_connect_time_out 8000
### Examples for localnet exclusion ### Examples for localnet exclusion
## localnet ranges will *not* use a proxy to connect. ## localnet ranges will *not* use a proxy to connect.
## note that localnet works only when plain IPv4 addresses are passed to the app, ## note that localnet works only when plain IP addresses are passed to the app,
## the hostname resolves via /etc/hosts, or proxy_dns is disabled or proxy_dns_old used. ## the hostname resolves via /etc/hosts, or proxy_dns is disabled or proxy_dns_old used.
## Exclude connections to 192.168.1.0/24 with port 80 ## Exclude connections to 192.168.1.0/24 with port 80
@@ -105,12 +105,14 @@ tcp_connect_time_out 8000
## Exclude connections to ANYwhere with port 80 ## Exclude connections to ANYwhere with port 80
# localnet 0.0.0.0:80/0.0.0.0 # localnet 0.0.0.0:80/0.0.0.0
# localnet [::]:80/0
## RFC5735 Loopback address range ## RFC6890 Loopback address range
## if you enable this, you have to make sure remote_dns_subnet is not 127 ## 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. ## connects to localhost.
# localnet 127.0.0.0/255.0.0.0 # localnet 127.0.0.0/255.0.0.0
# localnet ::1/128
## RFC1918 Private Address Ranges ## RFC1918 Private Address Ranges
# localnet 10.0.0.0/255.0.0.0 # localnet 10.0.0.0/255.0.0.0
+35
View File
@@ -3,6 +3,8 @@
#include <netdb.h> #include <netdb.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <assert.h>
#include <string.h>
#ifndef NI_MAXHOST #ifndef NI_MAXHOST
#define NI_MAXHOST 1025 #define NI_MAXHOST 1025
@@ -43,9 +45,42 @@ static int doit(const char* host, const char* service) {
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
/* reproduce use of getaddrinfo as used by nmap 7.91's canonicalize_address */
int canonicalize_address(struct sockaddr_storage *ss, struct sockaddr_storage *output) {
char canonical_ip_string[NI_MAXHOST];
struct addrinfo *ai;
int rc;
/* Convert address to string. */
rc = getnameinfo((struct sockaddr *) ss, sizeof(*ss),
canonical_ip_string, sizeof(canonical_ip_string), NULL, 0, NI_NUMERICHOST);
assert(rc == 0);
struct addrinfo hints = {
.ai_family = ss->ss_family,
.ai_socktype = SOCK_DGRAM,
.ai_flags = AI_NUMERICHOST,
};
rc = getaddrinfo(canonical_ip_string, NULL, &hints, &ai);
if (rc != 0 || ai == NULL)
return -1;
assert(ai->ai_addrlen > 0 && ai->ai_addrlen <= (int) sizeof(*output));
memcpy(output, ai->ai_addr, ai->ai_addrlen);
freeaddrinfo(ai);
return 0;
}
int main(void) { int main(void) {
int ret; int ret;
ret = doit("www.example.com", NULL); ret = doit("www.example.com", NULL);
ret = doit("www.example.com", "80"); ret = doit("www.example.com", "80");
struct sockaddr_storage o, ss = {.ss_family = PF_INET};
struct sockaddr_in *v4 = &ss;
struct sockaddr_in6 *v6 = &ss;
memcpy(&v4->sin_addr, "\x7f\0\0\1", 4);
ret = canonicalize_address(&ss, &o);
assert (ret == 0);
ss.ss_family = PF_INET6;
memcpy(&v6->sin6_addr, "\0\0\0\0" "\0\0\0\0" "\0\0\0\0""\0\0\0\1", 16);
ret = canonicalize_address(&ss, &o);
assert (ret == 0);
return ret; return ret;
} }
+12
View File
@@ -123,5 +123,17 @@ int main() {
ASSERT(ret == 0); ASSERT(ret == 0);
b.sin6_port = 0;
b.sin6_scope_id = 0;
memcpy(&b.sin6_addr,"\0\0\0\0" "\0\0\0\0" "\0\0\0\0" "\0\0\0\1", 16);
if ((ret = getnameinfo((void*)sb, sizeof b, hbuf, sizeof(hbuf), NULL,
0, NI_NUMERICHOST)) == 0)
printf("host=%s\n", hbuf);
else
printf("%s\n", gai_strerror(ret));
ASSERT(ret == 0);
return 0; return 0;
} }