mirror of
https://github.com/rofl0r/proxychains-ng
synced 2026-05-14 01:12:34 +08:00
Compare commits
129 Commits
@@ -13,23 +13,29 @@ includedir = $(prefix)/include
|
|||||||
libdir = $(prefix)/lib
|
libdir = $(prefix)/lib
|
||||||
sysconfdir=$(prefix)/etc
|
sysconfdir=$(prefix)/etc
|
||||||
|
|
||||||
SRCS = $(sort $(wildcard src/*.c))
|
OBJS = src/common.o src/main.o
|
||||||
OBJS = $(SRCS:.c=.o)
|
|
||||||
|
DOBJS = src/daemon/hsearch.o \
|
||||||
|
src/daemon/sblist.o src/daemon/sblist_delete.o \
|
||||||
|
src/daemon/daemon.o src/daemon/udpserver.o
|
||||||
|
|
||||||
LOBJS = src/nameinfo.o src/version.o \
|
LOBJS = src/nameinfo.o src/version.o \
|
||||||
src/core.o src/common.o src/libproxychains.o src/shm.o \
|
src/core.o src/common.o src/libproxychains.o \
|
||||||
src/allocator_thread.o src/ip_type.o src/stringdump.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
|
||||||
|
|
||||||
|
|
||||||
GENH = src/version.h
|
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
|
LIBDL = -ldl
|
||||||
LDFLAGS = -fPIC $(NO_AS_NEEDED)
|
LDFLAGS = -fPIC $(NO_AS_NEEDED) $(LIBDL) -lpthread
|
||||||
INC =
|
INC =
|
||||||
PIC = -fPIC
|
PIC = -fPIC
|
||||||
AR = $(CROSS_COMPILE)ar
|
AR = $(CROSS_COMPILE)ar
|
||||||
RANLIB = $(CROSS_COMPILE)ranlib
|
RANLIB = $(CROSS_COMPILE)ranlib
|
||||||
|
SOCKET_LIBS =
|
||||||
|
|
||||||
LDSO_SUFFIX = so
|
LDSO_SUFFIX = so
|
||||||
LD_SET_SONAME = -Wl,-soname=
|
LD_SET_SONAME = -Wl,-soname=
|
||||||
@@ -40,13 +46,13 @@ LDSO_PATHNAME = libproxychains4.$(LDSO_SUFFIX)
|
|||||||
SHARED_LIBS = $(LDSO_PATHNAME)
|
SHARED_LIBS = $(LDSO_PATHNAME)
|
||||||
ALL_LIBS = $(SHARED_LIBS)
|
ALL_LIBS = $(SHARED_LIBS)
|
||||||
PXCHAINS = proxychains4
|
PXCHAINS = proxychains4
|
||||||
ALL_TOOLS = $(PXCHAINS)
|
PXCHAINS_D = proxychains4-daemon
|
||||||
|
ALL_TOOLS = $(PXCHAINS) $(PXCHAINS_D)
|
||||||
ALL_CONFIGS = src/proxychains.conf
|
ALL_CONFIGS = src/proxychains.conf
|
||||||
|
|
||||||
-include config.mak
|
-include config.mak
|
||||||
|
|
||||||
CFLAGS+=$(USER_CFLAGS) $(MAC_CFLAGS)
|
CFLAGS+=$(USER_CFLAGS) $(MAC_CFLAGS)
|
||||||
LDFLAGS+=$(USER_LDFLAGS)
|
|
||||||
CFLAGS_MAIN=-DLIB_DIR=\"$(libdir)\" -DSYSCONFDIR=\"$(sysconfdir)\" -DDLL_NAME=\"$(LDSO_PATHNAME)\"
|
CFLAGS_MAIN=-DLIB_DIR=\"$(libdir)\" -DSYSCONFDIR=\"$(sysconfdir)\" -DDLL_NAME=\"$(LDSO_PATHNAME)\"
|
||||||
|
|
||||||
|
|
||||||
@@ -70,7 +76,7 @@ install-config: $(ALL_CONFIGS:src/%=$(DESTDIR)$(sysconfdir)/%)
|
|||||||
clean:
|
clean:
|
||||||
rm -f $(ALL_LIBS)
|
rm -f $(ALL_LIBS)
|
||||||
rm -f $(ALL_TOOLS)
|
rm -f $(ALL_TOOLS)
|
||||||
rm -f $(OBJS)
|
rm -f $(OBJS) $(LOBJS) $(DOBJS)
|
||||||
rm -f $(GENH)
|
rm -f $(GENH)
|
||||||
|
|
||||||
src/version.h: $(wildcard VERSION .git)
|
src/version.h: $(wildcard VERSION .git)
|
||||||
@@ -82,10 +88,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) -shared $(LDFLAGS) $(LD_SET_SONAME)$(LDSO_PATHNAME) -lpthread $(LIBDL) -o $@ $(LOBJS)
|
$(CC) $(LDFLAGS) $(LD_SET_SONAME)$(LDSO_PATHNAME) $(USER_LDFLAGS) \
|
||||||
|
-shared -o $@ $^ $(SOCKET_LIBS)
|
||||||
|
|
||||||
$(ALL_TOOLS): $(OBJS)
|
$(PXCHAINS): $(OBJS)
|
||||||
$(CC) $(LDFLAGS) src/main.o src/common.o -o $(PXCHAINS)
|
$(CC) $^ $(USER_LDFLAGS) $(LIBDL) -o $@
|
||||||
|
|
||||||
|
$(PXCHAINS_D): $(DOBJS)
|
||||||
|
$(CC) $^ $(USER_LDFLAGS) -o $@
|
||||||
|
|
||||||
|
|
||||||
.PHONY: all clean install install-config install-libs install-tools
|
.PHONY: all clean install install-config install-libs install-tools
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
ProxyChains-NG ver 4.8 README
|
ProxyChains-NG ver 4.14 README
|
||||||
=============================
|
=============================
|
||||||
|
|
||||||
ProxyChains is a UNIX program, that hooks network-related libc functions
|
ProxyChains is a UNIX program, that hooks network-related libc functions
|
||||||
@@ -7,16 +7,16 @@ ProxyChains-NG ver 4.8 README
|
|||||||
It supports TCP only (no UDP/ICMP etc).
|
It supports TCP only (no UDP/ICMP etc).
|
||||||
|
|
||||||
The way it works is basically a HACK; so it is possible that it doesn't
|
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
|
numerous processes like background daemons or uses dlopen() to load
|
||||||
"modules" (bug in glibc dynlinker).
|
"modules" (bug in glibc dynlinker).
|
||||||
It should work with simple compiled (C/C++) dynamically linked programs
|
It should work with simple compiled (C/C++) dynamically linked programs
|
||||||
though.
|
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.
|
iptables based solution instead; this is much more robust.
|
||||||
|
|
||||||
Supported Platforms: Linux, BSD, Mac.
|
Supported Platforms: Linux, BSD, Mac, Haiku.
|
||||||
|
|
||||||
|
|
||||||
*********** ATTENTION ***********
|
*********** ATTENTION ***********
|
||||||
@@ -35,8 +35,8 @@ ProxyChains-NG ver 4.8 README
|
|||||||
|
|
||||||
ONLY USE PROXYCHAINS IF YOU KNOW WHAT YOU'RE DOING.
|
ONLY USE PROXYCHAINS IF YOU KNOW WHAT YOU'RE DOING.
|
||||||
|
|
||||||
THE AUTHORS AND MAINTAINERS OF PROXYCHAINS DO NOT TAKE ANY
|
THE AUTHORS AND MAINTAINERS OF PROXYCHAINS DO NOT TAKE ANY
|
||||||
RESPONSIBILITY FOR ANY ABUSE OR MISUSE OF THIS SOFTWARE AND
|
RESPONSIBILITY FOR ANY ABUSE OR MISUSE OF THIS SOFTWARE AND
|
||||||
THE RESULTING CONSEQUENCES.
|
THE RESULTING CONSEQUENCES.
|
||||||
|
|
||||||
*** Installation ***
|
*** Installation ***
|
||||||
@@ -52,6 +52,45 @@ ProxyChains-NG ver 4.8 README
|
|||||||
|
|
||||||
Changelog:
|
Changelog:
|
||||||
----------
|
----------
|
||||||
|
Version 4.14
|
||||||
|
- allow alternative proto://user:pass@ip:port syntax for proxylist
|
||||||
|
- fix endless loop in round robin mode when all proxies are down (#147)
|
||||||
|
- fix compilation on android (#265)
|
||||||
|
- fix fd leak in forked processes (#273)
|
||||||
|
- skip connection attempt to nullrouted ips
|
||||||
|
- allow hostnames for proxylist under specific circumstances
|
||||||
|
|
||||||
|
Version 4.13
|
||||||
|
- fix robustness of DNS lookup thread and a segfault
|
||||||
|
- fix socks5 user/pass auth on non-conforming servers
|
||||||
|
- fix memory leak
|
||||||
|
- add support for Solaris
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
Version 4.9
|
||||||
|
- fix a security issue CVE-2015-3887
|
||||||
|
- add sendto hook to handle MSG_FASTOPEN flag
|
||||||
|
- replace problematic hostentdb with hostsreader
|
||||||
|
- fix compilation on OpenBSD (although doesn't work there)
|
||||||
|
|
||||||
Version 4.8.1:
|
Version 4.8.1:
|
||||||
- fix regression in 4.8 install-config Makefile target
|
- fix regression in 4.8 install-config Makefile target
|
||||||
|
|
||||||
@@ -66,7 +105,7 @@ Version 4.7:
|
|||||||
- new round_robin chaintype by crass.
|
- new round_robin chaintype by crass.
|
||||||
- fix bug with lazy allocation when GCC constructor was not used.
|
- 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
|
- 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
|
it's legal for a program to retry close() calls when they receive
|
||||||
EINTR, which could cause an infinite loop, as seen in chromium.
|
EINTR, which could cause an infinite loop, as seen in chromium.
|
||||||
|
|
||||||
@@ -93,13 +132,13 @@ Version 4.2:
|
|||||||
- fixes compilation issues with ubuntu 12.04 toolchain
|
- fixes compilation issues with ubuntu 12.04 toolchain
|
||||||
- fixes segfault in rare codepath
|
- fixes segfault in rare codepath
|
||||||
|
|
||||||
Version 4.1
|
Version 4.1
|
||||||
- support for mac os x (all archs)
|
- 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).
|
(default).
|
||||||
|
|
||||||
Version 4.0
|
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.
|
binary to be present) with remote DNS lookup.
|
||||||
this speeds up any operation involving DNS, as the old script had to use TCP.
|
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.
|
additionally it allows to use .onion urls when used with TOR.
|
||||||
@@ -109,7 +148,7 @@ Version 4.0
|
|||||||
environment variables.
|
environment variables.
|
||||||
|
|
||||||
Version 3.0
|
Version 3.0
|
||||||
- support for DNS resolving through proxy
|
- support for DNS resolving through proxy
|
||||||
supports SOCKS4, SOCKS5 and HTTP CONNECT proxy servers.
|
supports SOCKS4, SOCKS5 and HTTP CONNECT proxy servers.
|
||||||
Auth-types: socks - "user/pass" , http - "basic".
|
Auth-types: socks - "user/pass" , http - "basic".
|
||||||
|
|
||||||
@@ -131,7 +170,7 @@ Some cool features:
|
|||||||
random order from the list ( user defined length of chain ).
|
random order from the list ( user defined length of chain ).
|
||||||
exact order (as they appear in the list )
|
exact order (as they appear in the list )
|
||||||
dynamic order (smart exclude dead proxies from chain)
|
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.
|
scanners, as long as they use standard libc functionality.
|
||||||
pcap based scanning does not work.
|
pcap based scanning does not work.
|
||||||
* You can use it with servers, like squid, sendmail, or whatever.
|
* You can use it with servers, like squid, sendmail, or whatever.
|
||||||
@@ -159,9 +198,9 @@ specified by proxychains.conf
|
|||||||
|
|
||||||
Usage Example:
|
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.
|
to connect to targethost2.com host.
|
||||||
|
|
||||||
Usage Example:
|
Usage Example:
|
||||||
@@ -171,6 +210,30 @@ Usage Example:
|
|||||||
in this example it will resolve targethost.com through proxy(or chained proxies)
|
in this example it will resolve targethost.com through proxy(or chained proxies)
|
||||||
specified by proxychains.conf
|
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:
|
Community:
|
||||||
----------
|
----------
|
||||||
#proxychains on irc.freenode.net
|
#proxychains on irc.freenode.net
|
||||||
|
|||||||
@@ -1,28 +1,77 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
prefix=/usr/local
|
prefix=/usr/local
|
||||||
|
OUR_CPPFLAGS=
|
||||||
|
|
||||||
ismac() {
|
# Get a temporary filename
|
||||||
uname -s | grep Darwin >/dev/null
|
fail() { printf "%s\n" "$1" >&2 ; exit 1 ; }
|
||||||
|
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
|
||||||
|
|
||||||
|
check_compile() {
|
||||||
|
printf "checking %s ... " "$1"
|
||||||
|
printf "$3" > "$tmpc"
|
||||||
|
local res=0
|
||||||
|
$CC $OUR_CPPFLAGS $CPPFLAGS $2 $CFLAGS "$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
|
||||||
}
|
}
|
||||||
|
|
||||||
isx86_64() {
|
check_define() {
|
||||||
uname -m | grep -i X86_64 >/dev/null
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
isbsd() {
|
check_compile_run() {
|
||||||
uname -s | grep BSD >/dev/null
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
check_link_silent() {
|
||||||
|
printf "$2" > "$tmpc"
|
||||||
|
$CC $OUR_CPPFLAGS $CPPFLAGS $1 $CFLAGS "$tmpc" -o /dev/null >/dev/null 2>&1
|
||||||
|
}
|
||||||
|
|
||||||
|
check_link() {
|
||||||
|
printf "checking %s ... " "$1"
|
||||||
|
local res=0
|
||||||
|
check_link_silent "$2" "$3" || res=1
|
||||||
|
test x$res = x0 && printf "yes\n" || printf "no\n"
|
||||||
|
return $res
|
||||||
}
|
}
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
echo "supported arguments"
|
echo "supported arguments"
|
||||||
echo "--prefix=/path default: $prefix"
|
echo "--prefix=/path default: $prefix"
|
||||||
echo "--exec_prefix=/path default: $prefix/bin"
|
echo "--exec_prefix=/path default: $prefix/bin"
|
||||||
echo "--bindir=/path default: $prefix/bin"
|
echo "--bindir=/path default: $prefix/bin"
|
||||||
echo "--libdir=/path default: $prefix/lib"
|
echo "--libdir=/path default: $prefix/lib"
|
||||||
echo "--includedir=/path default: $prefix/include"
|
echo "--includedir=/path default: $prefix/include"
|
||||||
echo "--sysconfdir=/path default: $prefix/etc"
|
echo "--sysconfdir=/path default: $prefix/etc"
|
||||||
ismac && isx86_64 && echo "--fat-binary : build for both i386 and x86_64 architectures on 64-bit Macs"
|
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)"
|
||||||
|
echo "--fat-binary : build for both i386 and x86_64 architectures on 64-bit Macs"
|
||||||
echo "--help : show this text"
|
echo "--help : show this text"
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
@@ -35,7 +84,7 @@ spliteq() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fat_binary=
|
fat_binary=
|
||||||
|
ignore_cve=no
|
||||||
parsearg() {
|
parsearg() {
|
||||||
case "$1" in
|
case "$1" in
|
||||||
--prefix=*) prefix=`spliteq $1`;;
|
--prefix=*) prefix=`spliteq $1`;;
|
||||||
@@ -44,6 +93,8 @@ parsearg() {
|
|||||||
--libdir=*) libdir=`spliteq $1`;;
|
--libdir=*) libdir=`spliteq $1`;;
|
||||||
--includedir=*) includedir=`spliteq $1`;;
|
--includedir=*) includedir=`spliteq $1`;;
|
||||||
--sysconfdir=*) sysconfdir=`spliteq $1`;;
|
--sysconfdir=*) sysconfdir=`spliteq $1`;;
|
||||||
|
--ignore-cve) ignore_cve=1;;
|
||||||
|
--ignore-cve=*) ignore_cve=`spliteq $1`;;
|
||||||
--fat-binary) fat_binary=1;;
|
--fat-binary) fat_binary=1;;
|
||||||
--help) usage;;
|
--help) usage;;
|
||||||
esac
|
esac
|
||||||
@@ -80,31 +131,102 @@ if [ -z "$CC" ] ; then
|
|||||||
CC=cc
|
CC=cc
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo CC?=$CC>config.mak
|
echo > config.mak
|
||||||
[ -z "$CPPFLAGS" ] || echo CPPFLAGS?=$CPPFLAGS>>config.mak
|
|
||||||
[ -z "$CFLAGS" ] || echo USER_CFLAGS?=$CFLAGS>>config.mak
|
bsd_detected=false
|
||||||
[ -z "$LDFLAGS" ] || echo USER_LDFLAGS?=$LDFLAGS>>config.mak
|
isbsd() {
|
||||||
|
$bsd_detected
|
||||||
|
}
|
||||||
|
mac_detected=false
|
||||||
|
ismac() {
|
||||||
|
$mac_detected
|
||||||
|
}
|
||||||
|
mac_64=false
|
||||||
|
ismac64() {
|
||||||
|
$mac_64
|
||||||
|
}
|
||||||
|
solaris_detected=false
|
||||||
|
issolaris() {
|
||||||
|
$solaris_detected
|
||||||
|
}
|
||||||
|
haiku_detected=false
|
||||||
|
ishaiku() {
|
||||||
|
$haiku_detected
|
||||||
|
}
|
||||||
|
|
||||||
|
check_compile 'whether C compiler works' '' 'int main() {return 0;}' || fail 'error: install a C compiler and library'
|
||||||
|
|
||||||
|
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;}'
|
||||||
|
|
||||||
|
check_compile 'whether we have pipe2() and O_CLOEXEC' "-DHAVE_PIPE2" \
|
||||||
|
'#define _GNU_SOURCE\n#include <fcntl.h>\n#include <unistd.h>\nint main() {\nint pipefd[2];\npipe2(pipefd, O_CLOEXEC);\nreturn 0;}'
|
||||||
|
|
||||||
|
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);}'
|
||||||
|
|
||||||
|
check_define __APPLE__ && {
|
||||||
|
mac_detected=true
|
||||||
|
check_define __x86_64__ && mac_64=true
|
||||||
|
}
|
||||||
|
check_define __FreeBSD__ && bsd_detected=true
|
||||||
|
check_define __OpenBSD__ && {
|
||||||
|
bsd_detected=true
|
||||||
|
echo "CFLAGS+=-DIS_OPENBSD">>config.mak
|
||||||
|
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"
|
||||||
|
}
|
||||||
|
check_define __sun && check_define __SVR4 && solaris_detected=true
|
||||||
|
check_define __HAIKU__ && haiku_detected=true
|
||||||
|
|
||||||
|
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 prefix=$prefix>>config.mak
|
||||||
echo exec_prefix=$exec_prefix>>config.mak
|
echo exec_prefix=$exec_prefix>>config.mak
|
||||||
echo bindir=$bindir>>config.mak
|
echo bindir=$bindir>>config.mak
|
||||||
echo libdir=$libdir>>config.mak
|
echo libdir=$libdir>>config.mak
|
||||||
echo includedir=$includedir>>config.mak
|
echo includedir=$includedir>>config.mak
|
||||||
echo sysconfdir=$sysconfdir>>config.mak
|
echo sysconfdir=$sysconfdir>>config.mak
|
||||||
|
[ "$ignore_cve" = "no" ] && echo "CPPFLAGS+= -DSUPER_SECURE">>config.mak
|
||||||
|
[ -z "$OUR_CPPFLAGS" ] || echo "CPPFLAGS+= $OUR_CPPFLAGS" >>config.mak
|
||||||
|
|
||||||
|
check_link "whether we can use -Wl,--no-as-needed" "-Wl,--no-as-needed" \
|
||||||
|
"int main() { return 0; }" || echo NO_AS_NEEDED= >> config.mak
|
||||||
|
|
||||||
|
LD_SONAME_FLAG=
|
||||||
|
printf "checking what's the option to use in linker to set library name ... "
|
||||||
|
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
|
||||||
|
done
|
||||||
|
if [ -z "$LD_SONAME_FLAG" ]; then
|
||||||
|
printf '\ncannot find an option to set library name\n'
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "$LD_SONAME_FLAG"
|
||||||
|
echo "LD_SET_SONAME = -Wl,$LD_SONAME_FLAG," >> config.mak
|
||||||
|
|
||||||
make_cmd=make
|
make_cmd=make
|
||||||
if ismac ; then
|
if ismac ; then
|
||||||
echo NO_AS_NEEDED=>>config.mak
|
|
||||||
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 isx86_64 && [ "$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 LDFLAGS+=-arch i386 -arch x86_64>>config.mak
|
||||||
fi
|
fi
|
||||||
echo LD_SET_SONAME=-Wl,-install_name,>>config.mak
|
|
||||||
elif isbsd ; then
|
elif isbsd ; then
|
||||||
echo LIBDL=>>config.mak
|
echo LIBDL=>>config.mak
|
||||||
echo "CFLAGS+=-DIS_BSD">>config.mak
|
echo "CFLAGS+=-DIS_BSD">>config.mak
|
||||||
make_cmd=gmake
|
make_cmd=gmake
|
||||||
|
elif issolaris; then
|
||||||
|
echo "CFLAGS+=-DIS_SOLARIS -D__EXTENSIONS__" >> config.mak
|
||||||
|
echo "SOCKET_LIBS=-lsocket -lnsl" >> config.mak
|
||||||
|
elif ishaiku ; then
|
||||||
|
echo LIBDL=>>config.mak
|
||||||
|
echo "CFLAGS+=-DIS_HAIKU" >> config.mak
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "Done, now run $make_cmd && $make_cmd install"
|
echo "Done, now run $make_cmd && $make_cmd install"
|
||||||
|
|||||||
Vendored
-11
@@ -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
|
|
||||||
|
|
||||||
+143
-79
@@ -1,3 +1,8 @@
|
|||||||
|
#undef _GNU_SOURCE
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
#undef _POSIX_C_SOURCE
|
||||||
|
#define _DARWIN_C_SOURCE
|
||||||
|
#include <limits.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
@@ -9,13 +14,13 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
#include "allocator_thread.h"
|
#include "allocator_thread.h"
|
||||||
#include "shm.h"
|
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "ip_type.h"
|
#include "ip_type.h"
|
||||||
#include "mutex.h"
|
#include "mutex.h"
|
||||||
#include "hash.h"
|
#include "hash.h"
|
||||||
#include "stringdump.h"
|
#include "remotedns.h"
|
||||||
|
|
||||||
/* stuff for our internal translation table */
|
/* stuff for our internal translation table */
|
||||||
|
|
||||||
@@ -30,20 +35,25 @@ typedef struct {
|
|||||||
string_hash_tuple** list;
|
string_hash_tuple** list;
|
||||||
} internal_ip_lookup_table;
|
} internal_ip_lookup_table;
|
||||||
|
|
||||||
pthread_mutex_t internal_ips_lock;
|
static void *dumpstring(char* s, size_t len) {
|
||||||
internal_ip_lookup_table *internal_ips = NULL;
|
char* p = malloc(len);
|
||||||
internal_ip_lookup_table internal_ips_buf;
|
if(p) memcpy(p, s, len);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t index_from_internal_ip(ip_type internalip) {
|
static pthread_mutex_t *internal_ips_lock;
|
||||||
|
static internal_ip_lookup_table *internal_ips;
|
||||||
|
|
||||||
|
uint32_t index_from_internal_ip(ip_type4 internalip) {
|
||||||
PFUNC();
|
PFUNC();
|
||||||
ip_type tmp = internalip;
|
ip_type4 tmp = internalip;
|
||||||
uint32_t ret;
|
uint32_t ret;
|
||||||
ret = tmp.octet[3] + (tmp.octet[2] << 8) + (tmp.octet[1] << 16);
|
ret = tmp.octet[3] + (tmp.octet[2] << 8) + (tmp.octet[1] << 16);
|
||||||
ret -= 1;
|
ret -= 1;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *string_from_internal_ip(ip_type internalip) {
|
char *string_from_internal_ip(ip_type4 internalip) {
|
||||||
PFUNC();
|
PFUNC();
|
||||||
char *res = NULL;
|
char *res = NULL;
|
||||||
uint32_t index = index_from_internal_ip(internalip);
|
uint32_t index = index_from_internal_ip(internalip);
|
||||||
@@ -53,11 +63,11 @@ char *string_from_internal_ip(ip_type internalip) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
extern unsigned int remote_dns_subnet;
|
extern unsigned int remote_dns_subnet;
|
||||||
ip_type make_internal_ip(uint32_t index) {
|
ip_type4 make_internal_ip(uint32_t index) {
|
||||||
ip_type ret;
|
ip_type4 ret;
|
||||||
index++; // so we can start at .0.0.1
|
index++; // so we can start at .0.0.1
|
||||||
if(index > 0xFFFFFF)
|
if(index > 0xFFFFFF)
|
||||||
return ip_type_invalid;
|
return IPT4_INVALID;
|
||||||
ret.octet[0] = remote_dns_subnet & 0xFF;
|
ret.octet[0] = remote_dns_subnet & 0xFF;
|
||||||
ret.octet[1] = (index & 0xFF0000) >> 16;
|
ret.octet[1] = (index & 0xFF0000) >> 16;
|
||||||
ret.octet[2] = (index & 0xFF00) >> 8;
|
ret.octet[2] = (index & 0xFF00) >> 8;
|
||||||
@@ -65,10 +75,10 @@ ip_type make_internal_ip(uint32_t index) {
|
|||||||
return ret;
|
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);
|
uint32_t hash = dalias_hash((char *) name);
|
||||||
size_t i;
|
size_t i;
|
||||||
ip_type res;
|
ip_type4 res;
|
||||||
void* new_mem;
|
void* new_mem;
|
||||||
// see if we already have this dns entry saved.
|
// see if we already have this dns entry saved.
|
||||||
if(internal_ips->counter) {
|
if(internal_ips->counter) {
|
||||||
@@ -95,7 +105,7 @@ static ip_type ip_from_internal_list(char* name, size_t len) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
res = make_internal_ip(internal_ips->counter);
|
res = make_internal_ip(internal_ips->counter);
|
||||||
if(res.as_int == ip_type_invalid.as_int)
|
if(res.as_int == IPT4_INVALID.as_int)
|
||||||
goto err_plus_unlock;
|
goto err_plus_unlock;
|
||||||
|
|
||||||
string_hash_tuple tmp = { 0 };
|
string_hash_tuple tmp = { 0 };
|
||||||
@@ -107,9 +117,9 @@ static ip_type ip_from_internal_list(char* name, size_t len) {
|
|||||||
|
|
||||||
internal_ips->list[internal_ips->counter] = new_mem;
|
internal_ips->list[internal_ips->counter] = new_mem;
|
||||||
internal_ips->list[internal_ips->counter]->hash = hash;
|
internal_ips->list[internal_ips->counter]->hash = hash;
|
||||||
|
|
||||||
new_mem = dumpstring((char*) name, len + 1);
|
new_mem = dumpstring((char*) name, len);
|
||||||
|
|
||||||
if(!new_mem) {
|
if(!new_mem) {
|
||||||
internal_ips->list[internal_ips->counter] = 0;
|
internal_ips->list[internal_ips->counter] = 0;
|
||||||
goto oom;
|
goto oom;
|
||||||
@@ -122,32 +132,20 @@ static ip_type ip_from_internal_list(char* name, size_t len) {
|
|||||||
|
|
||||||
return res;
|
return res;
|
||||||
err_plus_unlock:
|
err_plus_unlock:
|
||||||
|
|
||||||
PDEBUG("return err\n");
|
PDEBUG("return err\n");
|
||||||
return ip_type_invalid;
|
return IPT4_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* stuff for communication with the allocator thread */
|
/* stuff for communication with the allocator thread */
|
||||||
|
|
||||||
enum at_msgtype {
|
|
||||||
ATM_GETIP,
|
|
||||||
ATM_GETNAME,
|
|
||||||
ATM_EXIT,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum at_direction {
|
enum at_direction {
|
||||||
ATD_SERVER = 0,
|
ATD_SERVER = 0,
|
||||||
ATD_CLIENT,
|
ATD_CLIENT,
|
||||||
ATD_MAX,
|
ATD_MAX,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct at_msghdr {
|
|
||||||
enum at_msgtype msgtype;
|
|
||||||
size_t datalen;
|
|
||||||
};
|
|
||||||
|
|
||||||
static pthread_t allocator_thread;
|
static pthread_t allocator_thread;
|
||||||
static pthread_attr_t allocator_thread_attr;
|
|
||||||
int req_pipefd[2];
|
int req_pipefd[2];
|
||||||
int resp_pipefd[2];
|
int resp_pipefd[2];
|
||||||
|
|
||||||
@@ -172,25 +170,62 @@ static int wait_data(int readfd) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sendmessage(enum at_direction dir, struct at_msghdr *hdr, void* data) {
|
static int trywrite(int fd, void* buf, size_t bytes) {
|
||||||
static int* destfd[ATD_MAX] = { [ATD_SERVER] = &req_pipefd[1], [ATD_CLIENT] = &resp_pipefd[1] };
|
ssize_t ret;
|
||||||
int ret = write(*destfd[dir], hdr, sizeof *hdr) == sizeof *hdr;
|
unsigned char *out = buf;
|
||||||
if(ret && hdr->datalen) {
|
again:
|
||||||
assert(hdr->datalen <= MSG_LEN_MAX);
|
ret = write(fd, out, bytes);
|
||||||
ret = write(*destfd[dir], data, hdr->datalen) == hdr->datalen;
|
switch(ret) {
|
||||||
|
case -1:
|
||||||
|
if(errno == EINTR) goto again;
|
||||||
|
case 0:
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
if(ret == bytes || !bytes) return 1;
|
||||||
|
out += ret;
|
||||||
|
bytes -= ret;
|
||||||
|
goto again;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sendmessage(enum at_direction dir, struct at_msg *msg) {
|
||||||
|
static int* destfd[ATD_MAX] = { [ATD_SERVER] = &req_pipefd[1], [ATD_CLIENT] = &resp_pipefd[1] };
|
||||||
|
assert(msg->h.datalen <= MSG_LEN_MAX);
|
||||||
|
int ret = trywrite(*destfd[dir], msg, sizeof (msg->h)+msg->h.datalen);
|
||||||
|
assert(msg->h.datalen <= MSG_LEN_MAX);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int getmessage(enum at_direction dir, struct at_msghdr *hdr, void* data) {
|
static int tryread(int fd, void* buf, size_t bytes) {
|
||||||
|
ssize_t ret;
|
||||||
|
unsigned char *out = buf;
|
||||||
|
again:
|
||||||
|
ret = read(fd, out, bytes);
|
||||||
|
switch(ret) {
|
||||||
|
case -1:
|
||||||
|
if(errno == EINTR) goto again;
|
||||||
|
case 0:
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
if(ret == bytes || !bytes) return 1;
|
||||||
|
out += ret;
|
||||||
|
bytes -= ret;
|
||||||
|
goto again;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static int readmsg(int fd, struct at_msg *msg) {
|
||||||
|
int ret = tryread(fd, msg, sizeof(msg->h));
|
||||||
|
if(ret != 1) return ret;
|
||||||
|
return tryread(fd, &msg->m, msg->h.datalen);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int getmessage(enum at_direction dir, struct at_msg *msg) {
|
||||||
static int* readfd[ATD_MAX] = { [ATD_SERVER] = &req_pipefd[0], [ATD_CLIENT] = &resp_pipefd[0] };
|
static int* readfd[ATD_MAX] = { [ATD_SERVER] = &req_pipefd[0], [ATD_CLIENT] = &resp_pipefd[0] };
|
||||||
int ret;
|
ssize_t ret;
|
||||||
if((ret = wait_data(*readfd[dir]))) {
|
if((ret = wait_data(*readfd[dir]))) {
|
||||||
ret = read(*readfd[dir], hdr, sizeof *hdr) == sizeof(*hdr);
|
if(!readmsg(*readfd[dir], msg))
|
||||||
assert(hdr->datalen <= MSG_LEN_MAX);
|
return 0;
|
||||||
if(ret && hdr->datalen) {
|
assert(msg->h.datalen <= MSG_LEN_MAX);
|
||||||
ret = read(*readfd[dir], data, hdr->datalen) == hdr->datalen;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -198,26 +233,24 @@ static int getmessage(enum at_direction dir, struct at_msghdr *hdr, void* data)
|
|||||||
static void* threadfunc(void* x) {
|
static void* threadfunc(void* x) {
|
||||||
(void) x;
|
(void) x;
|
||||||
int ret;
|
int ret;
|
||||||
struct at_msghdr msg;
|
struct at_msg msg;
|
||||||
union {
|
while((ret = getmessage(ATD_SERVER, &msg))) {
|
||||||
char host[MSG_LEN_MAX];
|
switch(msg.h.msgtype) {
|
||||||
ip_type ip;
|
|
||||||
} readbuf;
|
|
||||||
while((ret = getmessage(ATD_SERVER, &msg, &readbuf))) {
|
|
||||||
switch(msg.msgtype) {
|
|
||||||
case ATM_GETIP:
|
case ATM_GETIP:
|
||||||
/* client wants an ip for a DNS name. iterate our list and check if we have an existing entry.
|
/* 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. */
|
* if not, create a new one. */
|
||||||
readbuf.ip = ip_from_internal_list(readbuf.host, msg.datalen - 1);
|
msg.m.ip = ip_from_internal_list(msg.m.host, msg.h.datalen);
|
||||||
msg.datalen = sizeof(ip_type);
|
msg.h.datalen = sizeof(ip_type4);
|
||||||
break;
|
break;
|
||||||
case ATM_GETNAME: {
|
case ATM_GETNAME: {
|
||||||
char *host = string_from_internal_ip(readbuf.ip);
|
char *host = string_from_internal_ip(msg.m.ip);
|
||||||
if(host) {
|
if(host) {
|
||||||
size_t l = strlen(host);
|
size_t l = strlen(host);
|
||||||
assert(l < MSG_LEN_MAX);
|
assert(l+1 < MSG_LEN_MAX);
|
||||||
memcpy(readbuf.host, host, l + 1);
|
memcpy(msg.m.host, host, l + 1);
|
||||||
msg.datalen = l + 1;
|
msg.h.datalen = l + 1;
|
||||||
|
} else {
|
||||||
|
msg.h.datalen = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -226,60 +259,92 @@ static void* threadfunc(void* x) {
|
|||||||
default:
|
default:
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
ret = sendmessage(ATD_CLIENT, &msg, &readbuf);
|
ret = sendmessage(ATD_CLIENT, &msg);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* API to access the internal ip mapping */
|
/* API to access the internal ip mapping */
|
||||||
|
|
||||||
ip_type at_get_ip_for_host(char* host, size_t len) {
|
ip_type4 at_get_ip_for_host(char* host, size_t len) {
|
||||||
ip_type readbuf;
|
ip_type4 readbuf;
|
||||||
MUTEX_LOCK(&internal_ips_lock);
|
MUTEX_LOCK(internal_ips_lock);
|
||||||
if(len > MSG_LEN_MAX) goto inv;
|
if(len > MSG_LEN_MAX) goto inv;
|
||||||
struct at_msghdr msg = {.msgtype = ATM_GETIP, .datalen = len + 1 };
|
struct at_msg msg = {.h.msgtype = ATM_GETIP, .h.datalen = len + 1 };
|
||||||
if(sendmessage(ATD_SERVER, &msg, host) &&
|
memcpy(msg.m.host, host, len+1);
|
||||||
getmessage(ATD_CLIENT, &msg, &readbuf));
|
if(sendmessage(ATD_SERVER, &msg) &&
|
||||||
|
getmessage(ATD_CLIENT, &msg)) readbuf = msg.m.ip;
|
||||||
else {
|
else {
|
||||||
inv:
|
inv:
|
||||||
readbuf = ip_type_invalid;
|
readbuf = IPT4_INVALID;
|
||||||
}
|
}
|
||||||
MUTEX_UNLOCK(&internal_ips_lock);
|
assert(msg.h.msgtype == ATM_GETIP);
|
||||||
|
MUTEX_UNLOCK(internal_ips_lock);
|
||||||
return readbuf;
|
return readbuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t at_get_host_for_ip(ip_type ip, char* readbuf) {
|
size_t at_get_host_for_ip(ip_type4 ip, char* readbuf) {
|
||||||
struct at_msghdr msg = {.msgtype = ATM_GETNAME, .datalen = sizeof(ip_type) };
|
struct at_msg msg = {.h.msgtype = ATM_GETNAME, .h.datalen = sizeof(ip_type4), .m.ip = ip };
|
||||||
size_t res = 0;
|
size_t res = 0;
|
||||||
MUTEX_LOCK(&internal_ips_lock);
|
MUTEX_LOCK(internal_ips_lock);
|
||||||
if(sendmessage(ATD_SERVER, &msg, &ip) && getmessage(ATD_CLIENT, &msg, readbuf)) {
|
if(sendmessage(ATD_SERVER, &msg) && getmessage(ATD_CLIENT, &msg)) {
|
||||||
if((ptrdiff_t) msg.datalen <= 0) res = 0;
|
if((int16_t) msg.h.datalen <= 0) res = 0;
|
||||||
else res = msg.datalen - 1;
|
else {
|
||||||
|
memcpy(readbuf, msg.m.host, msg.h.datalen);
|
||||||
|
res = msg.h.datalen - 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
MUTEX_UNLOCK(&internal_ips_lock);
|
assert(msg.h.msgtype == ATM_GETNAME);
|
||||||
|
MUTEX_UNLOCK(internal_ips_lock);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void initpipe(int* fds) {
|
static void initpipe(int* fds) {
|
||||||
if(pipe(fds) == -1) {
|
int retval;
|
||||||
|
|
||||||
|
#ifdef HAVE_PIPE2
|
||||||
|
retval = pipe2(fds, O_CLOEXEC);
|
||||||
|
#else
|
||||||
|
retval = pipe(fds);
|
||||||
|
if(retval == 0) {
|
||||||
|
fcntl(fds[0], F_SETFD, FD_CLOEXEC);
|
||||||
|
fcntl(fds[1], F_SETFD, FD_CLOEXEC);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if(retval == -1) {
|
||||||
perror("pipe");
|
perror("pipe");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef MAX
|
||||||
|
#define MAX(x, y) ((x) > (y) ? (x) : (y))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(PTHREAD_STACK_MIN) || defined(__APPLE__)
|
||||||
|
/* MAC says its min is 8KB, but then crashes in our face. thx hunkOLard */
|
||||||
|
#define PTHREAD_STACK_MIN 64*1024
|
||||||
|
#endif
|
||||||
|
|
||||||
/* initialize with pointers to shared memory. these will
|
/* initialize with pointers to shared memory. these will
|
||||||
* be used to place responses and arguments */
|
* be used to place responses and arguments */
|
||||||
void at_init(void) {
|
void at_init(void) {
|
||||||
PFUNC();
|
PFUNC();
|
||||||
MUTEX_INIT(&internal_ips_lock);
|
void *shm = mmap(0, 4096, PROT_WRITE|PROT_READ, MAP_ANON|MAP_SHARED, -1, 0);
|
||||||
internal_ips = &internal_ips_buf;
|
assert(shm);
|
||||||
|
internal_ips_lock = shm;
|
||||||
|
internal_ips = (void*)((char*)shm + 2048);
|
||||||
|
|
||||||
|
MUTEX_INIT(internal_ips_lock);
|
||||||
memset(internal_ips, 0, sizeof *internal_ips);
|
memset(internal_ips, 0, sizeof *internal_ips);
|
||||||
initpipe(req_pipefd);
|
initpipe(req_pipefd);
|
||||||
initpipe(resp_pipefd);
|
initpipe(resp_pipefd);
|
||||||
|
pthread_attr_t allocator_thread_attr;
|
||||||
pthread_attr_init(&allocator_thread_attr);
|
pthread_attr_init(&allocator_thread_attr);
|
||||||
pthread_attr_setstacksize(&allocator_thread_attr, 16 * 1024);
|
pthread_attr_setstacksize(&allocator_thread_attr, MAX(16 * 1024, PTHREAD_STACK_MIN));
|
||||||
pthread_create(&allocator_thread, &allocator_thread_attr, threadfunc, 0);
|
pthread_create(&allocator_thread, &allocator_thread_attr, threadfunc, 0);
|
||||||
|
pthread_attr_destroy(&allocator_thread_attr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void at_close(void) {
|
void at_close(void) {
|
||||||
@@ -291,6 +356,5 @@ void at_close(void) {
|
|||||||
close(req_pipefd[1]);
|
close(req_pipefd[1]);
|
||||||
close(resp_pipefd[0]);
|
close(resp_pipefd[0]);
|
||||||
close(resp_pipefd[1]);
|
close(resp_pipefd[1]);
|
||||||
pthread_attr_destroy(&allocator_thread_attr);
|
MUTEX_DESTROY(internal_ips_lock);
|
||||||
MUTEX_DESTROY(&internal_ips_lock);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,15 +4,13 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include "ip_type.h"
|
#include "ip_type.h"
|
||||||
|
|
||||||
#define MSG_LEN_MAX 256
|
|
||||||
|
|
||||||
extern int req_pipefd[2];
|
extern int req_pipefd[2];
|
||||||
extern int resp_pipefd[2];
|
extern int resp_pipefd[2];
|
||||||
|
|
||||||
void at_init(void);
|
void at_init(void);
|
||||||
void at_close(void);
|
void at_close(void);
|
||||||
size_t at_get_host_for_ip(ip_type ip, char* readbuf);
|
size_t at_get_host_for_ip(ip_type4 ip, char* readbuf);
|
||||||
ip_type at_get_ip_for_host(char* host, size_t len);
|
ip_type4 at_get_ip_for_host(char* host, size_t len);
|
||||||
|
|
||||||
//RcB: DEP "allocator_thread.c"
|
//RcB: DEP "allocator_thread.c"
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -23,6 +23,33 @@ const char *proxy_state_strmap[] = {
|
|||||||
"busy",
|
"busy",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* isnumericipv4() taken from libulz */
|
||||||
|
int pc_isnumericipv4(const char* ipstring) {
|
||||||
|
size_t x = 0, n = 0, d = 0;
|
||||||
|
int wasdot = 0;
|
||||||
|
while(1) {
|
||||||
|
switch(ipstring[x]) {
|
||||||
|
case 0: goto done;
|
||||||
|
case '.':
|
||||||
|
if(!n || wasdot) return 0;
|
||||||
|
d++;
|
||||||
|
wasdot = 1;
|
||||||
|
break;
|
||||||
|
case '0': case '1': case '2': case '3': case '4':
|
||||||
|
case '5': case '6': case '7': case '8': case '9':
|
||||||
|
n++;
|
||||||
|
wasdot = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
x++;
|
||||||
|
}
|
||||||
|
done:
|
||||||
|
if(d == 3 && n >= 4 && n <= 12) return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// stolen from libulz (C) rofl0r
|
// stolen from libulz (C) rofl0r
|
||||||
void pc_stringfromipv4(unsigned char *ip_buf_4_bytes, char *outbuf_16_bytes) {
|
void pc_stringfromipv4(unsigned char *ip_buf_4_bytes, char *outbuf_16_bytes) {
|
||||||
unsigned char *p;
|
unsigned char *p;
|
||||||
@@ -78,6 +105,13 @@ char *get_config_path(char* default_path, char* pbuf, size_t bufsize) {
|
|||||||
path = pbuf;
|
path = pbuf;
|
||||||
if(check_path(path))
|
if(check_path(path))
|
||||||
goto have;
|
goto have;
|
||||||
|
|
||||||
|
// priority 3b: ~/config/settings/proxychains.conf (for haiku)
|
||||||
|
path = getenv("HOME");
|
||||||
|
snprintf(pbuf, bufsize, "%s/config/settings/%s", path, PROXYCHAINS_CONF_FILE);
|
||||||
|
path = pbuf;
|
||||||
|
if(check_path(path))
|
||||||
|
goto have;
|
||||||
|
|
||||||
// priority 4: $SYSCONFDIR/proxychains.conf
|
// priority 4: $SYSCONFDIR/proxychains.conf
|
||||||
path = SYSCONFDIR "/" PROXYCHAINS_CONF_FILE;
|
path = SYSCONFDIR "/" PROXYCHAINS_CONF_FILE;
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ extern const char *proxy_state_strmap[];
|
|||||||
|
|
||||||
char *get_config_path(char* default_path, char* pbuf, size_t bufsize);
|
char *get_config_path(char* default_path, char* pbuf, size_t bufsize);
|
||||||
void pc_stringfromipv4(unsigned char *ip_buf_4_bytes, char *outbuf_16_bytes);
|
void pc_stringfromipv4(unsigned char *ip_buf_4_bytes, char *outbuf_16_bytes);
|
||||||
|
int pc_isnumericipv4(const char* ipstring);
|
||||||
|
|
||||||
//RcB: DEP "common.c"
|
//RcB: DEP "common.c"
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+459
-260
@@ -37,8 +37,8 @@
|
|||||||
|
|
||||||
#include "core.h"
|
#include "core.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "shm.h"
|
#include "rdns.h"
|
||||||
#include "allocator_thread.h"
|
#include "mutex.h"
|
||||||
|
|
||||||
extern int tcp_read_time_out;
|
extern int tcp_read_time_out;
|
||||||
extern int tcp_connect_time_out;
|
extern int tcp_connect_time_out;
|
||||||
@@ -107,7 +107,7 @@ static void encode_base_64(char *src, char *dest, int max_len) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void proxychains_write_log(char *str, ...) {
|
void proxychains_write_log(char *str, ...) {
|
||||||
char buff[1024*20];
|
char buff[1024*4];
|
||||||
va_list arglist;
|
va_list arglist;
|
||||||
if(!proxychains_quiet_mode) {
|
if(!proxychains_quiet_mode) {
|
||||||
va_start(arglist, str);
|
va_start(arglist, str);
|
||||||
@@ -188,6 +188,7 @@ static int timed_connect(int sock, const struct sockaddr *addr, socklen_t len) {
|
|||||||
|
|
||||||
|
|
||||||
#define INVALID_INDEX 0xFFFFFFFFU
|
#define INVALID_INDEX 0xFFFFFFFFU
|
||||||
|
#define BUFF_SIZE 1024 // used to read responses from proxies.
|
||||||
static int tunnel_to(int sock, ip_type ip, unsigned short port, proxy_type pt, char *user, char *pass) {
|
static int tunnel_to(int sock, ip_type ip, unsigned short port, proxy_type pt, char *user, char *pass) {
|
||||||
char *dns_name = NULL;
|
char *dns_name = NULL;
|
||||||
char hostnamebuf[MSG_LEN_MAX];
|
char hostnamebuf[MSG_LEN_MAX];
|
||||||
@@ -199,8 +200,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 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 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
|
// the hardcoded number 224 can now be changed using the config option remote_dns_subnet to i.e. 127
|
||||||
if(ip.octet[0] == remote_dns_subnet) {
|
if(!ip.is_v6 && proxychains_resolver >= DNSLF_RDNS_START && ip.addr.v4.octet[0] == remote_dns_subnet) {
|
||||||
dns_len = at_get_host_for_ip(ip, hostnamebuf);
|
dns_len = rdns_get_host_for_ip(ip.addr.v4, hostnamebuf);
|
||||||
if(!dns_len) goto err;
|
if(!dns_len) goto err;
|
||||||
else dns_name = hostnamebuf;
|
else dns_name = hostnamebuf;
|
||||||
}
|
}
|
||||||
@@ -217,209 +218,205 @@ static int tunnel_to(int sock, ip_type ip, unsigned short port, proxy_type pt, c
|
|||||||
|
|
||||||
int len;
|
int len;
|
||||||
unsigned char buff[BUFF_SIZE];
|
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) {
|
switch (pt) {
|
||||||
|
case RAW_TYPE: {
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case HTTP_TYPE:{
|
case HTTP_TYPE:{
|
||||||
if(!dns_len) {
|
if(!dns_len) {
|
||||||
pc_stringfromipv4(&ip.octet[0], ip_buf);
|
if(!inet_ntop(v6?AF_INET6:AF_INET,ip.addr.v6,ip_buf,sizeof ip_buf)) {
|
||||||
dns_name = ip_buf;
|
proxychains_write_log(LOG_PREFIX "error: ip address conversion failed\n");
|
||||||
}
|
|
||||||
|
|
||||||
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))
|
|
||||||
goto err;
|
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;
|
|
||||||
}
|
}
|
||||||
|
dns_name = ip_buf;
|
||||||
// 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;
|
#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:{
|
case SOCKS4_TYPE:{
|
||||||
buff[0] = 4; // socks version
|
if(v6) {
|
||||||
buff[1] = 1; // connect command
|
proxychains_write_log(LOG_PREFIX "error: SOCKS4 doesn't support ipv6 addresses\n");
|
||||||
memcpy(&buff[2], &port, 2); // dest port
|
goto err;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
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:{
|
case SOCKS5_TYPE:{
|
||||||
if(user) {
|
int n_methods = ulen ? 2 : 1;
|
||||||
buff[0] = 5; //version
|
buff[0] = 5; // version
|
||||||
buff[1] = 2; //nomber of methods
|
buff[1] = n_methods ; // number of methods
|
||||||
buff[2] = 0; // no auth method
|
buff[2] = 0; // no auth method
|
||||||
buff[3] = 2; /// auth method -> username / password
|
if(ulen) buff[3] = 2; /// auth method -> username / password
|
||||||
if(4 != write_n_bytes(sock, (char *) buff, 4))
|
if(2+n_methods != write_n_bytes(sock, (char *) buff, 2+n_methods))
|
||||||
goto err;
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
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;
|
||||||
|
/* according to RFC 1929 the version field for the user/pass auth sub-
|
||||||
|
negotiation should be 1, which is kinda counter-intuitive, so there
|
||||||
|
are some socks5 proxies that return 5 instead. other programs like
|
||||||
|
curl work fine when the version is 5, so let's do the same and accept
|
||||||
|
either of them. */
|
||||||
|
if(!(in[0] == 5 || in[0] == 1))
|
||||||
|
goto err;
|
||||||
|
if(in[1] != 0)
|
||||||
|
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:
|
err:
|
||||||
@@ -433,22 +430,30 @@ static int tunnel_to(int sock, ip_type ip, unsigned short port, proxy_type pt, c
|
|||||||
#define RRT "Round Robin chain"
|
#define RRT "Round Robin chain"
|
||||||
|
|
||||||
static int start_chain(int *fd, proxy_data * pd, char *begin_mark) {
|
static int start_chain(int *fd, proxy_data * pd, char *begin_mark) {
|
||||||
struct sockaddr_in addr;
|
int v6 = pd->ip.is_v6;
|
||||||
char ip_buf[16];
|
|
||||||
|
|
||||||
*fd = socket(PF_INET, SOCK_STREAM, 0);
|
*fd = socket(v6?PF_INET6:PF_INET, SOCK_STREAM, 0);
|
||||||
if(*fd == -1)
|
if(*fd == -1)
|
||||||
goto error;
|
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 ",
|
proxychains_write_log(LOG_PREFIX "%s " TP " %s:%d ",
|
||||||
begin_mark, ip_buf, htons(pd->port));
|
begin_mark, ip_buf, htons(pd->port));
|
||||||
pd->ps = PLAY_STATE;
|
pd->ps = PLAY_STATE;
|
||||||
memset(&addr, 0, sizeof(addr));
|
struct sockaddr_in addr = {
|
||||||
addr.sin_family = AF_INET;
|
.sin_family = AF_INET,
|
||||||
addr.sin_addr.s_addr = (in_addr_t) pd->ip.as_int;
|
.sin_port = pd->port,
|
||||||
addr.sin_port = pd->port;
|
.sin_addr.s_addr = (in_addr_t) pd->ip.addr.v4.as_int
|
||||||
if(timed_connect(*fd, (struct sockaddr *) &addr, sizeof(addr))) {
|
};
|
||||||
|
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;
|
pd->ps = DOWN_STATE;
|
||||||
goto error1;
|
goto error1;
|
||||||
}
|
}
|
||||||
@@ -470,7 +475,8 @@ static proxy_data *select_proxy(select_type how, proxy_data * pd, unsigned int p
|
|||||||
case RANDOMLY:
|
case RANDOMLY:
|
||||||
do {
|
do {
|
||||||
k++;
|
k++;
|
||||||
i = 0 + (unsigned int) (proxy_count * 1.0 * rand() / (RAND_MAX + 1.0));
|
i = rand() % (proxy_count-proxychains_fixed_chain);
|
||||||
|
i += proxychains_fixed_chain;
|
||||||
} while(pd[i].ps != PLAY_STATE && k < proxy_count * 100);
|
} while(pd[i].ps != PLAY_STATE && k < proxy_count * 100);
|
||||||
break;
|
break;
|
||||||
case FIFOLY:
|
case FIFOLY:
|
||||||
@@ -519,16 +525,22 @@ static int chain_step(int ns, proxy_data * pfrom, proxy_data * pto) {
|
|||||||
int retcode = -1;
|
int retcode = -1;
|
||||||
char *hostname;
|
char *hostname;
|
||||||
char hostname_buf[MSG_LEN_MAX];
|
char hostname_buf[MSG_LEN_MAX];
|
||||||
char ip_buf[16];
|
char ip_buf[INET6_ADDRSTRLEN];
|
||||||
|
int v6 = pto->ip.is_v6;
|
||||||
|
|
||||||
PFUNC();
|
PFUNC();
|
||||||
|
|
||||||
if(pto->ip.octet[0] == remote_dns_subnet) {
|
if(!v6 && proxychains_resolver >= DNSLF_RDNS_START && pto->ip.addr.v4.octet[0] == remote_dns_subnet) {
|
||||||
if(!at_get_host_for_ip(pto->ip, hostname_buf)) goto usenumericip;
|
if(!rdns_get_host_for_ip(pto->ip.addr.v4, hostname_buf)) goto usenumericip;
|
||||||
else hostname = hostname_buf;
|
else hostname = hostname_buf;
|
||||||
} else {
|
} else {
|
||||||
usenumericip:
|
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;
|
hostname = ip_buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -552,9 +564,38 @@ static int chain_step(int ns, proxy_data * pfrom, proxy_data * pto) {
|
|||||||
return retcode;
|
return retcode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int strict_connect(
|
||||||
|
unsigned *alive_count,
|
||||||
|
unsigned *offset,
|
||||||
|
int *ns,
|
||||||
|
proxy_data **p1, proxy_data **p2,
|
||||||
|
unsigned proxy_count, proxy_data * pd)
|
||||||
|
{
|
||||||
|
*alive_count = calc_alive(pd, proxy_count);
|
||||||
|
*offset = 0;
|
||||||
|
if(!(*p1 = select_proxy(FIFOLY, pd, proxy_count, offset))) {
|
||||||
|
PDEBUG("select_proxy failed\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if(SUCCESS != start_chain(ns, *p1, ST)) {
|
||||||
|
PDEBUG("start_chain failed\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
while(*offset < proxy_count) {
|
||||||
|
if(!(*p2 = select_proxy(FIFOLY, pd, proxy_count, offset)))
|
||||||
|
break;
|
||||||
|
if(SUCCESS != chain_step(*ns, *p1, *p2)) {
|
||||||
|
PDEBUG("chain_step failed\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
*p1 = *p2;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
int connect_proxy_chain(int sock, ip_type target_ip,
|
int connect_proxy_chain(int sock, ip_type target_ip,
|
||||||
unsigned short target_port, proxy_data * pd,
|
unsigned short target_port, proxy_data * pd,
|
||||||
unsigned int proxy_count, chain_type ct, unsigned int max_chain) {
|
unsigned int proxy_count, chain_type ct) {
|
||||||
proxy_data p4;
|
proxy_data p4;
|
||||||
proxy_data *p1, *p2, *p3;
|
proxy_data *p1, *p2, *p3;
|
||||||
int ns = -1;
|
int ns = -1;
|
||||||
@@ -562,8 +603,9 @@ int connect_proxy_chain(int sock, ip_type target_ip,
|
|||||||
unsigned int offset = 0;
|
unsigned int offset = 0;
|
||||||
unsigned int alive_count = 0;
|
unsigned int alive_count = 0;
|
||||||
unsigned int curr_len = 0;
|
unsigned int curr_len = 0;
|
||||||
unsigned int curr_pos = 0;
|
|
||||||
unsigned int looped = 0; // went back to start of list in RR mode
|
unsigned int looped = 0; // went back to start of list in RR mode
|
||||||
|
unsigned int rr_loop_max = 14;
|
||||||
|
unsigned int max_chain = proxychains_max_chain;
|
||||||
|
|
||||||
p3 = &p4;
|
p3 = &p4;
|
||||||
|
|
||||||
@@ -572,9 +614,14 @@ int connect_proxy_chain(int sock, ip_type target_ip,
|
|||||||
again:
|
again:
|
||||||
rc = -1;
|
rc = -1;
|
||||||
DUMP_PROXY_CHAIN(pd, proxy_count);
|
DUMP_PROXY_CHAIN(pd, proxy_count);
|
||||||
|
if(proxychains_fixed_chain) {
|
||||||
|
if(!strict_connect(&alive_count, &offset, &ns, &p1, &p2, proxychains_fixed_chain, pd))
|
||||||
|
goto error_strict;
|
||||||
|
}
|
||||||
|
|
||||||
switch (ct) {
|
switch (ct) {
|
||||||
case DYNAMIC_TYPE:
|
case DYNAMIC_TYPE:
|
||||||
|
if(proxychains_fixed_chain) goto dyn_fixed_resume;
|
||||||
alive_count = calc_alive(pd, proxy_count);
|
alive_count = calc_alive(pd, proxy_count);
|
||||||
offset = 0;
|
offset = 0;
|
||||||
do {
|
do {
|
||||||
@@ -590,6 +637,7 @@ int connect_proxy_chain(int sock, ip_type target_ip,
|
|||||||
goto again;
|
goto again;
|
||||||
}
|
}
|
||||||
p1 = p2;
|
p1 = p2;
|
||||||
|
dyn_fixed_resume:;
|
||||||
}
|
}
|
||||||
//proxychains_write_log(TP);
|
//proxychains_write_log(TP);
|
||||||
p3->ip = target_ip;
|
p3->ip = target_ip;
|
||||||
@@ -599,24 +647,29 @@ int connect_proxy_chain(int sock, ip_type target_ip,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case ROUND_ROBIN_TYPE:
|
case ROUND_ROBIN_TYPE:
|
||||||
|
// FIXME: add support for fixed_len
|
||||||
alive_count = calc_alive(pd, proxy_count);
|
alive_count = calc_alive(pd, proxy_count);
|
||||||
curr_pos = offset = proxychains_proxy_offset;
|
offset = proxychains_proxy_offset;
|
||||||
if(alive_count < max_chain)
|
if(alive_count < max_chain)
|
||||||
goto error_more;
|
goto error_more;
|
||||||
PDEBUG("1:rr_offset = %d, curr_pos = %d\n", offset, curr_pos);
|
PDEBUG("1:rr_offset = %d\n", offset);
|
||||||
/* Check from current RR offset til end */
|
/* Check from current RR offset til end */
|
||||||
for (;rc != SUCCESS;) {
|
for (;rc != SUCCESS;) {
|
||||||
if (!(p1 = select_proxy(FIFOLY, pd, proxy_count, &offset))) {
|
if (!(p1 = select_proxy(FIFOLY, pd, proxy_count, &offset))) {
|
||||||
/* We've reached the end of the list, go to the start */
|
/* We've reached the end of the list, go to the start */
|
||||||
offset = 0;
|
offset = 0;
|
||||||
looped++;
|
looped++;
|
||||||
continue;
|
if (looped > rr_loop_max) {
|
||||||
} else if (looped && rc > 0 && offset >= curr_pos) {
|
proxychains_proxy_offset = 0;
|
||||||
PDEBUG("GOTO MORE PROXIES 0\n");
|
goto error_more;
|
||||||
/* We've gone back to the start and now past our starting position */
|
} else {
|
||||||
proxychains_proxy_offset = 0;
|
PDEBUG("rr_type all proxies down, release all\n");
|
||||||
goto error_more;
|
release_all(pd, proxy_count);
|
||||||
}
|
/* Each loop we wait 10ms more */
|
||||||
|
usleep(10000 * looped);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
PDEBUG("2:rr_offset = %d\n", offset);
|
PDEBUG("2:rr_offset = %d\n", offset);
|
||||||
rc=start_chain(&ns, p1, RRT);
|
rc=start_chain(&ns, p1, RRT);
|
||||||
}
|
}
|
||||||
@@ -645,25 +698,8 @@ int connect_proxy_chain(int sock, ip_type target_ip,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case STRICT_TYPE:
|
case STRICT_TYPE:
|
||||||
alive_count = calc_alive(pd, proxy_count);
|
if(!strict_connect(&alive_count, &offset, &ns, &p1, &p2, proxy_count, pd))
|
||||||
offset = 0;
|
|
||||||
if(!(p1 = select_proxy(FIFOLY, pd, proxy_count, &offset))) {
|
|
||||||
PDEBUG("select_proxy failed\n");
|
|
||||||
goto error_strict;
|
goto error_strict;
|
||||||
}
|
|
||||||
if(SUCCESS != start_chain(&ns, p1, ST)) {
|
|
||||||
PDEBUG("start_chain failed\n");
|
|
||||||
goto error_strict;
|
|
||||||
}
|
|
||||||
while(offset < proxy_count) {
|
|
||||||
if(!(p2 = select_proxy(FIFOLY, pd, proxy_count, &offset)))
|
|
||||||
break;
|
|
||||||
if(SUCCESS != chain_step(ns, p1, p2)) {
|
|
||||||
PDEBUG("chain_step failed\n");
|
|
||||||
goto error_strict;
|
|
||||||
}
|
|
||||||
p1 = p2;
|
|
||||||
}
|
|
||||||
//proxychains_write_log(TP);
|
//proxychains_write_log(TP);
|
||||||
p3->ip = target_ip;
|
p3->ip = target_ip;
|
||||||
p3->port = target_port;
|
p3->port = target_port;
|
||||||
@@ -672,6 +708,12 @@ int connect_proxy_chain(int sock, ip_type target_ip,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case RANDOM_TYPE:
|
case RANDOM_TYPE:
|
||||||
|
if(proxychains_fixed_chain) {
|
||||||
|
if(alive_count < max_chain)
|
||||||
|
goto error_more;
|
||||||
|
curr_len = proxychains_fixed_chain - 1;
|
||||||
|
goto random_fixed_resume;
|
||||||
|
}
|
||||||
alive_count = calc_alive(pd, proxy_count);
|
alive_count = calc_alive(pd, proxy_count);
|
||||||
if(alive_count < max_chain)
|
if(alive_count < max_chain)
|
||||||
goto error_more;
|
goto error_more;
|
||||||
@@ -680,6 +722,9 @@ int connect_proxy_chain(int sock, ip_type target_ip,
|
|||||||
if(!(p1 = select_proxy(RANDOMLY, pd, proxy_count, &offset)))
|
if(!(p1 = select_proxy(RANDOMLY, pd, proxy_count, &offset)))
|
||||||
goto error_more;
|
goto error_more;
|
||||||
} while(SUCCESS != start_chain(&ns, p1, RT) && offset < max_chain);
|
} while(SUCCESS != start_chain(&ns, p1, RT) && offset < max_chain);
|
||||||
|
|
||||||
|
random_fixed_resume:;
|
||||||
|
|
||||||
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;
|
||||||
@@ -719,10 +764,13 @@ int connect_proxy_chain(int sock, ip_type target_ip,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static pthread_mutex_t servbyname_lock;
|
||||||
void core_initialize(void) {
|
void core_initialize(void) {
|
||||||
|
MUTEX_INIT(&servbyname_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void core_unload(void) {
|
void core_unload(void) {
|
||||||
|
MUTEX_DESTROY(&servbyname_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gethostbyname_data_setstring(struct gethostbyname_data* data, char* name) {
|
static void gethostbyname_data_setstring(struct gethostbyname_data* data, char* name) {
|
||||||
@@ -730,7 +778,103 @@ static void gethostbyname_data_setstring(struct gethostbyname_data* data, char*
|
|||||||
data->hostent_space.h_name = data->addr_name;
|
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_old(const char *name)
|
||||||
|
{
|
||||||
|
static struct hostent hostent_space;
|
||||||
|
static in_addr_t resolved_addr;
|
||||||
|
static char* resolved_addr_p;
|
||||||
|
static char addr_name[256];
|
||||||
|
|
||||||
|
int pipe_fd[2];
|
||||||
|
char buff[256];
|
||||||
|
in_addr_t addr;
|
||||||
|
pid_t pid;
|
||||||
|
int status, ret;
|
||||||
|
size_t l;
|
||||||
|
struct hostent* hp;
|
||||||
|
|
||||||
|
hostent_space.h_addr_list = &resolved_addr_p;
|
||||||
|
*hostent_space.h_addr_list = (char*)&resolved_addr;
|
||||||
|
resolved_addr = 0;
|
||||||
|
|
||||||
|
if(pc_isnumericipv4(name)) {
|
||||||
|
strcpy(buff, name);
|
||||||
|
goto got_buff;
|
||||||
|
}
|
||||||
|
|
||||||
|
gethostname(buff,sizeof(buff));
|
||||||
|
if(!strcmp(buff,name))
|
||||||
|
goto got_buff;
|
||||||
|
|
||||||
|
memset(buff, 0, sizeof(buff));
|
||||||
|
|
||||||
|
// TODO: this works only once, so cache it ...
|
||||||
|
// later
|
||||||
|
while ((hp=gethostent()))
|
||||||
|
if (!strcmp(hp->h_name,name))
|
||||||
|
return hp;
|
||||||
|
#ifdef HAVE_PIPE2
|
||||||
|
ret = pipe2(pipe_fd, O_CLOEXEC);
|
||||||
|
#else
|
||||||
|
ret = pipe(pipe_fd);
|
||||||
|
if(ret == 0) {
|
||||||
|
fcntl(pipe_fd[0], F_SETFD, FD_CLOEXEC);
|
||||||
|
fcntl(pipe_fd[1], F_SETFD, FD_CLOEXEC);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if(ret)
|
||||||
|
goto err;
|
||||||
|
pid = fork();
|
||||||
|
switch(pid) {
|
||||||
|
|
||||||
|
case 0: // child
|
||||||
|
proxychains_write_log("|DNS-request| %s \n", name);
|
||||||
|
close(pipe_fd[0]);
|
||||||
|
dup2(pipe_fd[1],1);
|
||||||
|
close(pipe_fd[1]);
|
||||||
|
|
||||||
|
// putenv("LD_PRELOAD=");
|
||||||
|
execlp("proxyresolv","proxyresolv",name,NULL);
|
||||||
|
perror("can't exec proxyresolv");
|
||||||
|
exit(2);
|
||||||
|
|
||||||
|
case -1: //error
|
||||||
|
close(pipe_fd[0]);
|
||||||
|
close(pipe_fd[1]);
|
||||||
|
perror("can't fork");
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
default:
|
||||||
|
close(pipe_fd[1]);
|
||||||
|
waitpid(pid, &status, 0);
|
||||||
|
buff[0] = 0;
|
||||||
|
read(pipe_fd[0],&buff,sizeof(buff));
|
||||||
|
close(pipe_fd[0]);
|
||||||
|
got_buff:
|
||||||
|
l = strlen(buff);
|
||||||
|
if(l && buff[l-1] == '\n') buff[l-1] = 0;
|
||||||
|
addr = inet_addr(buff);
|
||||||
|
if (addr == (in_addr_t) (-1))
|
||||||
|
goto err_dns;
|
||||||
|
memcpy(*(hostent_space.h_addr_list),
|
||||||
|
&addr ,sizeof(struct in_addr));
|
||||||
|
hostent_space.h_name = addr_name;
|
||||||
|
snprintf(addr_name, sizeof addr_name, "%s", buff);
|
||||||
|
hostent_space.h_length = sizeof (in_addr_t);
|
||||||
|
hostent_space.h_addrtype = AF_INET;
|
||||||
|
}
|
||||||
|
proxychains_write_log("|DNS-response| %s is %s\n",
|
||||||
|
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");
|
||||||
|
err:
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
struct hostent *proxy_gethostbyname(const char *name, struct gethostbyname_data* data) {
|
struct hostent *proxy_gethostbyname(const char *name, struct gethostbyname_data* data) {
|
||||||
PFUNC();
|
PFUNC();
|
||||||
char buff[256];
|
char buff[256];
|
||||||
@@ -746,24 +890,29 @@ struct hostent *proxy_gethostbyname(const char *name, struct gethostbyname_data*
|
|||||||
data->hostent_space.h_addrtype = AF_INET;
|
data->hostent_space.h_addrtype = AF_INET;
|
||||||
data->hostent_space.h_length = sizeof(in_addr_t);
|
data->hostent_space.h_length = sizeof(in_addr_t);
|
||||||
|
|
||||||
|
if(pc_isnumericipv4(name)) {
|
||||||
|
data->resolved_addr = inet_addr(name);
|
||||||
|
goto retname;
|
||||||
|
}
|
||||||
|
|
||||||
gethostname(buff, sizeof(buff));
|
gethostname(buff, sizeof(buff));
|
||||||
|
|
||||||
if(!strcmp(buff, name)) {
|
if(!strcmp(buff, name)) {
|
||||||
data->resolved_addr = inet_addr(buff);
|
data->resolved_addr = inet_addr(buff);
|
||||||
if(data->resolved_addr == (in_addr_t) (-1))
|
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) (IPT4_LOCALHOST.as_int);
|
||||||
goto retname;
|
goto retname;
|
||||||
}
|
}
|
||||||
|
|
||||||
// this iterates over the "known hosts" db, usually /etc/hosts
|
// this iterates over the "known hosts" db, usually /etc/hosts
|
||||||
ip_type hdb_res = hostsreader_get_numeric_ip_for_name(name);
|
ip_type4 hdb_res = hostsreader_get_numeric_ip_for_name(name);
|
||||||
if(hdb_res.as_int != ip_type_invalid.as_int) {
|
if(hdb_res.as_int != IPT4_INVALID.as_int) {
|
||||||
data->resolved_addr = hdb_res.as_int;
|
data->resolved_addr = hdb_res.as_int;
|
||||||
goto retname;
|
goto retname;
|
||||||
}
|
}
|
||||||
|
|
||||||
data->resolved_addr = at_get_ip_for_host((char*) name, strlen(name)).as_int;
|
data->resolved_addr = rdns_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) IPT4_INVALID.as_int) return NULL;
|
||||||
|
|
||||||
retname:
|
retname:
|
||||||
|
|
||||||
@@ -776,7 +925,7 @@ struct hostent *proxy_gethostbyname(const char *name, struct gethostbyname_data*
|
|||||||
|
|
||||||
struct addrinfo_data {
|
struct addrinfo_data {
|
||||||
struct addrinfo addrinfo_space;
|
struct addrinfo addrinfo_space;
|
||||||
struct sockaddr sockaddr_space;
|
struct sockaddr_storage sockaddr_space;
|
||||||
char addr_name[256];
|
char addr_name[256];
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -785,14 +934,17 @@ void proxy_freeaddrinfo(struct addrinfo *res) {
|
|||||||
free(res);
|
free(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef IS_MAC
|
static int mygetservbyname_r(const char* name, const char* proto, struct servent* result_buf,
|
||||||
/* getservbyname on mac is using thread local storage, so we dont need mutex */
|
|
||||||
static int getservbyname_r(const char* name, const char* proto, struct servent* result_buf,
|
|
||||||
char* buf, size_t buflen, struct servent** result) {
|
char* buf, size_t buflen, struct servent** result) {
|
||||||
PFUNC();
|
PFUNC();
|
||||||
|
#ifdef HAVE_GNU_GETSERVBYNAME_R
|
||||||
|
PDEBUG("using host getservbyname_r\n");
|
||||||
|
return getservbyname_r(name, proto, result_buf, buf, buflen, result);
|
||||||
|
#endif
|
||||||
struct servent *res;
|
struct servent *res;
|
||||||
int ret;
|
int ret;
|
||||||
(void) buf; (void) buflen;
|
(void) buf; (void) buflen;
|
||||||
|
MUTEX_LOCK(&servbyname_lock);
|
||||||
res = getservbyname(name, proto);
|
res = getservbyname(name, proto);
|
||||||
if(res) {
|
if(res) {
|
||||||
*result_buf = *res;
|
*result_buf = *res;
|
||||||
@@ -802,9 +954,36 @@ static int getservbyname_r(const char* name, const char* proto, struct servent*
|
|||||||
*result = NULL;
|
*result = NULL;
|
||||||
ret = ENOENT;
|
ret = ENOENT;
|
||||||
}
|
}
|
||||||
|
MUTEX_UNLOCK(&servbyname_lock);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int looks_like_numeric_ipv6(const char *node)
|
||||||
|
{
|
||||||
|
if(!strchr(node, ':')) return 0;
|
||||||
|
const char* p= node;
|
||||||
|
while(1) switch(*(p++)) {
|
||||||
|
case 0: return 1;
|
||||||
|
case ':': case '.':
|
||||||
|
case '0': case '1': case '2': case '3': case '4':
|
||||||
|
case '5': case '6': case '7': case '8': case '9':
|
||||||
|
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
|
||||||
|
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
|
||||||
|
break;
|
||||||
|
default: return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int my_inet_aton(const char *node, struct addrinfo_data* space)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
((struct sockaddr_in *) &space->sockaddr_space)->sin_family = AF_INET;
|
||||||
|
ret = inet_aton(node, &((struct sockaddr_in *) &space->sockaddr_space)->sin_addr);
|
||||||
|
if(ret || !looks_like_numeric_ipv6(node)) return ret;
|
||||||
|
ret = inet_pton(AF_INET6, node, &((struct sockaddr_in6 *) &space->sockaddr_space)->sin6_addr);
|
||||||
|
if(ret) ((struct sockaddr_in6 *) &space->sockaddr_space)->sin6_family = AF_INET6;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
int proxy_getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res) {
|
int proxy_getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res) {
|
||||||
struct gethostbyname_data ghdata;
|
struct gethostbyname_data ghdata;
|
||||||
@@ -814,45 +993,65 @@ int proxy_getaddrinfo(const char *node, const char *service, const struct addrin
|
|||||||
struct servent se_buf;
|
struct servent se_buf;
|
||||||
struct addrinfo *p;
|
struct addrinfo *p;
|
||||||
char buf[1024];
|
char buf[1024];
|
||||||
int port;
|
int port, af = AF_INET;
|
||||||
PFUNC();
|
|
||||||
|
PDEBUG("proxy_getaddrinfo node:%s service: %s, flags: %d\n",
|
||||||
|
node?node:"",service?service:"",hints?(int)hints->ai_flags:0);
|
||||||
|
|
||||||
// printf("proxy_getaddrinfo node %s service %s\n",node,service);
|
|
||||||
space = calloc(1, sizeof(struct addrinfo_data));
|
space = calloc(1, sizeof(struct addrinfo_data));
|
||||||
if(!space) goto err1;
|
if(!space) goto err1;
|
||||||
|
|
||||||
if(node && !inet_aton(node, &((struct sockaddr_in *) &space->sockaddr_space)->sin_addr)) {
|
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)) return EAI_NONAME;
|
if(hints && (hints->ai_flags & AI_NUMERICHOST)) {
|
||||||
hp = proxy_gethostbyname(node, &ghdata);
|
free(space);
|
||||||
|
return EAI_NONAME;
|
||||||
|
}
|
||||||
|
if(proxychains_resolver == DNSLF_FORKEXEC)
|
||||||
|
hp = proxy_gethostbyname_old(node);
|
||||||
|
else
|
||||||
|
hp = proxy_gethostbyname(node, &ghdata);
|
||||||
|
|
||||||
if(hp)
|
if(hp)
|
||||||
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 err2;
|
||||||
|
} else if(node) {
|
||||||
|
af = ((struct sockaddr_in *) &space->sockaddr_space)->sin_family;
|
||||||
|
} else if(!node && !(hints->ai_flags & AI_PASSIVE)) {
|
||||||
|
af = ((struct sockaddr_in *) &space->sockaddr_space)->sin_family = AF_INET;
|
||||||
|
memcpy(&((struct sockaddr_in *) &space->sockaddr_space)->sin_addr,
|
||||||
|
(char[]){127,0,0,1}, 4);
|
||||||
}
|
}
|
||||||
if(service) getservbyname_r(service, NULL, &se_buf, buf, sizeof(buf), &se);
|
if(service) mygetservbyname_r(service, NULL, &se_buf, buf, sizeof(buf), &se);
|
||||||
|
|
||||||
port = se ? se->s_port : htons(atoi(service ? service : "0"));
|
port = se ? se->s_port : htons(atoi(service ? service : "0"));
|
||||||
((struct sockaddr_in *) &space->sockaddr_space)->sin_port = port;
|
if(af == AF_INET)
|
||||||
|
((struct sockaddr_in *) &space->sockaddr_space)->sin_port = port;
|
||||||
|
else
|
||||||
|
((struct sockaddr_in6 *) &space->sockaddr_space)->sin6_port = port;
|
||||||
|
|
||||||
*res = p = &space->addrinfo_space;
|
*res = p = &space->addrinfo_space;
|
||||||
assert((size_t)p == (size_t) space);
|
assert((size_t)p == (size_t) space);
|
||||||
|
|
||||||
p->ai_addr = &space->sockaddr_space;
|
p->ai_addr = (void*) &space->sockaddr_space;
|
||||||
if(node)
|
if(node)
|
||||||
snprintf(space->addr_name, sizeof(space->addr_name), "%s", node);
|
snprintf(space->addr_name, sizeof(space->addr_name), "%s", node);
|
||||||
p->ai_canonname = space->addr_name;
|
p->ai_canonname = space->addr_name;
|
||||||
p->ai_next = NULL;
|
p->ai_next = NULL;
|
||||||
p->ai_family = space->sockaddr_space.sa_family = AF_INET;
|
p->ai_family = space->sockaddr_space.ss_family = af;
|
||||||
p->ai_addrlen = sizeof(space->sockaddr_space);
|
p->ai_addrlen = af == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6);
|
||||||
|
|
||||||
if(hints) {
|
if(hints) {
|
||||||
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;
|
||||||
} else {
|
} else {
|
||||||
|
#ifndef AI_V4MAPPED
|
||||||
|
#define AI_V4MAPPED 0
|
||||||
|
#endif
|
||||||
p->ai_flags = (AI_V4MAPPED | AI_ADDRCONFIG);
|
p->ai_flags = (AI_V4MAPPED | AI_ADDRCONFIG);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+14
-5
@@ -23,8 +23,8 @@
|
|||||||
|
|
||||||
#ifndef __CORE_HEADER
|
#ifndef __CORE_HEADER
|
||||||
#define __CORE_HEADER
|
#define __CORE_HEADER
|
||||||
#define BUFF_SIZE 8*1024 // used to read responses from proxies.
|
|
||||||
#define MAX_LOCALNET 64
|
#define MAX_LOCALNET 64
|
||||||
|
#define MAX_DNAT 64
|
||||||
|
|
||||||
#include "ip_type.h"
|
#include "ip_type.h"
|
||||||
|
|
||||||
@@ -41,7 +41,8 @@ typedef enum {
|
|||||||
typedef enum {
|
typedef enum {
|
||||||
HTTP_TYPE,
|
HTTP_TYPE,
|
||||||
SOCKS4_TYPE,
|
SOCKS4_TYPE,
|
||||||
SOCKS5_TYPE
|
SOCKS5_TYPE,
|
||||||
|
RAW_TYPE
|
||||||
} proxy_type;
|
} proxy_type;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@@ -68,6 +69,11 @@ typedef struct {
|
|||||||
unsigned short port;
|
unsigned short port;
|
||||||
} localaddr_arg;
|
} localaddr_arg;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
struct in_addr orig_dst, new_dst;
|
||||||
|
unsigned short orig_port, new_port;
|
||||||
|
} dnat_arg;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
ip_type ip;
|
ip_type ip;
|
||||||
unsigned short port;
|
unsigned short port;
|
||||||
@@ -78,8 +84,7 @@ typedef struct {
|
|||||||
} proxy_data;
|
} proxy_data;
|
||||||
|
|
||||||
int connect_proxy_chain (int sock, ip_type target_ip, unsigned short target_port,
|
int connect_proxy_chain (int sock, ip_type target_ip, unsigned short target_port,
|
||||||
proxy_data * pd, unsigned int proxy_count, chain_type ct,
|
proxy_data * pd, unsigned int proxy_count, chain_type ct );
|
||||||
unsigned int max_chain );
|
|
||||||
|
|
||||||
void proxychains_write_log(char *str, ...);
|
void proxychains_write_log(char *str, ...);
|
||||||
|
|
||||||
@@ -111,10 +116,11 @@ struct gethostbyname_data {
|
|||||||
struct hostent hostent_space;
|
struct hostent hostent_space;
|
||||||
in_addr_t resolved_addr;
|
in_addr_t resolved_addr;
|
||||||
char *resolved_addr_p[2];
|
char *resolved_addr_p[2];
|
||||||
char addr_name[1024 * 8];
|
char addr_name[256];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct hostent* proxy_gethostbyname(const char *name, struct gethostbyname_data *data);
|
struct hostent* proxy_gethostbyname(const char *name, struct gethostbyname_data *data);
|
||||||
|
struct hostent* proxy_gethostbyname_old(const char *name);
|
||||||
|
|
||||||
int proxy_getaddrinfo(const char *node, const char *service,
|
int proxy_getaddrinfo(const char *node, const char *service,
|
||||||
const struct addrinfo *hints, struct addrinfo **res);
|
const struct addrinfo *hints, struct addrinfo **res);
|
||||||
@@ -123,6 +129,9 @@ void proxy_freeaddrinfo(struct addrinfo *res);
|
|||||||
void core_initialize(void);
|
void core_initialize(void);
|
||||||
void core_unload(void);
|
void core_unload(void);
|
||||||
|
|
||||||
|
extern unsigned int proxychains_max_chain;
|
||||||
|
extern unsigned int proxychains_fixed_chain;
|
||||||
|
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -0,0 +1,231 @@
|
|||||||
|
/*
|
||||||
|
proxychains-ng DNS daemon
|
||||||
|
|
||||||
|
Copyright (C) 2020 rofl0r.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
#include <unistd.h>
|
||||||
|
#define _POSIX_C_SOURCE 200809L
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <sys/select.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include "udpserver.h"
|
||||||
|
#include "sblist.h"
|
||||||
|
#include "hsearch.h"
|
||||||
|
#include "../remotedns.h"
|
||||||
|
#include "../ip_type.h"
|
||||||
|
|
||||||
|
#ifndef MAX
|
||||||
|
#define MAX(x, y) ((x) > (y) ? (x) : (y))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static struct htab *ip_lookup_table;
|
||||||
|
static sblist *hostnames;
|
||||||
|
static unsigned remote_subnet;
|
||||||
|
static const struct server* server;
|
||||||
|
|
||||||
|
#ifndef CONFIG_LOG
|
||||||
|
#define CONFIG_LOG 1
|
||||||
|
#endif
|
||||||
|
#if CONFIG_LOG
|
||||||
|
/* we log to stderr because it's not using line buffering, i.e. malloc which would need
|
||||||
|
locking when called from different threads. for the same reason we use dprintf,
|
||||||
|
which writes directly to an fd. */
|
||||||
|
#define dolog(...) dprintf(2, __VA_ARGS__)
|
||||||
|
#else
|
||||||
|
static void dolog(const char* fmt, ...) { }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static char* my_inet_ntoa(unsigned char *ip_buf_4_bytes, char *outbuf_16_bytes) {
|
||||||
|
unsigned char *p;
|
||||||
|
char *o = outbuf_16_bytes;
|
||||||
|
unsigned char n;
|
||||||
|
for(p = ip_buf_4_bytes; p < ip_buf_4_bytes + 4; p++) {
|
||||||
|
n = *p;
|
||||||
|
if(*p >= 100) {
|
||||||
|
if(*p >= 200)
|
||||||
|
*(o++) = '2';
|
||||||
|
else
|
||||||
|
*(o++) = '1';
|
||||||
|
n %= 100;
|
||||||
|
}
|
||||||
|
if(*p >= 10) {
|
||||||
|
*(o++) = (n / 10) + '0';
|
||||||
|
n %= 10;
|
||||||
|
}
|
||||||
|
*(o++) = n + '0';
|
||||||
|
*(o++) = '.';
|
||||||
|
}
|
||||||
|
o[-1] = 0;
|
||||||
|
return outbuf_16_bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* buf needs to be long enough for an ipv6 addr, i.e. INET6_ADDRSTRLEN + 1 */
|
||||||
|
static char* ipstr(union sockaddr_union *su, char* buf) {
|
||||||
|
int af = SOCKADDR_UNION_AF(su);
|
||||||
|
void *ipdata = SOCKADDR_UNION_ADDRESS(su);
|
||||||
|
inet_ntop(af, ipdata, buf, INET6_ADDRSTRLEN+1);
|
||||||
|
char portbuf[7];
|
||||||
|
snprintf(portbuf, sizeof portbuf, ":%u", (unsigned) ntohs(SOCKADDR_UNION_PORT(su)));
|
||||||
|
strcat(buf, portbuf);
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int usage(char *a0) {
|
||||||
|
dprintf(2,
|
||||||
|
"Proxychains-NG remote dns daemon\n"
|
||||||
|
"--------------------------------\n"
|
||||||
|
"usage: %s -i listenip -p port -r remotesubnet\n"
|
||||||
|
"all arguments are optional.\n"
|
||||||
|
"by default listenip is 127.0.0.1, port 1053 and remotesubnet 224.\n\n", a0
|
||||||
|
);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned index_from_ip(ip_type4 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 *host_from_ip(ip_type4 internalip) {
|
||||||
|
char *res = NULL;
|
||||||
|
unsigned index = index_from_ip(internalip);
|
||||||
|
if(index < sblist_getsize(hostnames)) {
|
||||||
|
char **tmp = sblist_get(hostnames, index);
|
||||||
|
if(tmp && *tmp) res = *tmp;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
ip_type4 get_ip_from_index(unsigned index) {
|
||||||
|
ip_type4 ret;
|
||||||
|
index++; // so we can start at .0.0.1
|
||||||
|
if(index > 0xFFFFFF)
|
||||||
|
return IPT4_INVALID;
|
||||||
|
ret.octet[0] = remote_subnet & 0xFF;
|
||||||
|
ret.octet[1] = (index & 0xFF0000) >> 16;
|
||||||
|
ret.octet[2] = (index & 0xFF00) >> 8;
|
||||||
|
ret.octet[3] = index & 0xFF;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ip_type4 get_ip(char* hn) {
|
||||||
|
htab_value *v = htab_find(ip_lookup_table, hn);
|
||||||
|
if(v) return get_ip_from_index(v->n);
|
||||||
|
char *n = strdup(hn);
|
||||||
|
if(!n) return IPT4_INVALID;
|
||||||
|
if(!sblist_add(hostnames, &n)) {
|
||||||
|
o_out:;
|
||||||
|
free(n);
|
||||||
|
return IPT4_INVALID;
|
||||||
|
}
|
||||||
|
if(!htab_insert(ip_lookup_table, n, HTV_N(sblist_getsize(hostnames)-1))) {
|
||||||
|
sblist_delete(hostnames, sblist_getsize(hostnames)-1);
|
||||||
|
goto o_out;
|
||||||
|
}
|
||||||
|
return get_ip_from_index(sblist_getsize(hostnames)-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
int ch;
|
||||||
|
const char *listenip = "127.0.0.1";
|
||||||
|
unsigned port = 1053;
|
||||||
|
remote_subnet = 224;
|
||||||
|
while((ch = getopt(argc, argv, ":r:i:p:")) != -1) {
|
||||||
|
switch(ch) {
|
||||||
|
case 'r':
|
||||||
|
remote_subnet = atoi(optarg);
|
||||||
|
break;
|
||||||
|
case 'i':
|
||||||
|
listenip = optarg;
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
port = atoi(optarg);
|
||||||
|
break;
|
||||||
|
case ':':
|
||||||
|
dprintf(2, "error: option -%c requires an operand\n", optopt);
|
||||||
|
/* fall through */
|
||||||
|
case '?':
|
||||||
|
return usage(argv[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
signal(SIGPIPE, SIG_IGN);
|
||||||
|
struct server s;
|
||||||
|
if(server_setup(&s, listenip, port)) {
|
||||||
|
perror("server_setup");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
server = &s;
|
||||||
|
|
||||||
|
ip_lookup_table = htab_create(64);
|
||||||
|
hostnames = sblist_new(sizeof(char*), 64);
|
||||||
|
|
||||||
|
while(1) {
|
||||||
|
struct client c;
|
||||||
|
char ipstr_buf[INET6_ADDRSTRLEN+6+1];
|
||||||
|
char ip4str_buf[16];
|
||||||
|
struct at_msg msg, out;
|
||||||
|
size_t msgl = sizeof(msg);
|
||||||
|
int failed = 0;
|
||||||
|
|
||||||
|
#define FAIL() do { failed=1; goto sendresp; } while(0)
|
||||||
|
|
||||||
|
if(server_waitclient(&s, &c, &msg, &msgl)) continue;
|
||||||
|
msg.h.datalen = ntohs(msg.h.datalen);
|
||||||
|
if(msgl != sizeof(msg.h)+msg.h.datalen) {
|
||||||
|
dolog("%s: invalid datalen\n", ipstr(&c.addr, ipstr_buf));
|
||||||
|
FAIL();
|
||||||
|
}
|
||||||
|
|
||||||
|
out.h.msgtype = msg.h.msgtype;
|
||||||
|
if(msg.h.msgtype == ATM_GETIP) {
|
||||||
|
if(!memchr(msg.m.host, 0, msg.h.datalen)) {
|
||||||
|
dolog("%s: nul terminator missing\n", ipstr(&c.addr, ipstr_buf));
|
||||||
|
FAIL();
|
||||||
|
}
|
||||||
|
out.h.datalen = sizeof(ip_type4);
|
||||||
|
out.m.ip = get_ip(msg.m.host);
|
||||||
|
failed = !memcmp(&out.m.ip, &IPT4_INVALID, 4);
|
||||||
|
dolog("%s requested ip for %s (%s)\n", ipstr(&c.addr, ipstr_buf),
|
||||||
|
msg.m.host, failed?"FAIL":my_inet_ntoa((void*)&out.m.ip, ip4str_buf));
|
||||||
|
if(failed) FAIL();
|
||||||
|
} else if (msg.h.msgtype == ATM_GETNAME) {
|
||||||
|
if(msg.h.datalen != 4) {
|
||||||
|
dolog("%s: invalid len for getname request\n", ipstr(&c.addr, ipstr_buf));
|
||||||
|
FAIL();
|
||||||
|
}
|
||||||
|
char *hn = host_from_ip(msg.m.ip);
|
||||||
|
if(hn) {
|
||||||
|
size_t l = strlen(hn);
|
||||||
|
memcpy(out.m.host, hn, l+1);
|
||||||
|
out.h.datalen = l+1;
|
||||||
|
}
|
||||||
|
dolog("%s requested name for %s (%s)\n", ipstr(&c.addr, ipstr_buf),
|
||||||
|
my_inet_ntoa((void*) &msg.m.ip, ip4str_buf), hn?hn:"FAIL");
|
||||||
|
if(!hn) FAIL();
|
||||||
|
} else {
|
||||||
|
dolog("%s: unknown request %u\n", ipstr(&c.addr, ipstr_buf),
|
||||||
|
(unsigned) msg.h.msgtype);
|
||||||
|
}
|
||||||
|
sendresp:;
|
||||||
|
if(failed) {
|
||||||
|
out.h.msgtype = ATM_FAIL;
|
||||||
|
out.h.datalen = 0;
|
||||||
|
}
|
||||||
|
unsigned short dlen = out.h.datalen;
|
||||||
|
out.h.datalen = htons(dlen);
|
||||||
|
sendto(server->fd, &out, sizeof(out.h)+dlen, 0, (void*) &c.addr, SOCKADDR_UNION_LENGTH(&c.addr));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,188 @@
|
|||||||
|
/*
|
||||||
|
musl license, hsearch.c originally written by Szabolcs Nagy
|
||||||
|
|
||||||
|
Copyright © 2005-2020 Rich Felker, et al.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
"Software"), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||||
|
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||||
|
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||||
|
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "hsearch.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
open addressing hash table with 2^n table size
|
||||||
|
quadratic probing is used in case of hash collision
|
||||||
|
tab indices and hash are size_t
|
||||||
|
after resize fails with ENOMEM the state of tab is still usable
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct htab_entry {
|
||||||
|
char *key;
|
||||||
|
htab_value data;
|
||||||
|
} htab_entry;
|
||||||
|
|
||||||
|
struct elem {
|
||||||
|
htab_entry item;
|
||||||
|
size_t hash;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct htab {
|
||||||
|
struct elem *elems;
|
||||||
|
size_t mask;
|
||||||
|
size_t used;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define MINSIZE 8
|
||||||
|
#define MAXSIZE ((size_t)-1/2 + 1)
|
||||||
|
|
||||||
|
static size_t keyhash(char *k)
|
||||||
|
{
|
||||||
|
unsigned char *p = (void *)k;
|
||||||
|
size_t h = 0;
|
||||||
|
|
||||||
|
while (*p)
|
||||||
|
h = 31*h + *p++;
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int resize(struct htab *htab, size_t nel)
|
||||||
|
{
|
||||||
|
size_t newsize;
|
||||||
|
size_t i, j;
|
||||||
|
struct elem *e, *newe;
|
||||||
|
struct elem *oldtab = htab->elems;
|
||||||
|
struct elem *oldend = htab->elems + htab->mask + 1;
|
||||||
|
|
||||||
|
if (nel > MAXSIZE)
|
||||||
|
nel = MAXSIZE;
|
||||||
|
for (newsize = MINSIZE; newsize < nel; newsize *= 2);
|
||||||
|
htab->elems = calloc(newsize, sizeof *htab->elems);
|
||||||
|
if (!htab->elems) {
|
||||||
|
htab->elems = oldtab;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
htab->mask = newsize - 1;
|
||||||
|
if (!oldtab)
|
||||||
|
return 1;
|
||||||
|
for (e = oldtab; e < oldend; e++)
|
||||||
|
if (e->item.key) {
|
||||||
|
for (i=e->hash,j=1; ; i+=j++) {
|
||||||
|
newe = htab->elems + (i & htab->mask);
|
||||||
|
if (!newe->item.key)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
*newe = *e;
|
||||||
|
}
|
||||||
|
free(oldtab);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct elem *lookup(struct htab *htab, char *key, size_t hash)
|
||||||
|
{
|
||||||
|
size_t i, j;
|
||||||
|
struct elem *e;
|
||||||
|
|
||||||
|
for (i=hash,j=1; ; i+=j++) {
|
||||||
|
e = htab->elems + (i & htab->mask);
|
||||||
|
if (!e->item.key ||
|
||||||
|
(e->hash==hash && strcmp(e->item.key, key)==0))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct htab *htab_create(size_t nel)
|
||||||
|
{
|
||||||
|
struct htab *r = calloc(1, sizeof *r);
|
||||||
|
if(r && !resize(r, nel)) {
|
||||||
|
free(r);
|
||||||
|
r = 0;
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
void htab_destroy(struct htab *htab)
|
||||||
|
{
|
||||||
|
free(htab->elems);
|
||||||
|
free(htab);
|
||||||
|
}
|
||||||
|
|
||||||
|
static htab_entry *htab_find_item(struct htab *htab, char* key)
|
||||||
|
{
|
||||||
|
size_t hash = keyhash(key);
|
||||||
|
struct elem *e = lookup(htab, key, hash);
|
||||||
|
|
||||||
|
if (e->item.key) {
|
||||||
|
return &e->item;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
htab_value* htab_find(struct htab *htab, char* key)
|
||||||
|
{
|
||||||
|
htab_entry *i = htab_find_item(htab, key);
|
||||||
|
if(i) return &i->data;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int htab_delete(struct htab *htab, char* key)
|
||||||
|
{
|
||||||
|
htab_entry *i = htab_find_item(htab, key);
|
||||||
|
if(!i) return 0;
|
||||||
|
i->key = 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int htab_insert(struct htab *htab, char* key, htab_value value)
|
||||||
|
{
|
||||||
|
size_t hash = keyhash(key);
|
||||||
|
struct elem *e = lookup(htab, key, hash);
|
||||||
|
if(e->item.key) {
|
||||||
|
/* it's not allowed to overwrite existing data */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
e->item.key = key;
|
||||||
|
e->item.data = value;
|
||||||
|
e->hash = hash;
|
||||||
|
if (++htab->used > htab->mask - htab->mask/4) {
|
||||||
|
if (!resize(htab, 2*htab->used)) {
|
||||||
|
htab->used--;
|
||||||
|
e->item.key = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t htab_next(struct htab *htab, size_t iterator, char** key, htab_value **v)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
for(i=iterator;i<htab->mask+1;++i) {
|
||||||
|
struct elem *e = htab->elems + i;
|
||||||
|
if(e->item.key) {
|
||||||
|
*key = e->item.key;
|
||||||
|
*v = &e->item.data;
|
||||||
|
return i+1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
#ifndef HSEARCH_H
|
||||||
|
#define HSEARCH_H
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
typedef union htab_value {
|
||||||
|
void *p;
|
||||||
|
size_t n;
|
||||||
|
} htab_value;
|
||||||
|
|
||||||
|
#define HTV_N(N) (htab_value) {.n = N}
|
||||||
|
#define HTV_P(P) (htab_value) {.p = P}
|
||||||
|
|
||||||
|
struct htab * htab_create(size_t);
|
||||||
|
void htab_destroy(struct htab *);
|
||||||
|
htab_value* htab_find(struct htab *, char* key);
|
||||||
|
int htab_insert(struct htab *, char*, htab_value);
|
||||||
|
int htab_delete(struct htab *htab, char* key);
|
||||||
|
size_t htab_next(struct htab *, size_t iterator, char** key, htab_value **v);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
#undef _POSIX_C_SOURCE
|
||||||
|
#define _POSIX_C_SOURCE 200809L
|
||||||
|
#include "sblist.h"
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#define MY_PAGE_SIZE 4096
|
||||||
|
|
||||||
|
sblist* sblist_new(size_t itemsize, size_t blockitems) {
|
||||||
|
sblist* ret = (sblist*) malloc(sizeof(sblist));
|
||||||
|
sblist_init(ret, itemsize, blockitems);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sblist_clear(sblist* l) {
|
||||||
|
l->items = NULL;
|
||||||
|
l->capa = 0;
|
||||||
|
l->count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sblist_init(sblist* l, size_t itemsize, size_t blockitems) {
|
||||||
|
if(l) {
|
||||||
|
l->blockitems = blockitems ? blockitems : MY_PAGE_SIZE / itemsize;
|
||||||
|
l->itemsize = itemsize;
|
||||||
|
sblist_clear(l);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void sblist_free_items(sblist* l) {
|
||||||
|
if(l) {
|
||||||
|
if(l->items) free(l->items);
|
||||||
|
sblist_clear(l);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void sblist_free(sblist* l) {
|
||||||
|
if(l) {
|
||||||
|
sblist_free_items(l);
|
||||||
|
free(l);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char* sblist_item_from_index(sblist* l, size_t idx) {
|
||||||
|
return l->items + (idx * l->itemsize);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* sblist_get(sblist* l, size_t item) {
|
||||||
|
if(item < l->count) return (void*) sblist_item_from_index(l, item);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sblist_set(sblist* l, void* item, size_t pos) {
|
||||||
|
if(pos >= l->count) return 0;
|
||||||
|
memcpy(sblist_item_from_index(l, pos), item, l->itemsize);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sblist_grow_if_needed(sblist* l) {
|
||||||
|
char* temp;
|
||||||
|
if(l->count == l->capa) {
|
||||||
|
temp = realloc(l->items, (l->capa + l->blockitems) * l->itemsize);
|
||||||
|
if(!temp) return 0;
|
||||||
|
l->capa += l->blockitems;
|
||||||
|
l->items = temp;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sblist_add(sblist* l, void* item) {
|
||||||
|
if(!sblist_grow_if_needed(l)) return 0;
|
||||||
|
l->count++;
|
||||||
|
return sblist_set(l, item, l->count - 1);
|
||||||
|
}
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
#ifndef SBLIST_H
|
||||||
|
#define SBLIST_H
|
||||||
|
|
||||||
|
/* this file is part of libulz, as of commit 8ab361a27743aaf025323ee43b8b8876dc054fdd
|
||||||
|
modified for direct inclusion in microsocks. */
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
/*
|
||||||
|
* simple buffer list.
|
||||||
|
*
|
||||||
|
* this thing here is basically a generic dynamic array
|
||||||
|
* will realloc after every blockitems inserts
|
||||||
|
* can store items of any size.
|
||||||
|
*
|
||||||
|
* so think of it as a by-value list, as opposed to a typical by-ref list.
|
||||||
|
* you typically use it by having some struct on the stack, and pass a pointer
|
||||||
|
* to sblist_add, which will copy the contents into its internal memory.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
size_t itemsize;
|
||||||
|
size_t blockitems;
|
||||||
|
size_t count;
|
||||||
|
size_t capa;
|
||||||
|
char* items;
|
||||||
|
} sblist;
|
||||||
|
|
||||||
|
#define sblist_getsize(X) ((X)->count)
|
||||||
|
#define sblist_get_count(X) ((X)->count)
|
||||||
|
#define sblist_empty(X) ((X)->count == 0)
|
||||||
|
|
||||||
|
// for dynamic style
|
||||||
|
sblist* sblist_new(size_t itemsize, size_t blockitems);
|
||||||
|
void sblist_free(sblist* l);
|
||||||
|
|
||||||
|
//for static style
|
||||||
|
void sblist_init(sblist* l, size_t itemsize, size_t blockitems);
|
||||||
|
void sblist_free_items(sblist* l);
|
||||||
|
|
||||||
|
// accessors
|
||||||
|
void* sblist_get(sblist* l, size_t item);
|
||||||
|
// returns 1 on success, 0 on OOM
|
||||||
|
int sblist_add(sblist* l, void* item);
|
||||||
|
int sblist_set(sblist* l, void* item, size_t pos);
|
||||||
|
void sblist_delete(sblist* l, size_t item);
|
||||||
|
char* sblist_item_from_index(sblist* l, size_t idx);
|
||||||
|
int sblist_grow_if_needed(sblist* l);
|
||||||
|
int sblist_insert(sblist* l, void* item, size_t pos);
|
||||||
|
/* same as sblist_add, but returns list index of new item, or -1 */
|
||||||
|
size_t sblist_addi(sblist* l, void* item);
|
||||||
|
void sblist_sort(sblist *l, int (*compar)(const void *, const void *));
|
||||||
|
/* insert element into presorted list, returns listindex of new entry or -1*/
|
||||||
|
size_t sblist_insert_sorted(sblist* l, void* o, int (*compar)(const void *, const void *));
|
||||||
|
|
||||||
|
#ifndef __COUNTER__
|
||||||
|
#define __COUNTER__ __LINE__
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define __sblist_concat_impl( x, y ) x##y
|
||||||
|
#define __sblist_macro_concat( x, y ) __sblist_concat_impl( x, y )
|
||||||
|
#define __sblist_iterator_name __sblist_macro_concat(sblist_iterator, __COUNTER__)
|
||||||
|
|
||||||
|
// use with custom iterator variable
|
||||||
|
#define sblist_iter_counter(LIST, ITER, PTR) \
|
||||||
|
for(size_t ITER = 0; (PTR = sblist_get(LIST, ITER)), ITER < sblist_getsize(LIST); ITER++)
|
||||||
|
|
||||||
|
// use with custom iterator variable, which is predeclared
|
||||||
|
#define sblist_iter_counter2(LIST, ITER, PTR) \
|
||||||
|
for(ITER = 0; (PTR = sblist_get(LIST, ITER)), ITER < sblist_getsize(LIST); ITER++)
|
||||||
|
|
||||||
|
// use with custom iterator variable, which is predeclared and signed
|
||||||
|
// useful for a loop which can delete items from the list, and then decrease the iterator var.
|
||||||
|
#define sblist_iter_counter2s(LIST, ITER, PTR) \
|
||||||
|
for(ITER = 0; (PTR = sblist_get(LIST, ITER)), ITER < (ssize_t) sblist_getsize(LIST); ITER++)
|
||||||
|
|
||||||
|
|
||||||
|
// uses "magic" iterator variable
|
||||||
|
#define sblist_iter(LIST, PTR) sblist_iter_counter(LIST, __sblist_iterator_name, PTR)
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#pragma RcB2 DEP "sblist.c" "sblist_delete.c"
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
#include "sblist.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
void sblist_delete(sblist* l, size_t item) {
|
||||||
|
if (l->count && item < l->count) {
|
||||||
|
memmove(sblist_item_from_index(l, item), sblist_item_from_index(l, item + 1), (sblist_getsize(l) - (item + 1)) * l->itemsize);
|
||||||
|
l->count--;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include "../remotedns.h"
|
||||||
|
#include "../ip_type.h"
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
int fd;
|
||||||
|
int port = 1053;
|
||||||
|
char srvn[] = "127.0.0.1";
|
||||||
|
struct sockaddr_in srva = {.sin_family = AF_INET, .sin_port = htons(port)};
|
||||||
|
inet_pton(AF_INET, srvn, &srva.sin_addr);
|
||||||
|
fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||||
|
char namebuf[260];
|
||||||
|
while(fgets(namebuf, sizeof namebuf, stdin)) {
|
||||||
|
size_t l = strlen(namebuf);
|
||||||
|
if(namebuf[l-1] == '\n') {
|
||||||
|
l--;
|
||||||
|
namebuf[l] = 0;
|
||||||
|
}
|
||||||
|
struct at_msg msg = {0};
|
||||||
|
unsigned msglen;
|
||||||
|
if(isdigit(namebuf[0])) {
|
||||||
|
msglen = 4;
|
||||||
|
msg.h.msgtype = ATM_GETNAME;
|
||||||
|
inet_aton(namebuf, (void*) &msg.m.ip);
|
||||||
|
} else {
|
||||||
|
msglen = l+1;
|
||||||
|
msg.h.msgtype = ATM_GETIP;
|
||||||
|
memcpy(msg.m.host, namebuf, msglen);
|
||||||
|
}
|
||||||
|
msg.h.datalen = htons(msglen);
|
||||||
|
sendto(fd, &msg, sizeof(msg.h)+msglen, 0, (void*)&srva, sizeof(srva));
|
||||||
|
char rcvbuf[512];
|
||||||
|
recvfrom(fd, rcvbuf, sizeof rcvbuf, 0, (void*)0, (void*)0);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
#include "udpserver.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
int resolve(const char *host, unsigned short port, struct addrinfo** addr) {
|
||||||
|
struct addrinfo hints = {
|
||||||
|
.ai_family = AF_UNSPEC,
|
||||||
|
.ai_socktype = SOCK_STREAM,
|
||||||
|
.ai_flags = AI_PASSIVE,
|
||||||
|
};
|
||||||
|
char port_buf[8];
|
||||||
|
snprintf(port_buf, sizeof port_buf, "%u", port);
|
||||||
|
return getaddrinfo(host, port_buf, &hints, addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
int resolve_sa(const char *host, unsigned short port, union sockaddr_union *res) {
|
||||||
|
struct addrinfo *ainfo = 0;
|
||||||
|
int ret;
|
||||||
|
SOCKADDR_UNION_AF(res) = AF_UNSPEC;
|
||||||
|
if((ret = resolve(host, port, &ainfo))) return ret;
|
||||||
|
memcpy(res, ainfo->ai_addr, ainfo->ai_addrlen);
|
||||||
|
freeaddrinfo(ainfo);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int bindtoip(int fd, union sockaddr_union *bindaddr) {
|
||||||
|
socklen_t sz = SOCKADDR_UNION_LENGTH(bindaddr);
|
||||||
|
if(sz)
|
||||||
|
return bind(fd, (struct sockaddr*) bindaddr, sz);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int server_waitclient(struct server *server, struct client* client, void* buf, size_t *buflen) {
|
||||||
|
socklen_t clen = sizeof client->addr;
|
||||||
|
ssize_t ret = recvfrom(server->fd, buf, *buflen, 0, (void*)&client->addr, &clen);
|
||||||
|
if(ret >= 0) {
|
||||||
|
*buflen = ret;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int server_setup(struct server *server, const char* listenip, unsigned short port) {
|
||||||
|
struct addrinfo *ainfo = 0;
|
||||||
|
if(resolve(listenip, port, &ainfo)) return -1;
|
||||||
|
struct addrinfo* p;
|
||||||
|
int listenfd = -1;
|
||||||
|
for(p = ainfo; p; p = p->ai_next) {
|
||||||
|
if((listenfd = socket(p->ai_family, SOCK_DGRAM, 0)) < 0)
|
||||||
|
continue;
|
||||||
|
int yes = 1;
|
||||||
|
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
|
||||||
|
if(bind(listenfd, p->ai_addr, p->ai_addrlen) < 0) {
|
||||||
|
close(listenfd);
|
||||||
|
listenfd = -1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
freeaddrinfo(ainfo);
|
||||||
|
if(listenfd < 0) return -2;
|
||||||
|
server->fd = listenfd;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
#ifndef SERVER_H
|
||||||
|
#define SERVER_H
|
||||||
|
|
||||||
|
#undef _POSIX_C_SOURCE
|
||||||
|
#define _POSIX_C_SOURCE 200809L
|
||||||
|
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
|
||||||
|
#pragma RcB2 DEP "udpserver.c"
|
||||||
|
|
||||||
|
union sockaddr_union {
|
||||||
|
struct sockaddr_in v4;
|
||||||
|
struct sockaddr_in6 v6;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define SOCKADDR_UNION_AF(PTR) (PTR)->v4.sin_family
|
||||||
|
|
||||||
|
#define SOCKADDR_UNION_LENGTH(PTR) ( \
|
||||||
|
( SOCKADDR_UNION_AF(PTR) == AF_INET ) ? sizeof((PTR)->v4) : ( \
|
||||||
|
( SOCKADDR_UNION_AF(PTR) == AF_INET6 ) ? sizeof((PTR)->v6) : 0 ) )
|
||||||
|
|
||||||
|
#define SOCKADDR_UNION_ADDRESS(PTR) ( \
|
||||||
|
( SOCKADDR_UNION_AF(PTR) == AF_INET ) ? (void*) &(PTR)->v4.sin_addr : ( \
|
||||||
|
( SOCKADDR_UNION_AF(PTR) == AF_INET6 ) ? (void*) &(PTR)->v6.sin6_addr : (void*) 0 ) )
|
||||||
|
|
||||||
|
#define SOCKADDR_UNION_PORT(PTR) ( \
|
||||||
|
( SOCKADDR_UNION_AF(PTR) == AF_INET ) ? (PTR)->v4.sin_port : ( \
|
||||||
|
( SOCKADDR_UNION_AF(PTR) == AF_INET6 ) ? (PTR)->v6.sin6_port : 0 ) )
|
||||||
|
|
||||||
|
struct client {
|
||||||
|
union sockaddr_union addr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct server {
|
||||||
|
int fd;
|
||||||
|
};
|
||||||
|
|
||||||
|
int resolve(const char *host, unsigned short port, struct addrinfo** addr);
|
||||||
|
int resolve_sa(const char *host, unsigned short port, union sockaddr_union *res);
|
||||||
|
int bindtoip(int fd, union sockaddr_union *bindaddr);
|
||||||
|
|
||||||
|
int server_waitclient(struct server *server, struct client* client, void* buf, size_t *buflen);
|
||||||
|
int server_setup(struct server *server, const char* listenip, unsigned short port);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
+13
-3
@@ -3,11 +3,15 @@
|
|||||||
# include "core.h"
|
# include "core.h"
|
||||||
# include "common.h"
|
# include "common.h"
|
||||||
# include "debug.h"
|
# include "debug.h"
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
void DUMP_PROXY_CHAIN(proxy_data *pchain, unsigned int count) {
|
void dump_proxy_chain(proxy_data *pchain, unsigned int count) {
|
||||||
char ip_buf[16];
|
char ip_buf[INET6_ADDRSTRLEN];
|
||||||
for (; count; pchain++, count--) {
|
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],
|
PDEBUG("[%s] %s %s:%d", proxy_state_strmap[pchain->ps],
|
||||||
proxy_type_strmap[pchain->pt],
|
proxy_type_strmap[pchain->pt],
|
||||||
ip_buf, htons(pchain->port));
|
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
|
#endif
|
||||||
|
|||||||
+11
-7
@@ -1,20 +1,24 @@
|
|||||||
#ifndef DEBUG_H
|
#ifndef DEBUG_H
|
||||||
#define DEBUG_H
|
#define DEBUG_H
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
# include <stdio.h>
|
# include <stdio.h>
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
# define PSTDERR(fmt, args...) do { dprintf(2,fmt, ## args); } while(0)
|
# define PSTDERR(fmt, args...) do { dprintf(2,fmt, ## args); } while(0)
|
||||||
# define PDEBUG(fmt, args...) PSTDERR("DEBUG:"fmt, ## args)
|
# define PDEBUG(fmt, args...) PSTDERR("DEBUG:pid[%d]:" fmt, getpid(), ## args)
|
||||||
|
# define DEBUGDECL(args...) args
|
||||||
# include "core.h"
|
# define DUMP_PROXY_CHAIN(A, B) dump_proxy_chain(A, B)
|
||||||
void DUMP_PROXY_CHAIN(proxy_data *pchain, unsigned int count);
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
# define PDEBUG(fmt, args...) do {} while (0)
|
# define PDEBUG(fmt, args...) do {} while (0)
|
||||||
|
# define DEBUGDECL(args...)
|
||||||
# define DUMP_PROXY_CHAIN(args...) do {} while (0)
|
# define DUMP_PROXY_CHAIN(args...) do {} while (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
# define PFUNC() do { PDEBUG("pid[%d]:%s\n", getpid(), __FUNCTION__); } while(0)
|
# define PFUNC() do { PDEBUG("%s()\n", __FUNCTION__); } while(0)
|
||||||
|
|
||||||
|
#include "core.h"
|
||||||
|
void dump_proxy_chain(proxy_data *pchain, unsigned int count);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
+10
-35
@@ -1,6 +1,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
simple reader for /etc/hosts
|
simple reader for /etc/hosts
|
||||||
@@ -24,7 +25,6 @@ void hostsreader_close(struct hostsreader *ctx) {
|
|||||||
fclose(ctx->f);
|
fclose(ctx->f);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int isnumericipv4(const char* ipstring);
|
|
||||||
int hostsreader_get(struct hostsreader *ctx, char* buf, size_t bufsize) {
|
int hostsreader_get(struct hostsreader *ctx, char* buf, size_t bufsize) {
|
||||||
while(1) {
|
while(1) {
|
||||||
if(!fgets(buf, bufsize, ctx->f)) return 0;
|
if(!fgets(buf, bufsize, ctx->f)) return 0;
|
||||||
@@ -44,14 +44,14 @@ int hostsreader_get(struct hostsreader *ctx, char* buf, size_t bufsize) {
|
|||||||
l--;
|
l--;
|
||||||
}
|
}
|
||||||
if(!l || !*p) continue;
|
if(!l || !*p) continue;
|
||||||
ctx->name = buf;
|
ctx->name = p;
|
||||||
while(*p && !isspace(*p) && l) {
|
while(*p && !isspace(*p) && l) {
|
||||||
p++;
|
p++;
|
||||||
l--;
|
l--;
|
||||||
}
|
}
|
||||||
if(!l || !*p) continue;
|
if(!l || !*p) continue;
|
||||||
*p = 0;
|
*p = 0;
|
||||||
if(isnumericipv4(ctx->ip)) return 1;
|
if(pc_isnumericipv4(ctx->ip)) return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,49 +73,24 @@ char* hostsreader_get_ip_for_name(const char* name, char* buf, size_t bufsize) {
|
|||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <arpa/inet.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 *hres;
|
||||||
char buf[320];
|
char buf[320];
|
||||||
if((hres = hostsreader_get_ip_for_name(name, buf, sizeof buf))) {
|
if((hres = hostsreader_get_ip_for_name(name, buf, sizeof buf))) {
|
||||||
struct in_addr c;
|
struct in_addr c;
|
||||||
inet_aton(hres, &c);
|
inet_aton(hres, &c);
|
||||||
ip_type res;
|
ip_type4 res;
|
||||||
memcpy(res.octet, &c.s_addr, 4);
|
memcpy(res.octet, &c.s_addr, 4);
|
||||||
return res;
|
return res;
|
||||||
} else return ip_type_invalid;
|
} else return IPT4_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HOSTSREADER_TEST
|
#ifdef HOSTSREADER_TEST
|
||||||
int main() {
|
#include "ip_type.c"
|
||||||
|
int main(int a, char**b) {
|
||||||
char buf[256];
|
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");
|
printf("%s\n", ret ? ret : "null");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* isnumericipv4() taken from libulz */
|
|
||||||
static int isnumericipv4(const char* ipstring) {
|
|
||||||
size_t x = 0, n = 0, d = 0;
|
|
||||||
int wasdot = 0;
|
|
||||||
while(1) {
|
|
||||||
switch(ipstring[x]) {
|
|
||||||
case 0: goto done;
|
|
||||||
case '.':
|
|
||||||
if(!n || wasdot) return 0;
|
|
||||||
d++;
|
|
||||||
wasdot = 1;
|
|
||||||
break;
|
|
||||||
case '0': case '1': case '2': case '3': case '4':
|
|
||||||
case '5': case '6': case '7': case '8': case '9':
|
|
||||||
n++;
|
|
||||||
wasdot = 0;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
x++;
|
|
||||||
}
|
|
||||||
done:
|
|
||||||
if(d == 3 && n >= 4 && n <= 12) return 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
#include "ip_type.h"
|
|
||||||
|
|
||||||
const ip_type ip_type_invalid = { .as_int = -1 };
|
|
||||||
const ip_type ip_type_localhost = { {127, 0, 0, 1} };
|
|
||||||
|
|
||||||
+13
-3
@@ -6,10 +6,20 @@
|
|||||||
typedef union {
|
typedef union {
|
||||||
unsigned char octet[4];
|
unsigned char octet[4];
|
||||||
uint32_t as_int;
|
uint32_t as_int;
|
||||||
|
} ip_type4;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
union {
|
||||||
|
ip_type4 v4;
|
||||||
|
unsigned char v6[16];
|
||||||
|
} addr;
|
||||||
|
char is_v6;
|
||||||
} ip_type;
|
} ip_type;
|
||||||
|
|
||||||
extern const ip_type ip_type_invalid;
|
#define IPT4_INT(X) (ip_type4){.as_int = (X)}
|
||||||
extern const ip_type ip_type_localhost;
|
#define IPT4_INVALID IPT4_INT(-1)
|
||||||
|
|
||||||
|
#define IPT4_BYTES(A,B,C,D) (ip_type4){.octet = {(A), (B), (C), (D)} }
|
||||||
|
#define IPT4_LOCALHOST IPT4_BYTES(127,0,0,1)
|
||||||
|
|
||||||
//RcB: DEP "ip_type.c"
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+401
-107
@@ -22,6 +22,7 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
@@ -37,7 +38,9 @@
|
|||||||
|
|
||||||
#include "core.h"
|
#include "core.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
#include "rdns.h"
|
||||||
|
|
||||||
|
#undef satosin
|
||||||
#define satosin(x) ((struct sockaddr_in *) &(x))
|
#define satosin(x) ((struct sockaddr_in *) &(x))
|
||||||
#define SOCKADDR(x) (satosin(x)->sin_addr.s_addr)
|
#define SOCKADDR(x) (satosin(x)->sin_addr.s_addr)
|
||||||
#define SOCKADDR_2(x) (satosin(x)->sin_addr)
|
#define SOCKADDR_2(x) (satosin(x)->sin_addr)
|
||||||
@@ -45,6 +48,12 @@
|
|||||||
#define SOCKFAMILY(x) (satosin(x)->sin_family)
|
#define SOCKFAMILY(x) (satosin(x)->sin_family)
|
||||||
#define MAX_CHAIN 512
|
#define MAX_CHAIN 512
|
||||||
|
|
||||||
|
#ifdef IS_SOLARIS
|
||||||
|
#undef connect
|
||||||
|
int __xnet_connect(int sock, const struct sockaddr *addr, unsigned int len);
|
||||||
|
connect_t true___xnet_connect;
|
||||||
|
#endif
|
||||||
|
|
||||||
close_t true_close;
|
close_t true_close;
|
||||||
connect_t true_connect;
|
connect_t true_connect;
|
||||||
gethostbyname_t true_gethostbyname;
|
gethostbyname_t true_gethostbyname;
|
||||||
@@ -62,17 +71,20 @@ unsigned int proxychains_proxy_count = 0;
|
|||||||
unsigned int proxychains_proxy_offset = 0;
|
unsigned int proxychains_proxy_offset = 0;
|
||||||
int proxychains_got_chain_data = 0;
|
int proxychains_got_chain_data = 0;
|
||||||
unsigned int proxychains_max_chain = 1;
|
unsigned int proxychains_max_chain = 1;
|
||||||
|
unsigned int proxychains_fixed_chain = 0;
|
||||||
int proxychains_quiet_mode = 0;
|
int proxychains_quiet_mode = 0;
|
||||||
int proxychains_resolver = 0;
|
enum dns_lookup_flavor proxychains_resolver = DNSLF_LIBC;
|
||||||
localaddr_arg localnet_addr[MAX_LOCALNET];
|
localaddr_arg localnet_addr[MAX_LOCALNET];
|
||||||
size_t num_localnet_addr = 0;
|
size_t num_localnet_addr = 0;
|
||||||
|
dnat_arg dnats[MAX_DNAT];
|
||||||
|
size_t num_dnats = 0;
|
||||||
unsigned int remote_dns_subnet = 224;
|
unsigned int remote_dns_subnet = 224;
|
||||||
|
|
||||||
pthread_once_t init_once = PTHREAD_ONCE_INIT;
|
pthread_once_t init_once = PTHREAD_ONCE_INIT;
|
||||||
|
|
||||||
static int init_l = 0;
|
static int init_l = 0;
|
||||||
|
|
||||||
static inline 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) {
|
||||||
|
|
||||||
@@ -93,26 +105,13 @@ static void* load_sym(char* symname, void* proxyfunc) {
|
|||||||
|
|
||||||
#define INIT() init_lib_wrapper(__FUNCTION__)
|
#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 "shm.h"
|
|
||||||
#include "allocator_thread.h"
|
#include "allocator_thread.h"
|
||||||
#include "stringdump.h"
|
|
||||||
|
|
||||||
const char *proxychains_get_version(void);
|
const char *proxychains_get_version(void);
|
||||||
|
|
||||||
static void do_init(void) {
|
static void setup_hooks(void) {
|
||||||
srand(time(NULL));
|
|
||||||
dumpstring_init(); // global string garbage can
|
|
||||||
core_initialize();
|
|
||||||
at_init();
|
|
||||||
|
|
||||||
/* read the config file */
|
|
||||||
get_chain_data(proxychains_pd, &proxychains_proxy_count, &proxychains_ct);
|
|
||||||
DUMP_PROXY_CHAIN(proxychains_pd, proxychains_proxy_count);
|
|
||||||
|
|
||||||
proxychains_write_log(LOG_PREFIX "DLL init: proxychains-ng %s\n", proxychains_get_version());
|
|
||||||
|
|
||||||
SETUP_SYM(connect);
|
SETUP_SYM(connect);
|
||||||
SETUP_SYM(sendto);
|
SETUP_SYM(sendto);
|
||||||
SETUP_SYM(gethostbyname);
|
SETUP_SYM(gethostbyname);
|
||||||
@@ -120,21 +119,32 @@ static void do_init(void) {
|
|||||||
SETUP_SYM(freeaddrinfo);
|
SETUP_SYM(freeaddrinfo);
|
||||||
SETUP_SYM(gethostbyaddr);
|
SETUP_SYM(gethostbyaddr);
|
||||||
SETUP_SYM(getnameinfo);
|
SETUP_SYM(getnameinfo);
|
||||||
SETUP_SYM(close);
|
#ifdef IS_SOLARIS
|
||||||
|
SETUP_SYM(__xnet_connect);
|
||||||
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
|
#endif
|
||||||
|
SETUP_SYM(close);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int close_fds[16];
|
||||||
|
static int close_fds_cnt = 0;
|
||||||
|
|
||||||
|
static void do_init(void) {
|
||||||
|
srand(time(NULL));
|
||||||
|
core_initialize();
|
||||||
|
|
||||||
|
/* read the config file */
|
||||||
|
get_chain_data(proxychains_pd, &proxychains_proxy_count, &proxychains_ct);
|
||||||
|
DUMP_PROXY_CHAIN(proxychains_pd, proxychains_proxy_count);
|
||||||
|
|
||||||
|
proxychains_write_log(LOG_PREFIX "DLL init: proxychains-ng %s\n", proxychains_get_version());
|
||||||
|
|
||||||
|
setup_hooks();
|
||||||
|
|
||||||
|
while(close_fds_cnt) true_close(close_fds[--close_fds_cnt]);
|
||||||
|
init_l = 1;
|
||||||
|
|
||||||
|
rdns_init(proxychains_resolver);
|
||||||
|
}
|
||||||
|
|
||||||
static void init_lib_wrapper(const char* caller) {
|
static void init_lib_wrapper(const char* caller) {
|
||||||
#ifndef DEBUG
|
#ifndef DEBUG
|
||||||
@@ -156,24 +166,131 @@ static void gcc_init(void) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
RS_PT_NONE = 0,
|
||||||
|
RS_PT_SOCKS4,
|
||||||
|
RS_PT_SOCKS5,
|
||||||
|
RS_PT_HTTP
|
||||||
|
} rs_proxyType;
|
||||||
|
|
||||||
|
/*
|
||||||
|
proxy_from_string() taken from rocksock network I/O library (C) rofl0r
|
||||||
|
valid inputs:
|
||||||
|
socks5://user:password@proxy.domain.com:port
|
||||||
|
socks5://proxy.domain.com:port
|
||||||
|
socks4://proxy.domain.com:port
|
||||||
|
http://user:password@proxy.domain.com:port
|
||||||
|
http://proxy.domain.com:port
|
||||||
|
|
||||||
|
supplying port number is obligatory.
|
||||||
|
user:pass@ part is optional for http and socks5.
|
||||||
|
however, user:pass authentication is currently not implemented for http proxies.
|
||||||
|
return 1 on success, 0 on error.
|
||||||
|
*/
|
||||||
|
static int proxy_from_string(const char *proxystring,
|
||||||
|
char *type_buf,
|
||||||
|
char* host_buf,
|
||||||
|
int *port_n,
|
||||||
|
char *user_buf,
|
||||||
|
char* pass_buf)
|
||||||
|
{
|
||||||
|
const char* p;
|
||||||
|
rs_proxyType proxytype;
|
||||||
|
|
||||||
|
size_t next_token = 6, ul = 0, pl = 0, hl;
|
||||||
|
if(!proxystring[0] || !proxystring[1] || !proxystring[2] || !proxystring[3] || !proxystring[4] || !proxystring[5]) goto inv_string;
|
||||||
|
if(*proxystring == 's') {
|
||||||
|
switch(proxystring[5]) {
|
||||||
|
case '5': proxytype = RS_PT_SOCKS5; break;
|
||||||
|
case '4': proxytype = RS_PT_SOCKS4; break;
|
||||||
|
default: goto inv_string;
|
||||||
|
}
|
||||||
|
} else if(*proxystring == 'h') {
|
||||||
|
proxytype = RS_PT_HTTP;
|
||||||
|
next_token = 4;
|
||||||
|
} else goto inv_string;
|
||||||
|
if(
|
||||||
|
proxystring[next_token++] != ':' ||
|
||||||
|
proxystring[next_token++] != '/' ||
|
||||||
|
proxystring[next_token++] != '/') goto inv_string;
|
||||||
|
const char *at = strrchr(proxystring+next_token, '@');
|
||||||
|
if(at) {
|
||||||
|
if(proxytype == RS_PT_SOCKS4)
|
||||||
|
return 0;
|
||||||
|
p = strchr(proxystring+next_token, ':');
|
||||||
|
if(!p || p >= at) goto inv_string;
|
||||||
|
const char *u = proxystring+next_token;
|
||||||
|
ul = p-u;
|
||||||
|
p++;
|
||||||
|
pl = at-p;
|
||||||
|
if(proxytype == RS_PT_SOCKS5 && (ul > 255 || pl > 255))
|
||||||
|
return 0;
|
||||||
|
memcpy(user_buf, u, ul);
|
||||||
|
user_buf[ul]=0;
|
||||||
|
memcpy(pass_buf, p, pl);
|
||||||
|
pass_buf[pl]=0;
|
||||||
|
next_token += 2+ul+pl;
|
||||||
|
} else {
|
||||||
|
user_buf[0]=0;
|
||||||
|
pass_buf[0]=0;
|
||||||
|
}
|
||||||
|
const char* h = proxystring+next_token;
|
||||||
|
p = strchr(h, ':');
|
||||||
|
if(!p) goto inv_string;
|
||||||
|
hl = p-h;
|
||||||
|
if(hl > 255)
|
||||||
|
return 0;
|
||||||
|
memcpy(host_buf, h, hl);
|
||||||
|
host_buf[hl]=0;
|
||||||
|
*port_n = atoi(p+1);
|
||||||
|
switch(proxytype) {
|
||||||
|
case RS_PT_SOCKS4:
|
||||||
|
strcpy(type_buf, "socks4");
|
||||||
|
break;
|
||||||
|
case RS_PT_SOCKS5:
|
||||||
|
strcpy(type_buf, "socks5");
|
||||||
|
break;
|
||||||
|
case RS_PT_HTTP:
|
||||||
|
strcpy(type_buf, "http");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
inv_string:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char* bool_str(int bool_val) {
|
||||||
|
if(bool_val) return "true";
|
||||||
|
return "false";
|
||||||
|
}
|
||||||
|
|
||||||
|
#define STR_STARTSWITH(P, LIT) (!strncmp(P, LIT, sizeof(LIT)-1))
|
||||||
/* get configuration from config file */
|
/* get configuration from config file */
|
||||||
static void get_chain_data(proxy_data * pd, unsigned int *proxy_count, chain_type * ct) {
|
static void get_chain_data(proxy_data * pd, unsigned int *proxy_count, chain_type * ct) {
|
||||||
int count = 0, port_n = 0, list = 0;
|
int count = 0, port_n = 0, list = 0;
|
||||||
char buff[1024], type[1024], host[1024], user[1024];
|
char buf[1024], type[1024], host[1024], user[1024];
|
||||||
char *env;
|
char *buff, *env, *p;
|
||||||
char local_in_addr_port[32];
|
char local_in_addr_port[32];
|
||||||
char local_in_addr[32], local_in_port[32], 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[32], dnat_orig_port[32], dnat_new_addr[32], dnat_new_port[32];
|
||||||
|
char rdnsd_addr[32], rdnsd_port[8];
|
||||||
FILE *file = NULL;
|
FILE *file = NULL;
|
||||||
|
|
||||||
if(proxychains_got_chain_data)
|
if(proxychains_got_chain_data)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
PFUNC();
|
||||||
|
|
||||||
//Some defaults
|
//Some defaults
|
||||||
tcp_read_time_out = 4 * 1000;
|
tcp_read_time_out = 4 * 1000;
|
||||||
tcp_connect_time_out = 10 * 1000;
|
tcp_connect_time_out = 10 * 1000;
|
||||||
*ct = DYNAMIC_TYPE;
|
*ct = DYNAMIC_TYPE;
|
||||||
|
|
||||||
env = get_config_path(getenv(PROXYCHAINS_CONF_FILE_ENV_VAR), buff, sizeof(buff));
|
env = get_config_path(getenv(PROXYCHAINS_CONF_FILE_ENV_VAR), buf, sizeof(buf));
|
||||||
if( ( file = fopen(env, "r") ) == NULL )
|
if( ( file = fopen(env, "r") ) == NULL )
|
||||||
{
|
{
|
||||||
perror("couldnt read configuration file");
|
perror("couldnt read configuration file");
|
||||||
@@ -184,8 +301,17 @@ static void get_chain_data(proxy_data * pd, unsigned int *proxy_count, chain_typ
|
|||||||
if(env && *env == '1')
|
if(env && *env == '1')
|
||||||
proxychains_quiet_mode = 1;
|
proxychains_quiet_mode = 1;
|
||||||
|
|
||||||
while(fgets(buff, sizeof(buff), file)) {
|
while(fgets(buf, sizeof(buf), file)) {
|
||||||
if(buff[0] != '\n' && buff[strspn(buff, " ")] != '#') {
|
buff = buf;
|
||||||
|
/* remove leading whitespace */
|
||||||
|
while(isspace(*buff)) buff++;
|
||||||
|
/* remove trailing '\n' */
|
||||||
|
if((p = strrchr(buff, '\n'))) *p = 0;
|
||||||
|
p = buff + strlen(buff)-1;
|
||||||
|
/* remove trailing whitespace */
|
||||||
|
while(p >= buff && isspace(*p)) *(p--) = 0;
|
||||||
|
if(!*buff || *buff == '#') continue; /* skip empty lines and comments */
|
||||||
|
if(1) {
|
||||||
/* proxylist has to come last */
|
/* proxylist has to come last */
|
||||||
if(list) {
|
if(list) {
|
||||||
if(count >= MAX_CHAIN)
|
if(count >= MAX_CHAIN)
|
||||||
@@ -198,21 +324,39 @@ static void get_chain_data(proxy_data * pd, unsigned int *proxy_count, chain_typ
|
|||||||
|
|
||||||
int ret = sscanf(buff, "%s %s %d %s %s", type, host, &port_n, pd[count].user, pd[count].pass);
|
int ret = sscanf(buff, "%s %s %d %s %s", type, host, &port_n, pd[count].user, pd[count].pass);
|
||||||
if(ret < 3 || ret == EOF) {
|
if(ret < 3 || ret == EOF) {
|
||||||
inv:
|
if(!proxy_from_string(buff, type, host, &port_n, pd[count].user, pd[count].pass)) {
|
||||||
fprintf(stderr, "error: invalid item in proxylist section: %s", buff);
|
inv:
|
||||||
exit(1);
|
fprintf(stderr, "error: invalid item in proxylist section: %s", buff);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
in_addr_t host_ip = inet_addr(host);
|
memset(&pd[count].ip, 0, sizeof(pd[count].ip));
|
||||||
if(host_ip == INADDR_NONE) {
|
pd[count].ip.is_v6 = !!strchr(host, ':');
|
||||||
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);
|
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)) {
|
||||||
|
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));
|
||||||
|
pd[count].ip.is_v6 = 0;
|
||||||
|
host_ip->addr.v4 = internal_ip;
|
||||||
|
if(internal_ip.as_int == IPT4_INVALID.as_int)
|
||||||
|
goto inv_host;
|
||||||
|
} else {
|
||||||
|
inv_host:
|
||||||
|
fprintf(stderr, "proxy %s has invalid value or is not numeric\n", host);
|
||||||
|
fprintf(stderr, "non-numeric ips are only allowed under the following circumstances:\n");
|
||||||
|
fprintf(stderr, "chaintype == strict (%s), proxy is not first in list (%s), proxy_dns active (%s)\n\n", bool_str(*ct == STRICT_TYPE), bool_str(count > 0), rdns_resolver_string(proxychains_resolver));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(!strcmp(type, "http")) {
|
if(!strcmp(type, "http")) {
|
||||||
pd[count].pt = HTTP_TYPE;
|
pd[count].pt = HTTP_TYPE;
|
||||||
|
} else if(!strcmp(type, "raw")) {
|
||||||
|
pd[count].pt = RAW_TYPE;
|
||||||
} else if(!strcmp(type, "socks4")) {
|
} else if(!strcmp(type, "socks4")) {
|
||||||
pd[count].pt = SOCKS4_TYPE;
|
pd[count].pt = SOCKS4_TYPE;
|
||||||
} else if(!strcmp(type, "socks5")) {
|
} else if(!strcmp(type, "socks5")) {
|
||||||
@@ -220,31 +364,31 @@ static void get_chain_data(proxy_data * pd, unsigned int *proxy_count, chain_typ
|
|||||||
} else
|
} else
|
||||||
goto inv;
|
goto inv;
|
||||||
|
|
||||||
if(pd[count].ip.as_int && port_n && pd[count].ip.as_int != (uint32_t) - 1)
|
if(port_n)
|
||||||
count++;
|
count++;
|
||||||
} else {
|
} else {
|
||||||
if(strstr(buff, "[ProxyList]")) {
|
if(!strcmp(buff, "[ProxyList]")) {
|
||||||
list = 1;
|
list = 1;
|
||||||
} else if(strstr(buff, "random_chain")) {
|
} else if(!strcmp(buff, "random_chain")) {
|
||||||
*ct = RANDOM_TYPE;
|
*ct = RANDOM_TYPE;
|
||||||
} else if(strstr(buff, "strict_chain")) {
|
} else if(!strcmp(buff, "strict_chain")) {
|
||||||
*ct = STRICT_TYPE;
|
*ct = STRICT_TYPE;
|
||||||
} else if(strstr(buff, "dynamic_chain")) {
|
} else if(!strcmp(buff, "dynamic_chain")) {
|
||||||
*ct = DYNAMIC_TYPE;
|
*ct = DYNAMIC_TYPE;
|
||||||
} else if(strstr(buff, "round_robin_chain")) {
|
} else if(!strcmp(buff, "round_robin_chain")) {
|
||||||
*ct = ROUND_ROBIN_TYPE;
|
*ct = ROUND_ROBIN_TYPE;
|
||||||
} else if(strstr(buff, "tcp_read_time_out")) {
|
} else if(STR_STARTSWITH(buff, "tcp_read_time_out")) {
|
||||||
sscanf(buff, "%s %d", user, &tcp_read_time_out);
|
sscanf(buff, "%s %d", user, &tcp_read_time_out);
|
||||||
} else if(strstr(buff, "tcp_connect_time_out")) {
|
} else if(STR_STARTSWITH(buff, "tcp_connect_time_out")) {
|
||||||
sscanf(buff, "%s %d", user, &tcp_connect_time_out);
|
sscanf(buff, "%s %d", user, &tcp_connect_time_out);
|
||||||
} else if(strstr(buff, "remote_dns_subnet")) {
|
} else if(STR_STARTSWITH(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) {
|
if(remote_dns_subnet >= 256) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"remote_dns_subnet: invalid value. requires a number between 0 and 255.\n");
|
"remote_dns_subnet: invalid value. requires a number between 0 and 255.\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
} else if(strstr(buff, "localnet")) {
|
} else if(STR_STARTSWITH(buff, "localnet")) {
|
||||||
if(sscanf(buff, "%s %21[^/]/%15s", user, local_in_addr_port, local_netmask) < 3) {
|
if(sscanf(buff, "%s %21[^/]/%15s", user, local_in_addr_port, local_netmask) < 3) {
|
||||||
fprintf(stderr, "localnet format error");
|
fprintf(stderr, "localnet format error");
|
||||||
exit(1);
|
exit(1);
|
||||||
@@ -285,74 +429,208 @@ static void get_chain_data(proxy_data * pd, unsigned int *proxy_count, chain_typ
|
|||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "# of localnet exceed %d.\n", MAX_LOCALNET);
|
fprintf(stderr, "# of localnet exceed %d.\n", MAX_LOCALNET);
|
||||||
}
|
}
|
||||||
} else if(strstr(buff, "chain_len")) {
|
} else if(STR_STARTSWITH(buff, "chain_len")) {
|
||||||
char *pc;
|
char *pc;
|
||||||
int len;
|
int len;
|
||||||
pc = strchr(buff, '=');
|
pc = strchr(buff, '=');
|
||||||
|
if(!pc) {
|
||||||
|
fprintf(stderr, "error: missing equals sign '=' in chain_len directive.\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
len = atoi(++pc);
|
len = atoi(++pc);
|
||||||
proxychains_max_chain = (len ? len : 1);
|
proxychains_max_chain = (len ? len : 1);
|
||||||
} else if(strstr(buff, "quiet_mode")) {
|
} else if(STR_STARTSWITH(buff, "fixed_len")) {
|
||||||
|
char *pc;
|
||||||
|
int len;
|
||||||
|
pc = strchr(buff, '=');
|
||||||
|
if(!pc) {
|
||||||
|
fprintf(stderr, "error: missing equals sign '=' in fixed_len directive.\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
len = atoi(++pc);
|
||||||
|
proxychains_fixed_chain = (len ? len : 1);
|
||||||
|
} else if(!strcmp(buff, "quiet_mode")) {
|
||||||
proxychains_quiet_mode = 1;
|
proxychains_quiet_mode = 1;
|
||||||
} else if(strstr(buff, "proxy_dns")) {
|
} else if(!strcmp(buff, "proxy_dns_old")) {
|
||||||
proxychains_resolver = 1;
|
proxychains_resolver = DNSLF_FORKEXEC;
|
||||||
|
} else if(!strcmp(buff, "proxy_dns")) {
|
||||||
|
proxychains_resolver = DNSLF_RDNS_THREAD;
|
||||||
|
} else if(STR_STARTSWITH(buff, "proxy_dns_daemon")) {
|
||||||
|
struct sockaddr_in rdns_server_buffer;
|
||||||
|
|
||||||
|
if(sscanf(buff, "%s %15[^:]:%5s", user, rdnsd_addr, rdnsd_port) < 3) {
|
||||||
|
fprintf(stderr, "proxy_dns_daemon format error\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
rdns_server_buffer.sin_family = AF_INET;
|
||||||
|
int error = inet_pton(AF_INET, rdnsd_addr, &rdns_server_buffer.sin_addr);
|
||||||
|
if(error <= 0) {
|
||||||
|
fprintf(stderr, "bogus proxy_dns_daemon address\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
rdns_server_buffer.sin_port = htons(atoi(rdnsd_port));
|
||||||
|
proxychains_resolver = DNSLF_RDNS_DAEMON;
|
||||||
|
rdns_set_daemon(&rdns_server_buffer);
|
||||||
|
} else if(STR_STARTSWITH(buff, "dnat")) {
|
||||||
|
if(sscanf(buff, "%s %21[^ ] %21s\n", user, dnat_orig_addr_port, dnat_new_addr_port) < 3) {
|
||||||
|
fprintf(stderr, "dnat format error");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
/* clean previously used buffer */
|
||||||
|
memset(dnat_orig_port, 0, sizeof(dnat_orig_port) / sizeof(dnat_orig_port[0]));
|
||||||
|
memset(dnat_new_port, 0, sizeof(dnat_new_port) / sizeof(dnat_new_port[0]));
|
||||||
|
|
||||||
|
(void)sscanf(dnat_orig_addr_port, "%15[^:]:%5s", dnat_orig_addr, dnat_orig_port);
|
||||||
|
(void)sscanf(dnat_new_addr_port, "%15[^:]:%5s", dnat_new_addr, dnat_new_port);
|
||||||
|
|
||||||
|
if(num_dnats < MAX_DNAT) {
|
||||||
|
int error;
|
||||||
|
error =
|
||||||
|
inet_pton(AF_INET, dnat_orig_addr,
|
||||||
|
&dnats[num_dnats].orig_dst);
|
||||||
|
if(error <= 0) {
|
||||||
|
fprintf(stderr, "dnat original destination address error\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
error =
|
||||||
|
inet_pton(AF_INET, dnat_new_addr,
|
||||||
|
&dnats[num_dnats].new_dst);
|
||||||
|
if(error <= 0) {
|
||||||
|
fprintf(stderr, "dnat effective destination address error\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(dnat_orig_port[0]) {
|
||||||
|
dnats[num_dnats].orig_port =
|
||||||
|
(short) atoi(dnat_orig_port);
|
||||||
|
} else {
|
||||||
|
dnats[num_dnats].orig_port = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(dnat_new_port[0]) {
|
||||||
|
dnats[num_dnats].new_port =
|
||||||
|
(short) atoi(dnat_new_port);
|
||||||
|
} else {
|
||||||
|
dnats[num_dnats].new_port = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
PDEBUG("added dnat: orig-dst=%s orig-port=%d new-dst=%s new-port=%d\n", dnat_orig_addr, dnats[num_dnats].orig_port, dnat_new_addr, dnats[num_dnats].new_port);
|
||||||
|
++num_dnats;
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "# of dnat exceed %d.\n", MAX_DNAT);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#ifndef BROKEN_FCLOSE
|
||||||
fclose(file);
|
fclose(file);
|
||||||
|
#endif
|
||||||
if(!count) {
|
if(!count) {
|
||||||
fprintf(stderr, "error: no valid proxy found in config\n");
|
fprintf(stderr, "error: no valid proxy found in config\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
if(proxychains_max_chain <= proxychains_fixed_chain) {
|
||||||
|
fprintf(stderr, "error: fixed_len needs to be smaller than chain_len\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if(proxychains_fixed_chain > count) {
|
||||||
|
fprintf(stderr, "error: fixed_len > proxycount\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
*proxy_count = count;
|
*proxy_count = count;
|
||||||
proxychains_got_chain_data = 1;
|
proxychains_got_chain_data = 1;
|
||||||
|
PDEBUG("proxy_dns: %s\n", rdns_resolver_string(proxychains_resolver));
|
||||||
}
|
}
|
||||||
|
|
||||||
/******* HOOK FUNCTIONS *******/
|
/******* HOOK FUNCTIONS *******/
|
||||||
|
|
||||||
int close(int fd) {
|
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;
|
||||||
|
}
|
||||||
|
if(proxychains_resolver != DNSLF_RDNS_THREAD) return true_close(fd);
|
||||||
|
|
||||||
/* prevent rude programs (like ssh) from closing our pipes */
|
/* prevent rude programs (like ssh) from closing our pipes */
|
||||||
if(fd != req_pipefd[0] && fd != req_pipefd[1] &&
|
if(fd != req_pipefd[0] && fd != req_pipefd[1] &&
|
||||||
fd != resp_pipefd[0] && fd != resp_pipefd[1]) {
|
fd != resp_pipefd[0] && fd != resp_pipefd[1]) {
|
||||||
return true_close(fd);
|
return true_close(fd);
|
||||||
}
|
}
|
||||||
|
err:
|
||||||
errno = EBADF;
|
errno = EBADF;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
int connect(int sock, const struct sockaddr *addr, unsigned int len) {
|
int connect(int sock, const struct sockaddr *addr, unsigned int len) {
|
||||||
|
INIT();
|
||||||
PFUNC();
|
PFUNC();
|
||||||
|
|
||||||
int socktype = 0, flags = 0, ret = 0;
|
int socktype = 0, flags = 0, ret = 0;
|
||||||
socklen_t optlen = 0;
|
socklen_t optlen = 0;
|
||||||
ip_type dest_ip;
|
ip_type dest_ip;
|
||||||
#ifdef DEBUG
|
DEBUGDECL(char str[256]);
|
||||||
char str[256];
|
|
||||||
#endif
|
|
||||||
struct in_addr *p_addr_in;
|
struct in_addr *p_addr_in;
|
||||||
|
struct in6_addr *p_addr_in6;
|
||||||
|
dnat_arg *dnat = NULL;
|
||||||
unsigned short port;
|
unsigned short port;
|
||||||
size_t i;
|
size_t i;
|
||||||
int remote_dns_connect = 0;
|
int remote_dns_connect = 0;
|
||||||
INIT();
|
|
||||||
optlen = sizeof(socktype);
|
optlen = sizeof(socktype);
|
||||||
|
sa_family_t fam = SOCKFAMILY(*addr);
|
||||||
getsockopt(sock, SOL_SOCKET, SO_TYPE, &socktype, &optlen);
|
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);
|
return true_connect(sock, addr, len);
|
||||||
|
|
||||||
|
int v6 = dest_ip.is_v6 = fam == AF_INET6;
|
||||||
|
|
||||||
p_addr_in = &((struct sockaddr_in *) addr)->sin_addr;
|
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_addr[12], 4);
|
||||||
|
v6 = dest_ip.is_v6 = 0;
|
||||||
|
p_addr_in = &v4inv6;
|
||||||
|
}
|
||||||
|
if(!v6 && !memcmp(p_addr_in, "\0\0\0\0", 4)) {
|
||||||
|
errno = ECONNREFUSED;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
// PDEBUG("localnet: %s; ", inet_ntop(AF_INET,&in_addr_localnet, str, sizeof(str)));
|
// 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("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);
|
PDEBUG("port: %d\n", port);
|
||||||
#endif
|
|
||||||
|
|
||||||
// check if connect called from proxydns
|
// 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++) {
|
// more specific first
|
||||||
|
if (!v6) for(i = 0; i < num_dnats && !remote_dns_connect && !dnat; i++)
|
||||||
|
if(dnats[i].orig_dst.s_addr == p_addr_in->s_addr)
|
||||||
|
if(dnats[i].orig_port && (dnats[i].orig_port == port))
|
||||||
|
dnat = &dnats[i];
|
||||||
|
|
||||||
|
if (!v6) for(i = 0; i < num_dnats && !remote_dns_connect && !dnat; i++)
|
||||||
|
if(dnats[i].orig_dst.s_addr == p_addr_in->s_addr)
|
||||||
|
if(!dnats[i].orig_port)
|
||||||
|
dnat = &dnats[i];
|
||||||
|
|
||||||
|
if (dnat) {
|
||||||
|
p_addr_in = &dnat->new_dst;
|
||||||
|
if (dnat->new_port)
|
||||||
|
port = dnat->new_port;
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
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)) {
|
== (p_addr_in->s_addr & localnet_addr[i].netmask.s_addr)) {
|
||||||
if(!localnet_addr[i].port || localnet_addr[i].port == port) {
|
if(!localnet_addr[i].port || localnet_addr[i].port == port) {
|
||||||
@@ -366,12 +644,12 @@ int connect(int sock, const struct sockaddr *addr, unsigned int len) {
|
|||||||
if(flags & O_NONBLOCK)
|
if(flags & O_NONBLOCK)
|
||||||
fcntl(sock, F_SETFL, !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,
|
ret = connect_proxy_chain(sock,
|
||||||
dest_ip,
|
dest_ip,
|
||||||
SOCKPORT(*addr),
|
htons(port),
|
||||||
proxychains_pd, proxychains_proxy_count, proxychains_ct, proxychains_max_chain);
|
proxychains_pd, proxychains_proxy_count, proxychains_ct);
|
||||||
|
|
||||||
fcntl(sock, F_SETFL, flags);
|
fcntl(sock, F_SETFL, flags);
|
||||||
if(ret != SUCCESS)
|
if(ret != SUCCESS)
|
||||||
@@ -379,88 +657,102 @@ int connect(int sock, const struct sockaddr *addr, unsigned int len) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef IS_SOLARIS
|
||||||
|
int __xnet_connect(int sock, const struct sockaddr *addr, unsigned int len) {
|
||||||
|
return connect(sock, addr, len);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static struct gethostbyname_data ghbndata;
|
static struct gethostbyname_data ghbndata;
|
||||||
struct hostent *gethostbyname(const char *name) {
|
struct hostent *gethostbyname(const char *name) {
|
||||||
INIT();
|
INIT();
|
||||||
|
|
||||||
PDEBUG("gethostbyname: %s\n", name);
|
PDEBUG("gethostbyname: %s\n", name);
|
||||||
|
|
||||||
if(proxychains_resolver)
|
if(proxychains_resolver == DNSLF_FORKEXEC)
|
||||||
return proxy_gethostbyname(name, &ghbndata);
|
return proxy_gethostbyname_old(name);
|
||||||
else
|
else if(proxychains_resolver == DNSLF_LIBC)
|
||||||
return true_gethostbyname(name);
|
return true_gethostbyname(name);
|
||||||
|
else
|
||||||
|
return proxy_gethostbyname(name, &ghbndata);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res) {
|
int getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res) {
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
INIT();
|
INIT();
|
||||||
|
|
||||||
PDEBUG("getaddrinfo: %s %s\n", node ? node : "null", service ? service : "null");
|
PDEBUG("getaddrinfo: %s %s\n", node ? node : "null", service ? service : "null");
|
||||||
|
|
||||||
if(proxychains_resolver)
|
if(proxychains_resolver != DNSLF_LIBC)
|
||||||
ret = proxy_getaddrinfo(node, service, hints, res);
|
return proxy_getaddrinfo(node, service, hints, res);
|
||||||
else
|
else
|
||||||
ret = true_getaddrinfo(node, service, hints, res);
|
return true_getaddrinfo(node, service, hints, res);
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void freeaddrinfo(struct addrinfo *res) {
|
void freeaddrinfo(struct addrinfo *res) {
|
||||||
INIT();
|
INIT();
|
||||||
|
PDEBUG("freeaddrinfo %p \n", (void *) res);
|
||||||
|
|
||||||
PDEBUG("freeaddrinfo %p \n", res);
|
if(proxychains_resolver == DNSLF_LIBC)
|
||||||
|
|
||||||
if(!proxychains_resolver)
|
|
||||||
true_freeaddrinfo(res);
|
true_freeaddrinfo(res);
|
||||||
else
|
else
|
||||||
proxy_freeaddrinfo(res);
|
proxy_freeaddrinfo(res);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int pc_getnameinfo(const struct sockaddr *sa, socklen_t salen,
|
int pc_getnameinfo(const struct sockaddr *sa, socklen_t salen,
|
||||||
char *host, socklen_t hostlen, char *serv,
|
char *host, socklen_t hostlen, char *serv,
|
||||||
socklen_t servlen, int flags)
|
socklen_t servlen, int flags)
|
||||||
{
|
{
|
||||||
char ip_buf[16];
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
INIT();
|
INIT();
|
||||||
|
|
||||||
PFUNC();
|
PFUNC();
|
||||||
|
|
||||||
if(!proxychains_resolver) {
|
if(proxychains_resolver == DNSLF_LIBC) {
|
||||||
ret = true_getnameinfo(sa, salen, host, hostlen, serv, servlen, flags);
|
return true_getnameinfo(sa, salen, host, hostlen, serv, servlen, flags);
|
||||||
} else {
|
} 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;
|
return EAI_FAMILY;
|
||||||
if(hostlen) {
|
if(hostlen) {
|
||||||
pc_stringfromipv4((unsigned char*) &(SOCKADDR_2(*sa)), ip_buf);
|
unsigned char v4inv6buf[4];
|
||||||
if(snprintf(host, hostlen, "%s", ip_buf) >= hostlen)
|
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_addr[12], 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;
|
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(servlen) {
|
||||||
if(snprintf(serv, servlen, "%d", ntohs(SOCKPORT(*sa))) >= servlen)
|
if(snprintf(serv, servlen, "%d", ntohs(SOCKPORT(*sa))) >= servlen)
|
||||||
return EAI_OVERFLOW;
|
return EAI_OVERFLOW;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ret;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct hostent *gethostbyaddr(const void *addr, socklen_t len, int type) {
|
struct hostent *gethostbyaddr(const void *addr, socklen_t len, int type) {
|
||||||
|
INIT();
|
||||||
|
PDEBUG("TODO: proper gethostbyaddr hook\n");
|
||||||
|
|
||||||
static char buf[16];
|
static char buf[16];
|
||||||
static char ipv4[4];
|
static char ipv4[4];
|
||||||
static char *list[2];
|
static char *list[2];
|
||||||
static char *aliases[1];
|
static char *aliases[1];
|
||||||
static struct hostent he;
|
static struct hostent he;
|
||||||
|
|
||||||
INIT();
|
if(proxychains_resolver == DNSLF_LIBC)
|
||||||
|
|
||||||
PDEBUG("TODO: proper gethostbyaddr hook\n");
|
|
||||||
|
|
||||||
if(!proxychains_resolver)
|
|
||||||
return true_gethostbyaddr(addr, len, type);
|
return true_gethostbyaddr(addr, len, type);
|
||||||
else {
|
else {
|
||||||
|
|
||||||
@@ -488,6 +780,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,
|
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();
|
||||||
|
PFUNC();
|
||||||
if (flags & MSG_FASTOPEN) {
|
if (flags & MSG_FASTOPEN) {
|
||||||
if (!connect(sockfd, dest_addr, addrlen) && errno != EINPROGRESS) {
|
if (!connect(sockfd, dest_addr, addrlen) && errno != EINPROGRESS) {
|
||||||
return -1;
|
return -1;
|
||||||
|
|||||||
+20
-7
@@ -7,10 +7,7 @@
|
|||||||
* *
|
* *
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
#undef _POSIX_C_SOURCE
|
#define _DEFAULT_SOURCE
|
||||||
#define _POSIX_C_SOURCE 200809L
|
|
||||||
#undef _XOPEN_SOURCE
|
|
||||||
#define _XOPEN_SOURCE 700
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@@ -19,12 +16,17 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
|
|
||||||
|
#ifdef IS_MAC
|
||||||
|
#define _DARWIN_C_SOURCE
|
||||||
|
#endif
|
||||||
|
#include <dlfcn.h>
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
static int usage(char **argv) {
|
static int usage(char **argv) {
|
||||||
printf("\nUsage:\t%s -q -f config_file program_name [arguments]\n"
|
printf("\nUsage:\t%s -q -f config_file program_name [arguments]\n"
|
||||||
"\t-q makes proxychains quiet - this overrides the config setting\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]);
|
"\tfor example : proxychains telnet somehost.com\n" "More help in README file\n\n", argv[0]);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
@@ -33,7 +35,9 @@ static const char *dll_name = DLL_NAME;
|
|||||||
|
|
||||||
static char own_dir[256];
|
static char own_dir[256];
|
||||||
static const char *dll_dirs[] = {
|
static const char *dll_dirs[] = {
|
||||||
|
#ifndef SUPER_SECURE /* CVE-2015-3887 */
|
||||||
".",
|
".",
|
||||||
|
#endif
|
||||||
own_dir,
|
own_dir,
|
||||||
LIB_DIR,
|
LIB_DIR,
|
||||||
"/lib",
|
"/lib",
|
||||||
@@ -47,8 +51,12 @@ static void set_own_dir(const char *argv0) {
|
|||||||
size_t l = strlen(argv0);
|
size_t l = strlen(argv0);
|
||||||
while(l && argv0[l - 1] != '/')
|
while(l && argv0[l - 1] != '/')
|
||||||
l--;
|
l--;
|
||||||
if(l == 0)
|
if(l == 0 || l >= sizeof(own_dir))
|
||||||
|
#ifdef SUPER_SECURE
|
||||||
|
memcpy(own_dir, "/dev/null/", 11);
|
||||||
|
#else
|
||||||
memcpy(own_dir, ".", 2);
|
memcpy(own_dir, ".", 2);
|
||||||
|
#endif
|
||||||
else {
|
else {
|
||||||
memcpy(own_dir, argv0, l - 1);
|
memcpy(own_dir, argv0, l - 1);
|
||||||
own_dir[l] = 0;
|
own_dir[l] = 0;
|
||||||
@@ -66,6 +74,9 @@ int main(int argc, char *argv[]) {
|
|||||||
size_t i;
|
size_t i;
|
||||||
const char *prefix = NULL;
|
const char *prefix = NULL;
|
||||||
|
|
||||||
|
if(argc == 2 && !strcmp(argv[1], "--help"))
|
||||||
|
return usage(argv);
|
||||||
|
|
||||||
for(i = 0; i < MAX_COMMANDLINE_FLAGS; i++) {
|
for(i = 0; i < MAX_COMMANDLINE_FLAGS; i++) {
|
||||||
if(start_argv < argc && argv[start_argv][0] == '-') {
|
if(start_argv < argc && argv[start_argv][0] == '-') {
|
||||||
if(argv[start_argv][1] == 'q') {
|
if(argv[start_argv][1] == 'q') {
|
||||||
@@ -102,7 +113,9 @@ int main(int argc, char *argv[]) {
|
|||||||
|
|
||||||
// search DLL
|
// search DLL
|
||||||
|
|
||||||
set_own_dir(argv[0]);
|
Dl_info dli;
|
||||||
|
dladdr(own_dir, &dli);
|
||||||
|
set_own_dir(dli.dli_fname);
|
||||||
|
|
||||||
i = 0;
|
i = 0;
|
||||||
|
|
||||||
|
|||||||
+53
-3
@@ -45,11 +45,41 @@ strict_chain
|
|||||||
# Make sense only if random_chain or round_robin_chain
|
# Make sense only if random_chain or round_robin_chain
|
||||||
#chain_len = 2
|
#chain_len = 2
|
||||||
|
|
||||||
|
# use this if you want to use e.g. random_chain but always have
|
||||||
|
# e.g. tor as first proxy. in that case only chain_len - fixed_len proxies
|
||||||
|
# will be used for random chain.
|
||||||
|
# currently only implemented for dynamic_chain and random_chain.
|
||||||
|
#fixed_len = 1
|
||||||
|
|
||||||
# Quiet mode (no output from library)
|
# Quiet mode (no output from library)
|
||||||
#quiet_mode
|
#quiet_mode
|
||||||
|
|
||||||
# Proxy DNS requests - no leak for DNS data
|
## Proxy DNS requests - no leak for DNS data
|
||||||
proxy_dns
|
# (disable all of the 3 items below to not proxy your DNS requests)
|
||||||
|
|
||||||
|
# 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
|
||||||
|
# assigned from an internal list (via remote_dns_subset).
|
||||||
|
# this is the easiest (setup-wise) and fastest method, however on
|
||||||
|
# systems with buggy libcs and very complex software like webbrosers
|
||||||
|
# this might not work and/or cause crashes.
|
||||||
|
proxy_dns
|
||||||
|
|
||||||
|
# method 2. use the old proxyresolv script to proxy DNS requests
|
||||||
|
# in proxychains 3.1 style. requires `proxyresolv` in $PATH
|
||||||
|
# plus a dynamically linked `dig` binary.
|
||||||
|
# this is a lot slower than `proxy_dns`, doesn't support .onion URLs,
|
||||||
|
# but might be more compatible with complex software like webbrowsers.
|
||||||
|
#proxy_dns_old
|
||||||
|
|
||||||
|
# method 3. use proxychains4-daemon process to serve remote DNS requests.
|
||||||
|
# this is similar to the threaded `proxy_dns` method, however it requires
|
||||||
|
# that proxychains4-daemon is already running on the specified address.
|
||||||
|
# on the plus side it doesn't do malloc/threads so it should be quite
|
||||||
|
# compatible with complex, async-unsafe software.
|
||||||
|
# note that if you don't start proxychains4-daemon before using this,
|
||||||
|
# the process will simply hang.
|
||||||
|
#proxy_dns_daemon 127.0.0.1:1053
|
||||||
|
|
||||||
# set the class A subnet number to use for the internal remote DNS mapping
|
# set the class A subnet number to use for the internal remote DNS mapping
|
||||||
# we use the reserved 224.x.x.x range by default,
|
# we use the reserved 224.x.x.x range by default,
|
||||||
@@ -70,6 +100,9 @@ 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,
|
||||||
|
## 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
|
||||||
# localnet 192.168.1.0:80/255.255.255.0
|
# localnet 192.168.1.0:80/255.255.255.0
|
||||||
|
|
||||||
@@ -90,6 +123,22 @@ tcp_connect_time_out 8000
|
|||||||
# localnet 172.16.0.0/255.240.0.0
|
# localnet 172.16.0.0/255.240.0.0
|
||||||
# localnet 192.168.0.0/255.255.0.0
|
# localnet 192.168.0.0/255.255.0.0
|
||||||
|
|
||||||
|
### Examples for dnat
|
||||||
|
## Trying to proxy connections to destinations which are dnatted,
|
||||||
|
## will result in proxying connections to the new given destinations.
|
||||||
|
## Whenever I connect to 1.1.1.1 on port 1234 actually connect to 1.1.1.2 on port 443
|
||||||
|
# dnat 1.1.1.1:1234 1.1.1.2:443
|
||||||
|
|
||||||
|
## Whenever I connect to 1.1.1.1 on port 443 actually connect to 1.1.1.2 on port 443
|
||||||
|
## (no need to write :443 again)
|
||||||
|
# dnat 1.1.1.2:443 1.1.1.2
|
||||||
|
|
||||||
|
## No matter what port I connect to on 1.1.1.1 port actually connect to 1.1.1.2 on port 443
|
||||||
|
# dnat 1.1.1.1 1.1.1.2:443
|
||||||
|
|
||||||
|
## Always, instead of connecting to 1.1.1.1, connect to 1.1.1.2
|
||||||
|
# dnat 1.1.1.1 1.1.1.2
|
||||||
|
|
||||||
# ProxyList format
|
# ProxyList format
|
||||||
# type ip port [user pass]
|
# type ip port [user pass]
|
||||||
# (values separated by 'tab' or 'blank')
|
# (values separated by 'tab' or 'blank')
|
||||||
@@ -105,7 +154,8 @@ tcp_connect_time_out 8000
|
|||||||
# http 192.168.39.93 8080
|
# http 192.168.39.93 8080
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# proxy types: http, socks4, socks5
|
# proxy types: http, socks4, socks5, raw
|
||||||
|
# * raw: The traffic is simply forwarded to the proxy without modification.
|
||||||
# ( auth types supported: "basic"-http "user/pass"-socks )
|
# ( auth types supported: "basic"-http "user/pass"-socks )
|
||||||
#
|
#
|
||||||
[ProxyList]
|
[ProxyList]
|
||||||
|
|||||||
+11
-6
@@ -1,10 +1,8 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
# This is a legacy script that uses "dig" to do DNS lookups via TCP.
|
# This is a legacy script that uses "dig" or "drill" to do DNS lookups via TCP.
|
||||||
# it is not actively maintained since proxychains no longer depends
|
|
||||||
# on it. i leave it here as a bonus.
|
|
||||||
|
|
||||||
# DNS server used to resolve names
|
# DNS server used to resolve names
|
||||||
DNS_SERVER=8.8.8.8
|
test -z "$DNS_SERVER" && DNS_SERVER=8.8.8.8
|
||||||
|
|
||||||
|
|
||||||
if [ $# = 0 ] ; then
|
if [ $# = 0 ] ; then
|
||||||
@@ -14,5 +12,12 @@ if [ $# = 0 ] ; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
export LD_PRELOAD=libproxychains4.so
|
test -z $LD_PRELOAD && export LD_PRELOAD=libproxychains4.so
|
||||||
dig $1 @$DNS_SERVER +tcp | awk '/A.?[0-9]+\.[0-9]+\.[0-9]/{print $5;}'
|
|
||||||
|
if type dig 1>/dev/null 2>&1 ; then
|
||||||
|
dig $1 @$DNS_SERVER +tcp | awk '/A.?[0-9]+\.[0-9]+\.[0-9]/{print $5;}'
|
||||||
|
elif type drill 1>/dev/null 2>&1 ; then
|
||||||
|
drill -t4 $1 @$DNS_SERVER | awk '/A.+[0-9]+\.[0-9]+\.[0-9]/{print $5;}'
|
||||||
|
else
|
||||||
|
echo "error: neither dig nor drill found" >&2
|
||||||
|
fi
|
||||||
|
|||||||
+99
@@ -0,0 +1,99 @@
|
|||||||
|
#include <sys/socket.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "rdns.h"
|
||||||
|
#include "allocator_thread.h"
|
||||||
|
#include "remotedns.h"
|
||||||
|
|
||||||
|
#ifndef HAVE_SOCK_CLOEXEC
|
||||||
|
#define SOCK_CLOEXEC 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//static enum dns_lookup_flavor dns_flavor;
|
||||||
|
#define dns_flavor rdns_get_flavor()
|
||||||
|
|
||||||
|
static struct sockaddr_in rdns_server;
|
||||||
|
|
||||||
|
size_t rdns_daemon_get_host_for_ip(ip_type4 ip, char* readbuf) {
|
||||||
|
struct at_msg msg = {
|
||||||
|
.h.msgtype = ATM_GETNAME,
|
||||||
|
.h.datalen = htons(4),
|
||||||
|
.m.ip = ip,
|
||||||
|
};
|
||||||
|
int fd = socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC, 0);
|
||||||
|
sendto(fd, &msg, sizeof(msg.h)+4, 0, (void*)&rdns_server, sizeof(rdns_server));
|
||||||
|
recvfrom(fd, &msg, sizeof msg, 0, (void*)0, (void*)0);
|
||||||
|
close(fd);
|
||||||
|
msg.h.datalen = ntohs(msg.h.datalen);
|
||||||
|
if(!msg.h.datalen || msg.h.datalen > 256) return 0;
|
||||||
|
memcpy(readbuf, msg.m.host, msg.h.datalen);
|
||||||
|
return msg.h.datalen - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ip_type4 rdns_daemon_get_ip_for_host(char* host, size_t len) {
|
||||||
|
struct at_msg msg = {
|
||||||
|
.h.msgtype = ATM_GETIP,
|
||||||
|
};
|
||||||
|
if(len >= 256) return IPT4_INT(-1);
|
||||||
|
memcpy(msg.m.host, host, len+1);
|
||||||
|
msg.h.datalen = htons(len+1);
|
||||||
|
int fd = socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC, 0);
|
||||||
|
sendto(fd, &msg, sizeof(msg.h)+len+1, 0, (void*)&rdns_server, sizeof(rdns_server));
|
||||||
|
recvfrom(fd, &msg, sizeof msg, 0, (void*)0, (void*)0);
|
||||||
|
close(fd);
|
||||||
|
if(ntohs(msg.h.datalen) != 4) return IPT4_INT(-1);
|
||||||
|
return msg.m.ip;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *rdns_resolver_string(enum dns_lookup_flavor flavor) {
|
||||||
|
static const char tab[][7] = {
|
||||||
|
[DNSLF_LIBC] = "off",
|
||||||
|
[DNSLF_FORKEXEC] = "old",
|
||||||
|
[DNSLF_RDNS_THREAD] = "thread",
|
||||||
|
[DNSLF_RDNS_DAEMON] = "daemon",
|
||||||
|
};
|
||||||
|
return tab[flavor];
|
||||||
|
}
|
||||||
|
|
||||||
|
void rdns_init(enum dns_lookup_flavor flavor) {
|
||||||
|
static int init_done = 0;
|
||||||
|
if(!init_done) switch(flavor) {
|
||||||
|
case DNSLF_RDNS_THREAD:
|
||||||
|
at_init();
|
||||||
|
break;
|
||||||
|
case DNSLF_RDNS_DAEMON:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
init_done = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rdns_set_daemon(struct sockaddr_in* addr) {
|
||||||
|
rdns_server = *addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
enum dns_lookup_flavor rdns_get_flavor(void) {
|
||||||
|
return dns_flavor;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
size_t rdns_get_host_for_ip(ip_type4 ip, char* readbuf) {
|
||||||
|
switch(dns_flavor) {
|
||||||
|
case DNSLF_RDNS_THREAD: return at_get_host_for_ip(ip, readbuf);
|
||||||
|
case DNSLF_RDNS_DAEMON: return rdns_daemon_get_host_for_ip(ip, readbuf);
|
||||||
|
default:
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ip_type4 rdns_get_ip_for_host(char* host, size_t len) {
|
||||||
|
switch(dns_flavor) {
|
||||||
|
case DNSLF_RDNS_THREAD: return at_get_ip_for_host(host, len);
|
||||||
|
case DNSLF_RDNS_DAEMON: return rdns_daemon_get_ip_for_host(host, len);
|
||||||
|
default:
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
+28
@@ -0,0 +1,28 @@
|
|||||||
|
#ifndef RDNS_H
|
||||||
|
#define RDNS_H
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include "ip_type.h"
|
||||||
|
#include "remotedns.h"
|
||||||
|
|
||||||
|
enum dns_lookup_flavor {
|
||||||
|
DNSLF_LIBC = 0,
|
||||||
|
DNSLF_FORKEXEC,
|
||||||
|
|
||||||
|
DNSLF_RDNS_START,
|
||||||
|
DNSLF_RDNS_THREAD = DNSLF_RDNS_START,
|
||||||
|
DNSLF_RDNS_DAEMON,
|
||||||
|
};
|
||||||
|
|
||||||
|
void rdns_init(enum dns_lookup_flavor flavor);
|
||||||
|
void rdns_set_daemon(struct sockaddr_in* addr);
|
||||||
|
const char *rdns_resolver_string(enum dns_lookup_flavor flavor);
|
||||||
|
size_t rdns_get_host_for_ip(ip_type4 ip, char* readbuf);
|
||||||
|
ip_type4 rdns_get_ip_for_host(char* host, size_t len);
|
||||||
|
|
||||||
|
//enum dns_lookup_flavor rdns_get_flavor(void);
|
||||||
|
#define rdns_get_flavor() proxychains_resolver
|
||||||
|
extern enum dns_lookup_flavor proxychains_resolver;
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
#ifndef REMOTEDNS_H
|
||||||
|
#define REMOTEDNS_H
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include "ip_type.h"
|
||||||
|
|
||||||
|
#define MSG_LEN_MAX 256
|
||||||
|
|
||||||
|
enum at_msgtype {
|
||||||
|
ATM_GETIP = 0,
|
||||||
|
ATM_GETNAME,
|
||||||
|
ATM_FAIL,
|
||||||
|
ATM_EXIT,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct at_msghdr {
|
||||||
|
unsigned char msgtype; /* at_msgtype */
|
||||||
|
char reserved;
|
||||||
|
unsigned short datalen;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct at_msg {
|
||||||
|
struct at_msghdr h;
|
||||||
|
union {
|
||||||
|
char host[260];
|
||||||
|
ip_type4 ip;
|
||||||
|
} m;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
#include <assert.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <limits.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#ifndef PAGE_SIZE
|
|
||||||
#define PAGE_SIZE 4096
|
|
||||||
#endif
|
|
||||||
#include "shm.h"
|
|
||||||
#include "debug.h"
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
#include <sys/mman.h>
|
|
||||||
#include <sys/ipc.h>
|
|
||||||
#include <sys/shm.h>
|
|
||||||
|
|
||||||
/* allocates shared memory which can be accessed from the parent and its childs */
|
|
||||||
void *shm_realloc(void* old, size_t old_size, size_t new_size) {
|
|
||||||
//PFUNC();
|
|
||||||
void *nu = mmap(NULL, new_size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
|
|
||||||
if(old) {
|
|
||||||
if(!nu) return NULL;
|
|
||||||
assert(new_size >= old_size);
|
|
||||||
memcpy(nu, old, old_size);
|
|
||||||
munmap(old, old_size);
|
|
||||||
}
|
|
||||||
return nu;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void stringpool_init(struct stringpool* sp) {
|
|
||||||
PFUNC();
|
|
||||||
memset(sp, 0, sizeof *sp);
|
|
||||||
}
|
|
||||||
|
|
||||||
char* stringpool_add(struct stringpool *sp, char* s, size_t len) {
|
|
||||||
//PFUNC();
|
|
||||||
if(len > sp->alloced - sp->used) {
|
|
||||||
size_t newsz = sp->used + len;
|
|
||||||
size_t inc = PAGE_SIZE - (newsz % PAGE_SIZE);
|
|
||||||
newsz += (inc == PAGE_SIZE) ? 0 : inc;
|
|
||||||
void* p = realloc(sp->start, newsz);
|
|
||||||
if(p) {
|
|
||||||
sp->start = p;
|
|
||||||
sp->alloced = newsz;
|
|
||||||
} else
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
char* ret = sp->start + sp->used;
|
|
||||||
memcpy(ret, s, len);
|
|
||||||
sp->used += len;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
#ifndef SHM_H
|
|
||||||
#define SHM_H
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
struct stringpool {
|
|
||||||
size_t alloced;
|
|
||||||
size_t used;
|
|
||||||
char* start;
|
|
||||||
};
|
|
||||||
|
|
||||||
void stringpool_init(struct stringpool* sp);
|
|
||||||
char* stringpool_add(struct stringpool *sp, char* s, size_t len);
|
|
||||||
#if 0
|
|
||||||
void *shm_realloc(void* old, size_t old_size, size_t new_size);
|
|
||||||
#endif
|
|
||||||
//RcB: DEP "shm.c"
|
|
||||||
#endif
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
#include "stringdump.h"
|
|
||||||
#include "debug.h"
|
|
||||||
|
|
||||||
struct stringpool mem;
|
|
||||||
|
|
||||||
char *dumpstring(char* s, size_t len) {
|
|
||||||
PFUNC();
|
|
||||||
return stringpool_add(&mem, s, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
void dumpstring_init(void) {
|
|
||||||
stringpool_init(&mem);
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
#ifndef STRINGDUMP_H
|
|
||||||
#define STRINGDUMP_H
|
|
||||||
|
|
||||||
#include "shm.h"
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
char *dumpstring(char* s, size_t len);
|
|
||||||
void dumpstring_init(void);
|
|
||||||
|
|
||||||
//RcB: DEP "stringdump.h"
|
|
||||||
|
|
||||||
#endif
|
|
||||||
+25
-15
@@ -3,39 +3,49 @@
|
|||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
|
||||||
#ifndef NI_MAXHOST
|
#ifndef NI_MAXHOST
|
||||||
#define NI_MAXHOST 1025
|
#define NI_MAXHOST 1025
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int main(void) {
|
static int doit(const char* host, const char* service) {
|
||||||
struct addrinfo *result;
|
struct addrinfo *result;
|
||||||
struct addrinfo *res;
|
struct addrinfo *res;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
/* resolve the domain name into a list of addresses */
|
/* resolve the domain name into a list of addresses */
|
||||||
error = getaddrinfo("www.example.com", NULL, NULL, &result);
|
error = getaddrinfo(host, service, NULL, &result);
|
||||||
if (error != 0)
|
if (error != 0)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "error in getaddrinfo: %s\n", gai_strerror(error));
|
fprintf(stderr, "error in getaddrinfo: %s\n", gai_strerror(error));
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* loop over all returned results and do inverse lookup */
|
/* loop over all returned results and do inverse lookup */
|
||||||
for (res = result; res != NULL; res = res->ai_next)
|
for (res = result; res != NULL; res = res->ai_next)
|
||||||
{
|
{
|
||||||
char hostname[NI_MAXHOST] = "";
|
char hostname[NI_MAXHOST] = "";
|
||||||
|
|
||||||
error = getnameinfo(res->ai_addr, res->ai_addrlen, hostname, NI_MAXHOST, NULL, 0, 0);
|
error = getnameinfo(res->ai_addr, res->ai_addrlen, hostname, NI_MAXHOST, NULL, 0, 0);
|
||||||
if (error != 0)
|
if (error != 0)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "error in getnameinfo: %s\n", gai_strerror(error));
|
fprintf(stderr, "error in getnameinfo: %s\n", gai_strerror(error));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (*hostname != '\0')
|
int port = 0;
|
||||||
printf("hostname: %s\n", hostname);
|
if(res->ai_family == AF_INET) port = ((struct sockaddr_in*)res->ai_addr)->sin_port;
|
||||||
}
|
else if(res->ai_family == AF_INET6) port = ((struct sockaddr_in6*)res->ai_addr)->sin6_port;
|
||||||
|
port = ntohs(port);
|
||||||
|
printf("hostname: %s, port: %d\n", hostname, port);
|
||||||
|
}
|
||||||
|
|
||||||
freeaddrinfo(result);
|
freeaddrinfo(result);
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
int ret;
|
||||||
|
ret = doit("www.example.com", NULL);
|
||||||
|
ret = doit("www.example.com", "80");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include "../src/common.c"
|
||||||
|
|
||||||
|
void printhostent(struct hostent *hp) {
|
||||||
|
char ipbuf[16];
|
||||||
|
pc_stringfromipv4(hp->h_addr_list[0], ipbuf);
|
||||||
|
printf("alias: %p, len: %d, name: %s, addrlist: %p, addrtype: %d, ip: %s\n",
|
||||||
|
hp->h_aliases,
|
||||||
|
hp->h_length,
|
||||||
|
hp->h_name,
|
||||||
|
hp->h_addr_list,
|
||||||
|
hp->h_addrtype,
|
||||||
|
ipbuf
|
||||||
|
);
|
||||||
|
}
|
||||||
|
int main(int argc, char**argv) {
|
||||||
|
struct hostent* ret;
|
||||||
|
if(argc == 1) return 1;
|
||||||
|
ret = gethostbyname(argv[1]);
|
||||||
|
if(ret) printhostent(ret);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "../src/common.h"
|
#include "../src/common.c"
|
||||||
|
|
||||||
void printhostent(struct hostent *hp) {
|
void printhostent(struct hostent *hp) {
|
||||||
char ipbuf[16];
|
char ipbuf[16];
|
||||||
|
|||||||
+62
-18
@@ -11,73 +11,117 @@
|
|||||||
#define SOCKPORT(x) (satosin(x)->sin_port)
|
#define SOCKPORT(x) (satosin(x)->sin_port)
|
||||||
#define SOCKFAMILY(x) (satosin(x)->sin_family)
|
#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() {
|
int main() {
|
||||||
struct sockaddr a = {0}, *sa = &a;
|
struct sockaddr_in a = {0}, *sa = &a;
|
||||||
char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
|
char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
|
||||||
SOCKPORT(a) = htons(80);
|
a.sin_port = htons(80);
|
||||||
memcpy( &( (struct sockaddr_in*) sa ) ->sin_addr , (char[]) {127,0,0,1}, 4);
|
memcpy( &a.sin_addr , (char[]) {127,0,0,1}, 4);
|
||||||
|
|
||||||
int ret;
|
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)
|
sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV)) == 0)
|
||||||
printf("host=%s, serv=%s\n", hbuf, sbuf);
|
printf("host=%s, serv=%s\n", hbuf, sbuf);
|
||||||
else
|
else
|
||||||
printf("%s\n", gai_strerror(ret));
|
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)
|
sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV)) == 0)
|
||||||
printf("host=%s, serv=%s\n", hbuf, sbuf);
|
printf("host=%s, serv=%s\n", hbuf, sbuf);
|
||||||
else
|
else
|
||||||
printf("%s\n", gai_strerror(ret));
|
printf("%s\n", gai_strerror(ret));
|
||||||
|
|
||||||
assert(ret == EAI_FAMILY);
|
ASSERT(ret == EAI_FAMILY);
|
||||||
|
CLR();
|
||||||
|
|
||||||
SOCKFAMILY(a) = AF_INET;
|
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)
|
sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV)) == 0)
|
||||||
printf("host=%s, serv=%s\n", hbuf, sbuf);
|
printf("host=%s, serv=%s\n", hbuf, sbuf);
|
||||||
else
|
else
|
||||||
printf("%s\n", gai_strerror(ret));
|
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)
|
1, NI_NUMERICHOST | NI_NUMERICSERV)) == 0)
|
||||||
printf("host=%s, serv=%s\n", hbuf, sbuf);
|
printf("host=%s, serv=%s\n", hbuf, sbuf);
|
||||||
else
|
else
|
||||||
printf("%s\n", gai_strerror(ret));
|
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)
|
sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV)) == 0)
|
||||||
printf("host=%s, serv=%s\n", hbuf, sbuf);
|
printf("host=%s, serv=%s\n", hbuf, sbuf);
|
||||||
else
|
else
|
||||||
printf("%s\n", gai_strerror(ret));
|
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)
|
0, NI_NUMERICHOST | NI_NUMERICSERV)) == 0)
|
||||||
printf("host=%s, serv=%s\n", hbuf, sbuf);
|
printf("host=%s, serv=%s\n", hbuf, sbuf);
|
||||||
else
|
else
|
||||||
printf("%s\n", gai_strerror(ret));
|
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)
|
sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV)) == 0)
|
||||||
printf("host=%s, serv=%s\n", hbuf, sbuf);
|
printf("host=%s, serv=%s\n", hbuf, sbuf);
|
||||||
else
|
else
|
||||||
printf("%s\n", gai_strerror(ret));
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user