Compare commits

...

20 Commits

Author SHA1 Message Date
rofl0r fffd2532ad fix wrong prototype of freeaddrinfo_t
closes #557
2024-03-14 20:11:58 +00:00
rofl0r 282ac7dd02 release 4.17 2024-01-21 17:28:35 +00:00
rofl0r 1d0bc349eb fix potential double-close of file descriptors
in case of an error condition, both start_chain() and chain_step()
were closing the fd to be acted upon, without setting it to -1,
and the function calling them would close them again.

this could affect multi-threaded applications that opened new fds
between the first and the second close, invalidating those fds
in the targeted app.

patch loosely based on report and PR by @jhfrontz.

closes #542
2024-01-02 14:45:25 +00:00
Guilherme Janczak 0279dda939
OpenBSD: use ':' as LD_PRELOAD separator (#538)
LD_PRELOAD documentation added in 1998 talks about colon as
separator, and apparently space no longer works.
2023-12-09 12:59:53 +00:00
wzy d5cc80ae16
Fix zsh install location (#532)
Reported: https://github.com/NixOS/nixpkgs/pull/222667#issuecomment-1713238866
2023-12-02 21:28:35 +00:00
rofl0r 0c795085fa move initialization of quiet variable to do_init
fixes #511 - DLL init line is always printed even with -q.
regression from recent changes to init code.
2023-05-20 15:27:22 +00:00
Wu Zhenyu 42d2d95160 Remove unused code in zsh completion
Move completions/_proxychains4 to completions/zsh/_proxychains4 to avoid confusion
2023-04-26 21:11:29 +01:00
rofl0r 133e06b3f0 fix resolving of proxy names with proxy_dns_daemon
closes #497

in order to make this work, also the change in 2d265582a2
was required; otherwise the sendto() call from rdns lookup would
cause the init code to be called from within the init code and
ultimately hanging on pthread_once().
2023-03-20 20:29:25 +00:00
rofl0r 2d265582a2 disable lazy init if compiler supports GCC constructor attribute
before we started to use the gcc constructor attribute to load our
initialization code, each function hook used to check whether the
initialization was already done, and if not, do it at that point.

this workaround is quite ugly, and creates a circular reference
if the startup code calls any of the hooked functions.

now we only do the lazy init if the compiler used is not GCC
compatible.
2023-03-20 20:15:00 +00:00
rofl0r 66f99b19dd improve DNS failure handling with old proxyresolv method
should fix #493
2023-03-08 15:05:06 +00:00
rofl0r 199d03d8b4 configure: add a check for whether libc headers are usable
closes #486
2022-12-10 19:19:53 +00:00
rofl0r 060801d8c8 fat-binary-m1: use arm64e for dylib, but not for executable
according to research done by @malash, the proxychains4 binary
itself isn't allowed to use system-internal arm64e mode; but
it's possible to add it as a 3rd architecture to the shared
library (.dylib), and then even inject it into system binaries
like /usr/bin/curl, which didn't work since the introduction
of SIP.

therefore, we now create the dylib with all 3 archs, but the
launcher only with arm64 and x86_64.

closes #453
2022-07-21 23:04:03 +00:00
rofl0r 09142579c5 use -Wno-unknown-pragmas if available
this heavily reduces compiler warning spam in build logs.
2022-06-11 11:00:34 +00:00
rofl0r 916d2d7da1 fix --fat-binary-m1 option
even though the preload library was built correctly, the LDFLAGS set
weren't passed to the main proxychains4 binary, resulting in link
errors against the fat object files.

closes #452
2022-05-31 23:53:23 +00:00
rofl0r 4b531806b2 configure: add --fat-binary-m1 for arm64e/x86_64 (M1) fat binary
addresses #451
closes #383
2022-05-19 09:12:10 +00:00
Zenithal 9b42da71f4 Fix zsh completion file to proxychains4 2022-05-15 09:36:35 +01:00
Freed-Wu 04023d3811 Add zsh completion file 2022-04-13 00:55:19 +01:00
rofl0r 0a4daa62d6 using qsort for 4 ints is overkill
replace it with custom mini sort routine.
2022-04-12 23:51:17 +00:00
Recolic Keghart 0000000062 Add hook to close_range function, solves #439. |0! 2022-04-12 20:37:05 +08:00
rofl0r 07c15a02f6 add configure check for non-POSIX compliant getnameinfo signature
- glibc < 2.14 uses "unsigned" instead of "int" for flags
- openbsd and freebsd use "size_t" instead of socklen_t for servlen
  and nodelen, while still using socklen_t for salen.

closes #430
2022-01-25 15:42:55 +00:00
10 changed files with 209 additions and 70 deletions

1
.gitignore vendored
View File

@ -1,4 +1,5 @@
proxychains4
proxychains4-daemon
*.bz2
*.xz
*.o

View File

@ -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

11
README
View File

@ -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

View File

@ -1 +1 @@
4.16
4.17

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'

30
configure vendored
View File

@ -86,6 +86,7 @@ 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 "--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 +101,7 @@ spliteq() {
}
fat_binary=
fat_binary_m1=
ignore_cve=no
hookmethod=auto
@ -115,6 +117,7 @@ parsearg() {
--ignore-cve=*) ignore_cve=`spliteq $1`;;
--hookmethod=*) hookmethod=`spliteq $1`;;
--fat-binary) fat_binary=1;;
--fat-binary-m1) fat_binary_m1=1;;
--help) usage;;
esac
}
@ -174,6 +177,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 +280,14 @@ 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
elif isbsd ; then
echo LIBDL=>>config.mak

View File

@ -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,7 +993,7 @@ 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)) {
@ -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;
}

View File

@ -100,16 +100,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 *,
struct addrinfo **);
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,
const struct sockaddr *dest_addr, socklen_t addrlen);

View File

@ -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;
@ -86,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* 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 +105,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 +133,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 +168,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
@ -293,10 +313,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 +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) {
/* 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)
@ -587,6 +603,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();
@ -729,8 +808,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 +904,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 +923,7 @@ static void setup_hooks(void) {
SETUP_SYM(__xnet_connect);
#endif
SETUP_SYM(close);
SETUP_SYM_OPTIONAL(close_range);
}
#ifdef MONTEREY_HOOKING

View File

@ -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",