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

Compare commits

...

47 Commits

17 changed files with 592 additions and 363 deletions
+2 -2
View File
@@ -25,7 +25,7 @@ GENH = src/version.h
CFLAGS += -Wall -O0 -g -std=c99 -D_GNU_SOURCE -pipe
NO_AS_NEEDED = -Wl,--no-as-needed
LIBDL = -ldl
LDFLAGS = -shared -fPIC $(NO_AS_NEEDED) $(LIBDL) -lpthread
LDFLAGS = -fPIC $(NO_AS_NEEDED) $(LIBDL) -lpthread
INC =
PIC = -fPIC
AR = $(CROSS_COMPILE)ar
@@ -82,7 +82,7 @@ src/version.o: src/version.h
$(LDSO_PATHNAME): $(LOBJS)
$(CC) $(LDFLAGS) $(LD_SET_SONAME)$(LDSO_PATHNAME) $(USER_LDFLAGS) \
-o $@ $(LOBJS)
-shared -o $@ $(LOBJS)
$(ALL_TOOLS): $(OBJS)
$(CC) src/main.o src/common.o $(USER_LDFLAGS) -o $(PXCHAINS)
+52 -13
View File
@@ -1,4 +1,4 @@
ProxyChains-NG ver 4.10 README
ProxyChains-NG ver 4.12 README
=============================
ProxyChains is a UNIX program, that hooks network-related libc functions
@@ -7,13 +7,13 @@ ProxyChains-NG ver 4.10 README
It supports TCP only (no UDP/ICMP etc).
The way it works is basically a HACK; so it is possible that it doesn't
work with your program, especially when it's a script, or starts
work with your program, especially when it's a script, or starts
numerous processes like background daemons or uses dlopen() to load
"modules" (bug in glibc dynlinker).
It should work with simple compiled (C/C++) dynamically linked programs
though.
If your program doesn't work with proxychains, consider using an
If your program doesn't work with proxychains, consider using an
iptables based solution instead; this is much more robust.
Supported Platforms: Linux, BSD, Mac.
@@ -35,8 +35,8 @@ ProxyChains-NG ver 4.10 README
ONLY USE PROXYCHAINS IF YOU KNOW WHAT YOU'RE DOING.
THE AUTHORS AND MAINTAINERS OF PROXYCHAINS DO NOT TAKE ANY
RESPONSIBILITY FOR ANY ABUSE OR MISUSE OF THIS SOFTWARE AND
THE AUTHORS AND MAINTAINERS OF PROXYCHAINS DO NOT TAKE ANY
RESPONSIBILITY FOR ANY ABUSE OR MISUSE OF THIS SOFTWARE AND
THE RESULTING CONSEQUENCES.
*** Installation ***
@@ -52,6 +52,21 @@ ProxyChains-NG ver 4.10 README
Changelog:
----------
Version 4.12
- fix several build issues
- for MAC
- with -pie
- with custom CC
- compatibility fix for some GUI apps (8870140)
- compatibility fix for some HTTP proxies (cf9a16d)
- fix several warnings for cleaner build on debian
- fix random_chain on OSX (0f6b226)
Version 4.11
- preliminary IPv6 support
- fixed bug in hostsreader
- preliminary support for usage on OpenBSD (caveat emptor)
Version 4.10
- fix regression in linking order with custom LDFLAGS
- fix segfault in DNS mapping code in programs with > ~400 different lookups
@@ -76,7 +91,7 @@ Version 4.7:
- new round_robin chaintype by crass.
- fix bug with lazy allocation when GCC constructor was not used.
- new configure flag --fat-binary to create a "fat" binary/library on OS X
- return EBADF rather than EINTR in close hook.
- return EBADF rather than EINTR in close hook.
it's legal for a program to retry close() calls when they receive
EINTR, which could cause an infinite loop, as seen in chromium.
@@ -103,13 +118,13 @@ Version 4.2:
- fixes compilation issues with ubuntu 12.04 toolchain
- fixes segfault in rare codepath
Version 4.1
Version 4.1
- support for mac os x (all archs)
- all internal functions are threadsafe when compiled with -DTHREAD_SAFE
- all internal functions are threadsafe when compiled with -DTHREAD_SAFE
(default).
Version 4.0
- replaced dnsresolver script (which required a dynamically linked "dig"
- replaced dnsresolver script (which required a dynamically linked "dig"
binary to be present) with remote DNS lookup.
this speeds up any operation involving DNS, as the old script had to use TCP.
additionally it allows to use .onion urls when used with TOR.
@@ -119,7 +134,7 @@ Version 4.0
environment variables.
Version 3.0
- support for DNS resolving through proxy
- support for DNS resolving through proxy
supports SOCKS4, SOCKS5 and HTTP CONNECT proxy servers.
Auth-types: socks - "user/pass" , http - "basic".
@@ -141,7 +156,7 @@ Some cool features:
random order from the list ( user defined length of chain ).
exact order (as they appear in the list )
dynamic order (smart exclude dead proxies from chain)
* You can use it with most TCP client applications, possibly even network
* You can use it with most TCP client applications, possibly even network
scanners, as long as they use standard libc functionality.
pcap based scanning does not work.
* You can use it with servers, like squid, sendmail, or whatever.
@@ -169,9 +184,9 @@ specified by proxychains.conf
Usage Example:
$ proxychains -f /etc/proxychains-other.conf targethost2.com
$ proxychains -f /etc/proxychains-other.conf telnet targethost2.com
in this example it will use different configuration file then proxychains.conf
in this example it will use different configuration file then proxychains.conf
to connect to targethost2.com host.
Usage Example:
@@ -181,6 +196,30 @@ Usage Example:
in this example it will resolve targethost.com through proxy(or chained proxies)
specified by proxychains.conf
Known Problems:
---------------
- newer versions of nmap try to determine the network interface to use
even if it's not needed (like when doing simple syn scans which use the
standard POSIX socket API. this results in errors when proxychains hands
out an ip address to a reserved address space.
possible workarounds: disable proxy_dns, use a numeric ip, or use nmap's
native support for SOCKS proxies.
- Mac OS X 10.11 (El Capitan) ships with a new security feature called SIP
that prevents hooking of system apps.
workarounds are to partially disable SIP by issuing
csrutil enable --without debug in recovery mode,
or to copy the system binary into the home directory and run it from there.
see github issue #78 for details.
- the glibc dynlinker has a bug or security feature that inhibits dlopen()ed
modules from being subject to the same dlsym hooks as installed for the main
program. this mainly affects scripting languages such as perl or python
that heavily rely on dlopen() for modules written in C to work.
there are unconfirmed reports that it works as root though.
musl libc is unaffected from the bug.
Community:
----------
#proxychains on irc.freenode.net
+1 -1
View File
@@ -1 +1 @@
4.10
4.12
Vendored
+70 -12
View File
@@ -1,6 +1,18 @@
#!/bin/sh
prefix=/usr/local
OUR_CPPFLAGS=
# Get a temporary filename
i=0
set -C
while : ; do i=$(($i+1))
tmpc="./conf$$-$PPID-$i.c"
2>|/dev/null > "$tmpc" && break
test "$i" -gt 50 && fail "$0: cannot create temporary file $tmpc"
done
set +C
trap 'rm "$tmpc"' EXIT INT QUIT TERM HUP
ismac() {
uname -s | grep Darwin >/dev/null
@@ -18,15 +30,47 @@ isopenbsd() {
uname -s | grep OpenBSD >/dev/null
}
check_compile() {
printf "checking %s ... " "$1"
printf "$3" > "$tmpc"
local res=0
$CC $OUR_CPPFLAGS $CPPFLAGS $2 $CFLAGS -c "$tmpc" -o /dev/null >/dev/null 2>&1 \
|| res=1
test x$res = x0 && \
{ printf "yes\n" ; test x"$2" = x || OUR_CPPFLAGS="$OUR_CPPFLAGS $2" ; } \
|| printf "no\n"
return $res
}
check_define() {
printf "checking whether \$CC defines %s ... " "$1"
local res=1
$CC $OUR_CPPFLAGS $CPPFLAGS $CFLAGS -dM -E - </dev/null | grep "$1" >/dev/null && res=0
test x$res = x0 && printf "yes\n" || printf "no\n"
return $res
}
check_compile_run() {
printf "checking %s ... " "$1"
printf "$2" > "$tmpc"
local res=0
$CC $OUR_CPPFLAGS $CPPFLAGS $CFLAGS "$tmpc" -o "$tmpc".out >/dev/null 2>&1 \
|| res=1
test x$res = x0 && { "$tmpc".out || res=1 ; }
rm -f "$tmpc".out
test x$res = x0 && printf "yes\n" || printf "no\n"
return $res
}
usage() {
echo "supported arguments"
echo "--prefix=/path default: $prefix"
echo "--exec_prefix=/path default: $prefix/bin"
echo "--bindir=/path default: $prefix/bin"
echo "--libdir=/path default: $prefix/lib"
echo "--includedir=/path default: $prefix/include"
echo "--sysconfdir=/path default: $prefix/etc"
echo "--ignore-cve default: no"
echo "--prefix=/path default: $prefix"
echo "--exec_prefix=/path default: $prefix/bin"
echo "--bindir=/path default: $prefix/bin"
echo "--libdir=/path default: $prefix/lib"
echo "--includedir=/path default: $prefix/include"
echo "--sysconfdir=/path default: $prefix/etc"
echo "--ignore-cve default: no"
echo " if set to yes ignores CVE-2015-3887 and makes it possible"
echo " to preload from current dir (insecure)"
ismac && isx86_64 && echo "--fat-binary : build for both i386 and x86_64 architectures on 64-bit Macs"
@@ -89,17 +133,31 @@ if [ -z "$CC" ] ; then
CC=cc
fi
echo CC?=$CC>config.mak
[ -z "$CPPFLAGS" ] || echo CPPFLAGS?=$CPPFLAGS>>config.mak
[ -z "$CFLAGS" ] || echo USER_CFLAGS?=$CFLAGS>>config.mak
[ -z "$LDFLAGS" ] || echo USER_LDFLAGS?=$LDFLAGS>>config.mak
check_compile 'whether netinet/in.h defines s6_addr16' "" \
'#include <netinet/in.h>\nint main(int a, char**c){struct in6_addr x={.s6_addr32[0]=a};return x.s6_addr16[0]; }' \
|| {
check_compile 'whether netinet/in.h defines __u6_addr.__u6_addr16' \
'-Ds6_addr16=__u6_addr.__u6_addr16 -Ds6_addr32=__u6_addr.__u6_addr32' \
'#include <netinet/in.h>\nint main(int a, char**c){struct in6_addr x={.s6_addr32[0]=a};return x.s6_addr16[0]; }'
}
check_define __OpenBSD__ && \
check_compile_run 'whether OpenBSDs fclose() (illegally) calls close()' \
'#include <stdio.h>\n#include<stdlib.h>\nint close(int x){exit(0);}int main(){fclose(stdin);return 1;}' && \
OUR_CPPFLAGS="$OUR_CPPFLAGS -DBROKEN_FCLOSE"
echo "CC=$CC">config.mak
[ -z "$CPPFLAGS" ] || echo "CPPFLAGS=$CPPFLAGS">>config.mak
[ -z "$CFLAGS" ] || echo "USER_CFLAGS=$CFLAGS">>config.mak
[ -z "$LDFLAGS" ] || echo "USER_LDFLAGS=$LDFLAGS">>config.mak
echo prefix=$prefix>>config.mak
echo exec_prefix=$exec_prefix>>config.mak
echo bindir=$bindir>>config.mak
echo libdir=$libdir>>config.mak
echo includedir=$includedir>>config.mak
echo sysconfdir=$sysconfdir>>config.mak
[ "$ignore_cve" = "no" ] && echo CPPFLAGS+= -DSUPER_SECURE>>config.mak
[ "$ignore_cve" = "no" ] && echo "CPPFLAGS+= -DSUPER_SECURE">>config.mak
[ -z "$OUR_CPPFLAGS" ] || echo "CPPFLAGS+= $OUR_CPPFLAGS" >>config.mak
make_cmd=make
if ismac ; then
echo NO_AS_NEEDED=>>config.mak
-11
View File
@@ -1,11 +0,0 @@
### config.mak template for proxychains
#######################################
# just copy into proxychains root dir and adapt to your needs.
prefix = /usr/local/
libdir = $(prefix)/lib
exec_prefix = /usr/local
bindir = $(exec_prefix)/bin
+17 -17
View File
@@ -38,16 +38,16 @@ pthread_mutex_t internal_ips_lock;
internal_ip_lookup_table *internal_ips = NULL;
internal_ip_lookup_table internal_ips_buf;
uint32_t index_from_internal_ip(ip_type internalip) {
uint32_t index_from_internal_ip(ip_type4 internalip) {
PFUNC();
ip_type tmp = internalip;
ip_type4 tmp = internalip;
uint32_t ret;
ret = tmp.octet[3] + (tmp.octet[2] << 8) + (tmp.octet[1] << 16);
ret -= 1;
return ret;
}
char *string_from_internal_ip(ip_type internalip) {
char *string_from_internal_ip(ip_type4 internalip) {
PFUNC();
char *res = NULL;
uint32_t index = index_from_internal_ip(internalip);
@@ -57,11 +57,11 @@ char *string_from_internal_ip(ip_type internalip) {
}
extern unsigned int remote_dns_subnet;
ip_type make_internal_ip(uint32_t index) {
ip_type ret;
ip_type4 make_internal_ip(uint32_t index) {
ip_type4 ret;
index++; // so we can start at .0.0.1
if(index > 0xFFFFFF)
return ip_type_invalid;
return ip_type_invalid.addr.v4;
ret.octet[0] = remote_dns_subnet & 0xFF;
ret.octet[1] = (index & 0xFF0000) >> 16;
ret.octet[2] = (index & 0xFF00) >> 8;
@@ -69,10 +69,10 @@ ip_type make_internal_ip(uint32_t index) {
return ret;
}
static ip_type ip_from_internal_list(char* name, size_t len) {
static ip_type4 ip_from_internal_list(char* name, size_t len) {
uint32_t hash = dalias_hash((char *) name);
size_t i;
ip_type res;
ip_type4 res;
void* new_mem;
// see if we already have this dns entry saved.
if(internal_ips->counter) {
@@ -99,7 +99,7 @@ static ip_type ip_from_internal_list(char* name, size_t len) {
}
res = make_internal_ip(internal_ips->counter);
if(res.as_int == ip_type_invalid.as_int)
if(res.as_int == ip_type_invalid.addr.v4.as_int)
goto err_plus_unlock;
string_hash_tuple tmp = { 0 };
@@ -128,7 +128,7 @@ static ip_type ip_from_internal_list(char* name, size_t len) {
err_plus_unlock:
PDEBUG("return err\n");
return ip_type_invalid;
return ip_type_invalid.addr.v4;
}
/* stuff for communication with the allocator thread */
@@ -205,7 +205,7 @@ static void* threadfunc(void* x) {
struct at_msghdr msg;
union {
char host[MSG_LEN_MAX];
ip_type ip;
ip_type4 ip;
} readbuf;
while((ret = getmessage(ATD_SERVER, &msg, &readbuf))) {
switch(msg.msgtype) {
@@ -213,7 +213,7 @@ static void* threadfunc(void* x) {
/* client wants an ip for a DNS name. iterate our list and check if we have an existing entry.
* if not, create a new one. */
readbuf.ip = ip_from_internal_list(readbuf.host, msg.datalen - 1);
msg.datalen = sizeof(ip_type);
msg.datalen = sizeof(ip_type4);
break;
case ATM_GETNAME: {
char *host = string_from_internal_ip(readbuf.ip);
@@ -237,8 +237,8 @@ static void* threadfunc(void* x) {
/* API to access the internal ip mapping */
ip_type at_get_ip_for_host(char* host, size_t len) {
ip_type readbuf;
ip_type4 at_get_ip_for_host(char* host, size_t len) {
ip_type4 readbuf;
MUTEX_LOCK(&internal_ips_lock);
if(len > MSG_LEN_MAX) goto inv;
struct at_msghdr msg = {.msgtype = ATM_GETIP, .datalen = len + 1 };
@@ -246,14 +246,14 @@ ip_type at_get_ip_for_host(char* host, size_t len) {
getmessage(ATD_CLIENT, &msg, &readbuf));
else {
inv:
readbuf = ip_type_invalid;
readbuf = ip_type_invalid.addr.v4;
}
MUTEX_UNLOCK(&internal_ips_lock);
return readbuf;
}
size_t at_get_host_for_ip(ip_type ip, char* readbuf) {
struct at_msghdr msg = {.msgtype = ATM_GETNAME, .datalen = sizeof(ip_type) };
size_t at_get_host_for_ip(ip_type4 ip, char* readbuf) {
struct at_msghdr msg = {.msgtype = ATM_GETNAME, .datalen = sizeof(ip_type4) };
size_t res = 0;
MUTEX_LOCK(&internal_ips_lock);
if(sendmessage(ATD_SERVER, &msg, &ip) && getmessage(ATD_CLIENT, &msg, readbuf)) {
+2 -2
View File
@@ -11,8 +11,8 @@ extern int resp_pipefd[2];
void at_init(void);
void at_close(void);
size_t at_get_host_for_ip(ip_type ip, char* readbuf);
ip_type at_get_ip_for_host(char* host, size_t len);
size_t at_get_host_for_ip(ip_type4 ip, char* readbuf);
ip_type4 at_get_ip_for_host(char* host, size_t len);
//RcB: DEP "allocator_thread.c"
#endif
+214 -211
View File
@@ -198,8 +198,8 @@ static int tunnel_to(int sock, ip_type ip, unsigned short port, proxy_type pt, c
// the range 224-255.* is reserved, and it won't go outside (unless the app does some other stuff with
// the results returned from gethostbyname et al.)
// the hardcoded number 224 can now be changed using the config option remote_dns_subnet to i.e. 127
if(ip.octet[0] == remote_dns_subnet) {
dns_len = at_get_host_for_ip(ip, hostnamebuf);
if(!ip.is_v6 && ip.addr.v4.octet[0] == remote_dns_subnet) {
dns_len = at_get_host_for_ip(ip.addr.v4, hostnamebuf);
if(!dns_len) goto err;
else dns_name = hostnamebuf;
}
@@ -216,209 +216,198 @@ static int tunnel_to(int sock, ip_type ip, unsigned short port, proxy_type pt, c
int len;
unsigned char buff[BUFF_SIZE];
char ip_buf[16];
char ip_buf[INET6_ADDRSTRLEN];
int v6 = ip.is_v6;
//memset (buff, 0, sizeof(buff));
switch (pt) {
case HTTP_TYPE:{
if(!dns_len) {
pc_stringfromipv4(&ip.octet[0], ip_buf);
dns_name = ip_buf;
}
snprintf((char *) buff, sizeof(buff), "CONNECT %s:%d HTTP/1.0\r\n", dns_name,
ntohs(port));
if(user[0]) {
#define HTTP_AUTH_MAX ((0xFF * 2) + 1 + 1)
// 2 * 0xff: username and pass, plus 1 for ':' and 1 for zero terminator.
char src[HTTP_AUTH_MAX];
char dst[(4 * HTTP_AUTH_MAX)];
memcpy(src, user, ulen);
memcpy(src + ulen, ":", 1);
memcpy(src + ulen + 1, pass, passlen);
src[ulen + 1 + passlen] = 0;
encode_base_64(src, dst, sizeof(dst));
strcat((char *) buff, "Proxy-Authorization: Basic ");
strcat((char *) buff, dst);
strcat((char *) buff, "\r\n\r\n");
} else
strcat((char *) buff, "\r\n");
len = strlen((char *) buff);
if(len != send(sock, buff, len, 0))
if(!dns_len) {
if(!inet_ntop(v6?AF_INET6:AF_INET,ip.addr.v6,ip_buf,sizeof ip_buf)) {
proxychains_write_log(LOG_PREFIX "error: ip address conversion failed\n");
goto err;
len = 0;
// read header byte by byte.
while(len < BUFF_SIZE) {
if(1 == read_n_bytes(sock, (char *) (buff + len), 1))
len++;
else
goto err;
if(len > 4 &&
buff[len - 1] == '\n' &&
buff[len - 2] == '\r' && buff[len - 3] == '\n' && buff[len - 4] == '\r')
break;
}
// if not ok (200) or response greather than BUFF_SIZE return BLOCKED;
if(len == BUFF_SIZE || !(buff[9] == '2' && buff[10] == '0' && buff[11] == '0')) {
PDEBUG("HTTP proxy blocked: buff=\"%s\"\n", buff);
return BLOCKED;
}
return SUCCESS;
dns_name = ip_buf;
}
break;
#define HTTP_AUTH_MAX ((0xFF * 2) + 1 + 1) /* 2 * 0xff: username and pass, plus 1 for ':' and 1 for zero terminator. */
char src[HTTP_AUTH_MAX];
char dst[(4 * HTTP_AUTH_MAX)];
if(ulen) {
snprintf(src, sizeof(src), "%s:%s", user, pass);
encode_base_64(src, dst, sizeof(dst));
} else dst[0] = 0;
uint16_t hs_port = ntohs(port);
len = snprintf((char *) buff, sizeof(buff),
"CONNECT %s:%d HTTP/1.0\r\nHost: %s:%d\r\n%s%s%s\r\n",
dns_name, hs_port,
dns_name, hs_port,
ulen ? "Proxy-Authorization: Basic " : dst,
dst, ulen ? "\r\n" : dst);
if(len < 0 || len != send(sock, buff, len, 0))
goto err;
len = 0;
// read header byte by byte.
while(len < BUFF_SIZE) {
if(1 == read_n_bytes(sock, (char *) (buff + len), 1))
len++;
else
goto err;
if(len > 4 &&
buff[len - 1] == '\n' &&
buff[len - 2] == '\r' && buff[len - 3] == '\n' && buff[len - 4] == '\r')
break;
}
// if not ok (200) or response greather than BUFF_SIZE return BLOCKED;
if(len == BUFF_SIZE || !(buff[9] == '2' && buff[10] == '0' && buff[11] == '0')) {
PDEBUG("HTTP proxy blocked: buff=\"%s\"\n", buff);
return BLOCKED;
}
return SUCCESS;
}
break;
case SOCKS4_TYPE:{
buff[0] = 4; // socks version
buff[1] = 1; // connect command
memcpy(&buff[2], &port, 2); // dest port
if(dns_len) {
ip.octet[0] = 0;
ip.octet[1] = 0;
ip.octet[2] = 0;
ip.octet[3] = 1;
}
memcpy(&buff[4], &ip, 4); // dest host
len = ulen + 1; // username
if(len > 1)
memcpy(&buff[8], user, len);
else {
buff[8] = 0;
}
// do socksv4a dns resolution on the server
if(dns_len) {
memcpy(&buff[8 + len], dns_name, dns_len + 1);
len += dns_len + 1;
}
if((len + 8) != write_n_bytes(sock, (char *) buff, (8 + len)))
goto err;
if(8 != read_n_bytes(sock, (char *) buff, 8))
goto err;
if(buff[0] != 0 || buff[1] != 90)
return BLOCKED;
return SUCCESS;
if(v6) {
proxychains_write_log(LOG_PREFIX "error: SOCKS4 doesn't support ipv6 addresses\n");
goto err;
}
break;
buff[0] = 4; // socks version
buff[1] = 1; // connect command
memcpy(&buff[2], &port, 2); // dest port
if(dns_len) {
ip.addr.v4.octet[0] = 0;
ip.addr.v4.octet[1] = 0;
ip.addr.v4.octet[2] = 0;
ip.addr.v4.octet[3] = 1;
}
memcpy(&buff[4], &ip.addr.v4, 4); // dest host
len = ulen + 1; // username
if(len > 1)
memcpy(&buff[8], user, len);
else {
buff[8] = 0;
}
// do socksv4a dns resolution on the server
if(dns_len) {
memcpy(&buff[8 + len], dns_name, dns_len + 1);
len += dns_len + 1;
}
if((len + 8) != write_n_bytes(sock, (char *) buff, (8 + len)))
goto err;
if(8 != read_n_bytes(sock, (char *) buff, 8))
goto err;
if(buff[0] != 0 || buff[1] != 90)
return BLOCKED;
return SUCCESS;
}
break;
case SOCKS5_TYPE:{
if(user) {
buff[0] = 5; //version
buff[1] = 2; //nomber of methods
buff[2] = 0; // no auth method
buff[3] = 2; /// auth method -> username / password
if(4 != write_n_bytes(sock, (char *) buff, 4))
goto err;
} else {
buff[0] = 5; //version
buff[1] = 1; //nomber of methods
buff[2] = 0; // no auth method
if(3 != write_n_bytes(sock, (char *) buff, 3))
goto err;
}
int n_methods = ulen ? 2 : 1;
buff[0] = 5; // version
buff[1] = n_methods ; // number of methods
buff[2] = 0; // no auth method
if(ulen) buff[3] = 2; /// auth method -> username / password
if(2+n_methods != write_n_bytes(sock, (char *) buff, 2+n_methods))
goto err;
if(2 != read_n_bytes(sock, (char *) buff, 2))
if(2 != read_n_bytes(sock, (char *) buff, 2))
goto err;
if(buff[0] != 5 || (buff[1] != 0 && buff[1] != 2)) {
if(buff[0] == 5 && buff[1] == 0xFF)
return BLOCKED;
else
goto err;
if(buff[0] != 5 || (buff[1] != 0 && buff[1] != 2)) {
if(buff[0] == 5 && buff[1] == 0xFF)
return BLOCKED;
else
goto err;
}
if(buff[1] == 2) {
// authentication
char in[2];
char out[515];
char *cur = out;
size_t c;
*cur++ = 1; // version
c = ulen & 0xFF;
*cur++ = c;
memcpy(cur, user, c);
cur += c;
c = passlen & 0xFF;
*cur++ = c;
memcpy(cur, pass, c);
cur += c;
if((cur - out) != write_n_bytes(sock, out, cur - out))
goto err;
if(2 != read_n_bytes(sock, in, 2))
goto err;
if(in[0] != 1 || in[1] != 0) {
if(in[0] != 1)
goto err;
else
return BLOCKED;
}
}
int buff_iter = 0;
buff[buff_iter++] = 5; // version
buff[buff_iter++] = 1; // connect
buff[buff_iter++] = 0; // reserved
if(!dns_len) {
buff[buff_iter++] = 1; // ip v4
memcpy(buff + buff_iter, &ip, 4); // dest host
buff_iter += 4;
} else {
buff[buff_iter++] = 3; //dns
buff[buff_iter++] = dns_len & 0xFF;
memcpy(buff + buff_iter, dns_name, dns_len);
buff_iter += dns_len;
}
memcpy(buff + buff_iter, &port, 2); // dest port
buff_iter += 2;
if(buff_iter != write_n_bytes(sock, (char *) buff, buff_iter))
goto err;
if(4 != read_n_bytes(sock, (char *) buff, 4))
goto err;
if(buff[0] != 5 || buff[1] != 0)
goto err;
switch (buff[3]) {
case 1:
len = 4;
break;
case 4:
len = 16;
break;
case 3:
len = 0;
if(1 != read_n_bytes(sock, (char *) &len, 1))
goto err;
break;
default:
goto err;
}
if(len + 2 != read_n_bytes(sock, (char *) buff, len + 2))
goto err;
return SUCCESS;
}
break;
if(buff[1] == 2) {
// authentication
char in[2];
char out[515];
char *cur = out;
size_t c;
*cur++ = 1; // version
c = ulen & 0xFF;
*cur++ = c;
memcpy(cur, user, c);
cur += c;
c = passlen & 0xFF;
*cur++ = c;
memcpy(cur, pass, c);
cur += c;
if((cur - out) != write_n_bytes(sock, out, cur - out))
goto err;
if(2 != read_n_bytes(sock, in, 2))
goto err;
if(in[0] != 1 || in[1] != 0) {
if(in[0] != 1)
goto err;
else
return BLOCKED;
}
}
int buff_iter = 0;
buff[buff_iter++] = 5; // version
buff[buff_iter++] = 1; // connect
buff[buff_iter++] = 0; // reserved
if(!dns_len) {
buff[buff_iter++] = v6 ? 4 : 1; // ip v4/v6
memcpy(buff + buff_iter, ip.addr.v6, v6?16:4); // dest host
buff_iter += v6?16:4;
} else {
buff[buff_iter++] = 3; //dns
buff[buff_iter++] = dns_len & 0xFF;
memcpy(buff + buff_iter, dns_name, dns_len);
buff_iter += dns_len;
}
memcpy(buff + buff_iter, &port, 2); // dest port
buff_iter += 2;
if(buff_iter != write_n_bytes(sock, (char *) buff, buff_iter))
goto err;
if(4 != read_n_bytes(sock, (char *) buff, 4))
goto err;
if(buff[0] != 5 || buff[1] != 0)
goto err;
switch (buff[3]) {
case 1:
len = 4;
break;
case 4:
len = 16;
break;
case 3:
len = 0;
if(1 != read_n_bytes(sock, (char *) &len, 1))
goto err;
break;
default:
goto err;
}
if(len + 2 != read_n_bytes(sock, (char *) buff, len + 2))
goto err;
return SUCCESS;
}
break;
}
err:
@@ -432,22 +421,30 @@ static int tunnel_to(int sock, ip_type ip, unsigned short port, proxy_type pt, c
#define RRT "Round Robin chain"
static int start_chain(int *fd, proxy_data * pd, char *begin_mark) {
struct sockaddr_in addr;
char ip_buf[16];
int v6 = pd->ip.is_v6;
*fd = socket(PF_INET, SOCK_STREAM, 0);
*fd = socket(v6?PF_INET6:PF_INET, SOCK_STREAM, 0);
if(*fd == -1)
goto error;
pc_stringfromipv4(&pd->ip.octet[0], ip_buf);
char ip_buf[INET6_ADDRSTRLEN];
if(!inet_ntop(v6?AF_INET6:AF_INET,pd->ip.addr.v6,ip_buf,sizeof ip_buf))
goto error;
proxychains_write_log(LOG_PREFIX "%s " TP " %s:%d ",
begin_mark, ip_buf, htons(pd->port));
pd->ps = PLAY_STATE;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = (in_addr_t) pd->ip.as_int;
addr.sin_port = pd->port;
if(timed_connect(*fd, (struct sockaddr *) &addr, sizeof(addr))) {
struct sockaddr_in addr = {
.sin_family = AF_INET,
.sin_port = pd->port,
.sin_addr.s_addr = (in_addr_t) pd->ip.addr.v4.as_int
};
struct sockaddr_in6 addr6 = {
.sin6_family = AF_INET6,
.sin6_port = pd->port,
};
if(v6) memcpy(&addr6.sin6_addr.s6_addr, pd->ip.addr.v6, 16);
if(timed_connect(*fd, (struct sockaddr *) (v6?(void*)&addr6:(void*)&addr), v6?sizeof(addr6):sizeof(addr))) {
pd->ps = DOWN_STATE;
goto error1;
}
@@ -469,7 +466,7 @@ static proxy_data *select_proxy(select_type how, proxy_data * pd, unsigned int p
case RANDOMLY:
do {
k++;
i = 0 + (unsigned int) (proxy_count * 1.0 * rand() / (RAND_MAX + 1.0));
i = rand() % proxy_count;
} while(pd[i].ps != PLAY_STATE && k < proxy_count * 100);
break;
case FIFOLY:
@@ -518,16 +515,22 @@ static int chain_step(int ns, proxy_data * pfrom, proxy_data * pto) {
int retcode = -1;
char *hostname;
char hostname_buf[MSG_LEN_MAX];
char ip_buf[16];
char ip_buf[INET6_ADDRSTRLEN];
int v6 = pto->ip.is_v6;
PFUNC();
if(pto->ip.octet[0] == remote_dns_subnet) {
if(!at_get_host_for_ip(pto->ip, hostname_buf)) goto usenumericip;
if(!v6 && pto->ip.addr.v4.octet[0] == remote_dns_subnet) {
if(!at_get_host_for_ip(pto->ip.addr.v4, hostname_buf)) goto usenumericip;
else hostname = hostname_buf;
} else {
usenumericip:
pc_stringfromipv4(&pto->ip.octet[0], ip_buf);
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;
}
hostname = ip_buf;
}
@@ -729,7 +732,7 @@ static void gethostbyname_data_setstring(struct gethostbyname_data* data, char*
data->hostent_space.h_name = data->addr_name;
}
extern ip_type hostsreader_get_numeric_ip_for_name(const char* name);
extern ip_type4 hostsreader_get_numeric_ip_for_name(const char* name);
struct hostent *proxy_gethostbyname(const char *name, struct gethostbyname_data* data) {
PFUNC();
char buff[256];
@@ -750,19 +753,19 @@ struct hostent *proxy_gethostbyname(const char *name, struct gethostbyname_data*
if(!strcmp(buff, name)) {
data->resolved_addr = inet_addr(buff);
if(data->resolved_addr == (in_addr_t) (-1))
data->resolved_addr = (in_addr_t) (ip_type_localhost.as_int);
data->resolved_addr = (in_addr_t) (ip_type_localhost.addr.v4.as_int);
goto retname;
}
// this iterates over the "known hosts" db, usually /etc/hosts
ip_type hdb_res = hostsreader_get_numeric_ip_for_name(name);
if(hdb_res.as_int != ip_type_invalid.as_int) {
ip_type4 hdb_res = hostsreader_get_numeric_ip_for_name(name);
if(hdb_res.as_int != ip_type_invalid.addr.v4.as_int) {
data->resolved_addr = hdb_res.as_int;
goto retname;
}
data->resolved_addr = at_get_ip_for_host((char*) name, strlen(name)).as_int;
if(data->resolved_addr == (in_addr_t) ip_type_invalid.as_int) return NULL;
if(data->resolved_addr == (in_addr_t) ip_type_invalid.addr.v4.as_int) return NULL;
retname:
+12 -2
View File
@@ -3,11 +3,15 @@
# include "core.h"
# include "common.h"
# include "debug.h"
#include <arpa/inet.h>
void DUMP_PROXY_CHAIN(proxy_data *pchain, unsigned int count) {
char ip_buf[16];
char ip_buf[INET6_ADDRSTRLEN];
for (; count; pchain++, count--) {
pc_stringfromipv4(&pchain->ip.octet[0], ip_buf);
if(!inet_ntop(pchain->ip.is_v6?AF_INET6:AF_INET,pchain->ip.addr.v6,ip_buf,sizeof ip_buf)) {
proxychains_write_log(LOG_PREFIX "error: ip address conversion failed\n");
continue;
}
PDEBUG("[%s] %s %s:%d", proxy_state_strmap[pchain->ps],
proxy_type_strmap[pchain->pt],
ip_buf, htons(pchain->port));
@@ -18,4 +22,10 @@ void DUMP_PROXY_CHAIN(proxy_data *pchain, unsigned int count) {
}
}
#else
// Do not allow this translation unit to end up empty
// for non-DEBUG builds, to satisfy ISO C standards.
typedef int __appease_iso_compilers__;
#endif
+2
View File
@@ -5,12 +5,14 @@
# include <stdio.h>
# define PSTDERR(fmt, args...) do { dprintf(2,fmt, ## args); } while(0)
# define PDEBUG(fmt, args...) PSTDERR("DEBUG:"fmt, ## args)
# define DEBUGDECL(args...) args
# include "core.h"
void DUMP_PROXY_CHAIN(proxy_data *pchain, unsigned int count);
#else
# define PDEBUG(fmt, args...) do {} while (0)
# define DEBUGDECL(args...)
# define DUMP_PROXY_CHAIN(args...) do {} while (0)
#endif
+8 -6
View File
@@ -44,7 +44,7 @@ int hostsreader_get(struct hostsreader *ctx, char* buf, size_t bufsize) {
l--;
}
if(!l || !*p) continue;
ctx->name = buf;
ctx->name = p;
while(*p && !isspace(*p) && l) {
p++;
l--;
@@ -73,22 +73,24 @@ char* hostsreader_get_ip_for_name(const char* name, char* buf, size_t bufsize) {
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
ip_type hostsreader_get_numeric_ip_for_name(const char* name) {
ip_type4 hostsreader_get_numeric_ip_for_name(const char* name) {
char *hres;
char buf[320];
if((hres = hostsreader_get_ip_for_name(name, buf, sizeof buf))) {
struct in_addr c;
inet_aton(hres, &c);
ip_type res;
ip_type4 res;
memcpy(res.octet, &c.s_addr, 4);
return res;
} else return ip_type_invalid;
} else return ip_type_invalid.addr.v4;
}
#ifdef HOSTSREADER_TEST
int main() {
#include "ip_type.c"
int main(int a, char**b) {
char buf[256];
char * ret = hostsreader_get_ip_for_name("goo", buf, sizeof buf);
if(a != 2) return 1;
char * ret = hostsreader_get_ip_for_name(b[1], buf, sizeof buf);
printf("%s\n", ret ? ret : "null");
}
#endif
+2 -2
View File
@@ -1,5 +1,5 @@
#include "ip_type.h"
const ip_type ip_type_invalid = { .as_int = -1 };
const ip_type ip_type_localhost = { {127, 0, 0, 1} };
const ip_type ip_type_invalid = { .addr.v4.as_int = -1 };
const ip_type ip_type_localhost = { .addr.v4.octet = {127, 0, 0, 1} };
+8
View File
@@ -6,6 +6,14 @@
typedef union {
unsigned char octet[4];
uint32_t as_int;
} ip_type4;
typedef struct {
union {
ip_type4 v4;
unsigned char v6[16];
} addr;
char is_v6;
} ip_type;
extern const ip_type ip_type_invalid;
+97 -65
View File
@@ -93,12 +93,26 @@ static void* load_sym(char* symname, void* proxyfunc) {
#define INIT() init_lib_wrapper(__FUNCTION__)
#define SETUP_SYM(X) do { true_ ## X = load_sym( # X, X ); } while(0)
#define SETUP_SYM(X) do { if (! true_ ## X ) true_ ## X = load_sym( # X, X ); } while(0)
#include "allocator_thread.h"
const char *proxychains_get_version(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);
SETUP_SYM(close);
}
static int close_fds[16];
static int close_fds_cnt = 0;
static void do_init(void) {
srand(time(NULL));
core_initialize();
@@ -110,29 +124,13 @@ static void do_init(void) {
proxychains_write_log(LOG_PREFIX "DLL init: proxychains-ng %s\n", proxychains_get_version());
SETUP_SYM(connect);
SETUP_SYM(sendto);
SETUP_SYM(gethostbyname);
SETUP_SYM(getaddrinfo);
SETUP_SYM(freeaddrinfo);
SETUP_SYM(gethostbyaddr);
SETUP_SYM(getnameinfo);
SETUP_SYM(close);
setup_hooks();
while(close_fds_cnt) true_close(close_fds[--close_fds_cnt]);
init_l = 1;
}
#if 0
/* FIXME this is currently unused.
* it is not strictly needed.
* maybe let it be called by a gcc destructor, if that doesnt
* have negative consequences (e.g. when a child calles exit) */
static void unload(void) {
at_close();
core_unload();
}
#endif
static void init_lib_wrapper(const char* caller) {
#ifndef DEBUG
(void) caller;
@@ -200,13 +198,14 @@ static void get_chain_data(proxy_data * pd, unsigned int *proxy_count, chain_typ
exit(1);
}
in_addr_t host_ip = inet_addr(host);
if(host_ip == INADDR_NONE) {
memset(&pd[count].ip, 0, sizeof(pd[count].ip));
pd[count].ip.is_v6 = !!strchr(host, ':');
pd[count].port = htons((unsigned short) port_n);
ip_type* host_ip = &pd[count].ip;
if(1 != inet_pton(host_ip->is_v6 ? AF_INET6 : AF_INET, host, host_ip->addr.v6)) {
fprintf(stderr, "proxy %s has invalid value or is not numeric\n", host);
exit(1);
}
pd[count].ip.as_int = (uint32_t) host_ip;
pd[count].port = htons((unsigned short) port_n);
if(!strcmp(type, "http")) {
pd[count].pt = HTTP_TYPE;
@@ -217,7 +216,7 @@ static void get_chain_data(proxy_data * pd, unsigned int *proxy_count, chain_typ
} else
goto inv;
if(pd[count].ip.as_int && port_n && pd[count].ip.as_int != (uint32_t) - 1)
if(port_n)
count++;
} else {
if(strstr(buff, "[ProxyList]")) {
@@ -235,7 +234,7 @@ static void get_chain_data(proxy_data * pd, unsigned int *proxy_count, chain_typ
} else if(strstr(buff, "tcp_connect_time_out")) {
sscanf(buff, "%s %d", user, &tcp_connect_time_out);
} else if(strstr(buff, "remote_dns_subnet")) {
sscanf(buff, "%s %d", user, &remote_dns_subnet);
sscanf(buff, "%s %u", user, &remote_dns_subnet);
if(remote_dns_subnet >= 256) {
fprintf(stderr,
"remote_dns_subnet: invalid value. requires a number between 0 and 255.\n");
@@ -286,6 +285,10 @@ static void get_chain_data(proxy_data * pd, unsigned int *proxy_count, chain_typ
char *pc;
int len;
pc = strchr(buff, '=');
if(!pc) {
fprintf(stderr, "error: missing equals sign '=' in chain_len directive.\n");
exit(1);
}
len = atoi(++pc);
proxychains_max_chain = (len ? len : 1);
} else if(strstr(buff, "quiet_mode")) {
@@ -296,7 +299,9 @@ static void get_chain_data(proxy_data * pd, unsigned int *proxy_count, chain_typ
}
}
}
#ifndef BROKEN_FCLOSE
fclose(file);
#endif
if(!count) {
fprintf(stderr, "error: no valid proxy found in config\n");
exit(1);
@@ -308,48 +313,67 @@ static void get_chain_data(proxy_data * pd, unsigned int *proxy_count, chain_typ
/******* HOOK FUNCTIONS *******/
int close(int fd) {
INIT();
if(!init_l) {
if(close_fds_cnt>=(sizeof close_fds/sizeof close_fds[0])) goto err;
close_fds[close_fds_cnt++] = fd;
errno = 0;
return 0;
}
/* prevent rude programs (like ssh) from closing our pipes */
if(fd != req_pipefd[0] && fd != req_pipefd[1] &&
fd != resp_pipefd[0] && fd != resp_pipefd[1]) {
return true_close(fd);
}
err:
errno = EBADF;
return -1;
}
static int is_v4inv6(const struct in6_addr *a) {
return a->s6_addr32[0] == 0 && a->s6_addr32[1] == 0 &&
a->s6_addr16[4] == 0 && a->s6_addr16[5] == 0xffff;
}
int connect(int sock, const struct sockaddr *addr, unsigned int len) {
INIT();
PFUNC();
int socktype = 0, flags = 0, ret = 0;
socklen_t optlen = 0;
ip_type dest_ip;
#ifdef DEBUG
char str[256];
#endif
DEBUGDECL(char str[256]);
struct in_addr *p_addr_in;
struct in6_addr *p_addr_in6;
unsigned short port;
size_t i;
int remote_dns_connect = 0;
INIT();
optlen = sizeof(socktype);
sa_family_t fam = SOCKFAMILY(*addr);
getsockopt(sock, SOL_SOCKET, SO_TYPE, &socktype, &optlen);
if(!(SOCKFAMILY(*addr) == AF_INET && socktype == SOCK_STREAM))
if(!((fam == AF_INET || fam == AF_INET6) && socktype == SOCK_STREAM))
return true_connect(sock, addr, len);
int v6 = dest_ip.is_v6 = fam == AF_INET6;
p_addr_in = &((struct sockaddr_in *) addr)->sin_addr;
port = ntohs(((struct sockaddr_in *) addr)->sin_port);
p_addr_in6 = &((struct sockaddr_in6 *) addr)->sin6_addr;
port = !v6 ? ntohs(((struct sockaddr_in *) addr)->sin_port)
: ntohs(((struct sockaddr_in6 *) addr)->sin6_port);
struct in_addr v4inv6;
if(v6 && is_v4inv6(p_addr_in6)) {
memcpy(&v4inv6.s_addr, &p_addr_in6->s6_addr32[3], 4);
v6 = dest_ip.is_v6 = 0;
p_addr_in = &v4inv6;
}
#ifdef DEBUG
// PDEBUG("localnet: %s; ", inet_ntop(AF_INET,&in_addr_localnet, str, sizeof(str)));
// PDEBUG("netmask: %s; " , inet_ntop(AF_INET, &in_addr_netmask, str, sizeof(str)));
PDEBUG("target: %s\n", inet_ntop(AF_INET, p_addr_in, str, sizeof(str)));
PDEBUG("target: %s\n", inet_ntop(v6 ? AF_INET6 : AF_INET, v6 ? (void*)p_addr_in6 : (void*)p_addr_in, str, sizeof(str)));
PDEBUG("port: %d\n", port);
#endif
// check if connect called from proxydns
remote_dns_connect = (ntohl(p_addr_in->s_addr) >> 24 == remote_dns_subnet);
remote_dns_connect = !v6 && (ntohl(p_addr_in->s_addr) >> 24 == remote_dns_subnet);
for(i = 0; i < num_localnet_addr && !remote_dns_connect; i++) {
if (!v6) for(i = 0; i < num_localnet_addr && !remote_dns_connect; i++) {
if((localnet_addr[i].in_addr.s_addr & localnet_addr[i].netmask.s_addr)
== (p_addr_in->s_addr & localnet_addr[i].netmask.s_addr)) {
if(!localnet_addr[i].port || localnet_addr[i].port == port) {
@@ -363,11 +387,11 @@ int connect(int sock, const struct sockaddr *addr, unsigned int len) {
if(flags & O_NONBLOCK)
fcntl(sock, F_SETFL, !O_NONBLOCK);
dest_ip.as_int = SOCKADDR(*addr);
memcpy(dest_ip.addr.v6, v6 ? (void*)p_addr_in6 : (void*)p_addr_in, v6?16:4);
ret = connect_proxy_chain(sock,
dest_ip,
SOCKPORT(*addr),
htons(port),
proxychains_pd, proxychains_proxy_count, proxychains_ct, proxychains_max_chain);
fcntl(sock, F_SETFL, flags);
@@ -379,7 +403,6 @@ int connect(int sock, const struct sockaddr *addr, unsigned int len) {
static struct gethostbyname_data ghbndata;
struct hostent *gethostbyname(const char *name) {
INIT();
PDEBUG("gethostbyname: %s\n", name);
if(proxychains_resolver)
@@ -391,72 +414,79 @@ struct hostent *gethostbyname(const char *name) {
}
int getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res) {
int ret = 0;
INIT();
PDEBUG("getaddrinfo: %s %s\n", node ? node : "null", service ? service : "null");
if(proxychains_resolver)
ret = proxy_getaddrinfo(node, service, hints, res);
return proxy_getaddrinfo(node, service, hints, res);
else
ret = true_getaddrinfo(node, service, hints, res);
return ret;
return true_getaddrinfo(node, service, hints, res);
}
void freeaddrinfo(struct addrinfo *res) {
INIT();
PDEBUG("freeaddrinfo %p \n", res);
PDEBUG("freeaddrinfo %p \n", (void *) res);
if(!proxychains_resolver)
true_freeaddrinfo(res);
else
proxy_freeaddrinfo(res);
return;
}
int pc_getnameinfo(const struct sockaddr *sa, socklen_t salen,
char *host, socklen_t hostlen, char *serv,
socklen_t servlen, int flags)
{
char ip_buf[16];
int ret = 0;
INIT();
PFUNC();
if(!proxychains_resolver) {
ret = true_getnameinfo(sa, salen, host, hostlen, serv, servlen, flags);
return true_getnameinfo(sa, salen, host, hostlen, serv, servlen, flags);
} else {
if(salen < sizeof(struct sockaddr_in) || SOCKFAMILY(*sa) != AF_INET)
if(!salen || !(SOCKFAMILY(*sa) == AF_INET || SOCKFAMILY(*sa) == AF_INET6))
return EAI_FAMILY;
int v6 = SOCKFAMILY(*sa) == AF_INET6;
if(salen < (v6?sizeof(struct sockaddr_in6):sizeof(struct sockaddr_in)))
return EAI_FAMILY;
if(hostlen) {
pc_stringfromipv4((unsigned char*) &(SOCKADDR_2(*sa)), ip_buf);
if(snprintf(host, hostlen, "%s", ip_buf) >= hostlen)
unsigned char v4inv6buf[4];
const void *ip = v6 ? (void*)&((struct sockaddr_in6*)sa)->sin6_addr
: (void*)&((struct sockaddr_in*)sa)->sin_addr;
unsigned scopeid = 0;
if(v6) {
if(is_v4inv6(&((struct sockaddr_in6*)sa)->sin6_addr)) {
memcpy(v4inv6buf, &((struct sockaddr_in6*)sa)->sin6_addr.s6_addr32[3], 4);
ip = v4inv6buf;
v6 = 0;
} else
scopeid = ((struct sockaddr_in6 *)sa)->sin6_scope_id;
}
if(!inet_ntop(v6?AF_INET6:AF_INET,ip,host,hostlen))
return EAI_OVERFLOW;
if(scopeid) {
size_t l = strlen(host);
if(snprintf(host+l, hostlen-l, "%%%u", scopeid) >= hostlen-l)
return EAI_OVERFLOW;
}
}
if(servlen) {
if(snprintf(serv, servlen, "%d", ntohs(SOCKPORT(*sa))) >= servlen)
return EAI_OVERFLOW;
}
}
return ret;
return 0;
}
struct hostent *gethostbyaddr(const void *addr, socklen_t len, int type) {
INIT();
PDEBUG("TODO: proper gethostbyaddr hook\n");
static char buf[16];
static char ipv4[4];
static char *list[2];
static char *aliases[1];
static struct hostent he;
INIT();
PDEBUG("TODO: proper gethostbyaddr hook\n");
if(!proxychains_resolver)
return true_gethostbyaddr(addr, len, type);
else {
@@ -485,6 +515,8 @@ struct hostent *gethostbyaddr(const void *addr, socklen_t len, int type) {
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen) {
INIT();
PFUNC();
if (flags & MSG_FASTOPEN) {
if (!connect(sockfd, dest_addr, addrlen) && errno != EINPROGRESS) {
return -1;
+1 -1
View File
@@ -24,7 +24,7 @@
static int usage(char **argv) {
printf("\nUsage:\t%s -q -f config_file program_name [arguments]\n"
"\t-q makes proxychains quiet - this overrides the config setting\n"
"\t-f allows to manually specify a configfile to use\n"
"\t-f allows one to manually specify a configfile to use\n"
"\tfor example : proxychains telnet somehost.com\n" "More help in README file\n\n", argv[0]);
return EXIT_FAILURE;
}
+62 -18
View File
@@ -11,73 +11,117 @@
#define SOCKPORT(x) (satosin(x)->sin_port)
#define SOCKFAMILY(x) (satosin(x)->sin_family)
#define ASSERT(X) { if(!(X)) printf("ASSERTION FAILED: %s @%s:%d\n", # X, __FILE__, __LINE__); }
#define CLR() { hbuf[0] = 0; sbuf[0] = 0; }
int main() {
struct sockaddr a = {0}, *sa = &a;
struct sockaddr_in a = {0}, *sa = &a;
char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
SOCKPORT(a) = htons(80);
memcpy( &( (struct sockaddr_in*) sa ) ->sin_addr , (char[]) {127,0,0,1}, 4);
a.sin_port = htons(80);
memcpy( &a.sin_addr , (char[]) {127,0,0,1}, 4);
int ret;
if ((ret = getnameinfo(sa, 0, hbuf, sizeof(hbuf), sbuf,
if ((ret = getnameinfo((void*)sa, 0, hbuf, sizeof(hbuf), sbuf,
sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV)) == 0)
printf("host=%s, serv=%s\n", hbuf, sbuf);
else
printf("%s\n", gai_strerror(ret));
assert(ret == EAI_FAMILY);
ASSERT(ret == EAI_FAMILY);
CLR();
if ((ret = getnameinfo(sa, sizeof a, hbuf, sizeof(hbuf), sbuf,
if ((ret = getnameinfo((void*)sa, sizeof a, hbuf, sizeof(hbuf), sbuf,
sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV)) == 0)
printf("host=%s, serv=%s\n", hbuf, sbuf);
else
printf("%s\n", gai_strerror(ret));
assert(ret == EAI_FAMILY);
ASSERT(ret == EAI_FAMILY);
CLR();
SOCKFAMILY(a) = AF_INET;
if ((ret = getnameinfo(sa, sizeof a, hbuf, 1, sbuf,
if ((ret = getnameinfo((void*)sa, sizeof a, hbuf, 1, sbuf,
sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV)) == 0)
printf("host=%s, serv=%s\n", hbuf, sbuf);
else
printf("%s\n", gai_strerror(ret));
assert(ret == EAI_OVERFLOW);
ASSERT(ret == EAI_OVERFLOW);
CLR();
if ((ret = getnameinfo(sa, sizeof a, hbuf, 0, sbuf,
if ((ret = getnameinfo((void*)sa, sizeof a, hbuf, 0, sbuf,
1, NI_NUMERICHOST | NI_NUMERICSERV)) == 0)
printf("host=%s, serv=%s\n", hbuf, sbuf);
else
printf("%s\n", gai_strerror(ret));
assert(ret == EAI_OVERFLOW);
ASSERT(ret == EAI_OVERFLOW);
CLR();
if ((ret = getnameinfo(sa, sizeof a, hbuf, 0, sbuf,
if ((ret = getnameinfo((void*)sa, sizeof(a) - 1, hbuf, 0, sbuf,
sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV)) == 0)
printf("host=%s, serv=%s\n", hbuf, sbuf);
else
printf("%s\n", gai_strerror(ret));
assert(ret == 0);
ASSERT(ret == EAI_FAMILY);
CLR();
if ((ret = getnameinfo(sa, sizeof a, hbuf, sizeof hbuf, sbuf,
if ((ret = getnameinfo((void*)sa, sizeof a, hbuf, 0, sbuf,
sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV)) == 0)
printf("host=%s, serv=%s\n", hbuf, sbuf);
else
printf("%s\n", gai_strerror(ret));
ASSERT(ret == 0 && !strcmp("80", sbuf));
CLR();
if ((ret = getnameinfo((void*)sa, sizeof a, hbuf, sizeof hbuf, sbuf,
0, NI_NUMERICHOST | NI_NUMERICSERV)) == 0)
printf("host=%s, serv=%s\n", hbuf, sbuf);
else
printf("%s\n", gai_strerror(ret));
assert(ret == 0);
ASSERT(ret == 0 && !strcmp("127.0.0.1",hbuf));
CLR();
if ((ret = getnameinfo(sa, sizeof a, hbuf, sizeof(hbuf), sbuf,
if ((ret = getnameinfo((void*)sa, sizeof a, hbuf, sizeof(hbuf), sbuf,
sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV)) == 0)
printf("host=%s, serv=%s\n", hbuf, sbuf);
else
printf("%s\n", gai_strerror(ret));
assert(ret == 0);
ASSERT(ret == 0 && !strcmp("127.0.0.1",hbuf) && !strcmp("80", sbuf));
CLR();
struct sockaddr_in6 b = {0}, *sb = &b;
b.sin6_port = htons(8080);
b.sin6_family = AF_INET6;
memcpy(&b.sin6_addr,"\0\0\0\0\0\0\0\0\0\0\xff\xff\xc0\xa8\1\2", 16);
if ((ret = getnameinfo((void*)sb, sizeof b, hbuf, sizeof(hbuf), sbuf,
sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV)) == 0)
printf("host=%s, serv=%s\n", hbuf, sbuf);
else
printf("%s\n", gai_strerror(ret));
ASSERT(ret == 0 && !strcmp("192.168.1.2",hbuf) && !strcmp("8080", sbuf));
CLR();
b.sin6_scope_id = 3;
memcpy(&b.sin6_addr,"\0\0\xaa\0\0\0\0\0\0\0\0\xff\xc0\xa8\1\2", 16);
if ((ret = getnameinfo((void*)sb, sizeof b, hbuf, sizeof(hbuf), sbuf,
sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV | NI_NUMERICSCOPE)) == 0)
printf("host=%s, serv=%s\n", hbuf, sbuf);
else
printf("%s\n", gai_strerror(ret));
ASSERT(ret == 0);
return 0;
}
+42
View File
@@ -0,0 +1,42 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/socket.h>
static void v4_to_v6(const struct in_addr *v4, struct in6_addr *v6) {
memset(v6, 0, sizeof(*v6));
v6->s6_addr[10]=0xff;
v6->s6_addr[11]=0xff;
memcpy(&v6->s6_addr[12], &v4->s_addr, 4);
}
int main(void) {
struct addrinfo *result;
struct addrinfo *res;
const struct addrinfo hints = { .ai_family = AF_INET };
int error, sock;
/* resolve the domain name into a list of addresses */
error = getaddrinfo("www.example.com", NULL, &hints, &result);
if (error != 0) {
fprintf(stderr, "error in getaddrinfo: %s\n", gai_strerror(error));
return EXIT_FAILURE;
}
if((sock=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
perror("socket");
return EXIT_FAILURE;
}
struct sockaddr_in6 a = { .sin6_family = AF_INET6,
.sin6_port = htons(80) };
v4_to_v6(&((struct sockaddr_in *)result->ai_addr)->sin_addr, &a.sin6_addr);
freeaddrinfo(result);
if((error = connect(sock, (struct sockaddr *)&a, sizeof(a))) == -1) {
perror("connect");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}