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

Compare commits

...

64 Commits

32 changed files with 963 additions and 582 deletions
+4
View File
@@ -1,3 +1,6 @@
proxychains4
*.bz2
*.xz
*.o
*.so
*.la
@@ -8,6 +11,7 @@
*.out
*~
*.patch
version.h
# Autoconf stuff
libtool
+5 -1
View File
@@ -6,13 +6,17 @@ netcreature@users.sourceforge.net
main.c, remote-dns, thread safety, bugfixes, build system,
cleanups, mac support
rofl0r.
https://github.com/rofl0r/proxychains
https://github.com/rofl0r/proxychains-ng
localnet, bugfixes
jianing yang.
https://github.com/jianingy/proxychains
https://sourceforge.net/projects/proxychains/forums/forum/644747/topic/3498696
round-robin
crass.
https://github.com/crass/proxychains-ng
poll_retry (fixes for signal handling)
colin cross.
https://sourceforge.net/projects/proxychains/forums/forum/644747/topic/2367923
+2 -2
View File
@@ -1,8 +1,8 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
675 Mass Ave, Cambridge, MA 02139, USA
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
+32 -16
View File
@@ -15,10 +15,12 @@ sysconfdir=$(prefix)/etc
SRCS = $(sort $(wildcard src/*.c))
OBJS = $(SRCS:.c=.o)
LOBJS = src/nameinfo.o \
src/core.o src/common.o src/libproxychains.o src/shm.o \
src/allocator_thread.o src/ip_type.o src/stringdump.o \
src/hostentdb.o src/hash.o src/debug.o
LOBJS = src/nameinfo.o src/version.o \
src/core.o src/common.o src/libproxychains.o \
src/allocator_thread.o src/ip_type.o \
src/hostsreader.o src/hash.o src/debug.o
GENH = src/version.h
CFLAGS += -Wall -O0 -g -std=c99 -D_GNU_SOURCE -pipe
NO_AS_NEEDED = -Wl,--no-as-needed
@@ -31,7 +33,7 @@ RANLIB = $(CROSS_COMPILE)ranlib
LDSO_SUFFIX = so
LD_SET_SONAME = -Wl,-soname=
INSTALL_FLAGS = -D -m
INSTALL = ./tools/install.sh
LDSO_PATHNAME = libproxychains4.$(LDSO_SUFFIX)
@@ -39,6 +41,7 @@ SHARED_LIBS = $(LDSO_PATHNAME)
ALL_LIBS = $(SHARED_LIBS)
PXCHAINS = proxychains4
ALL_TOOLS = $(PXCHAINS)
ALL_CONFIGS = src/proxychains.conf
-include config.mak
@@ -48,28 +51,41 @@ CFLAGS_MAIN=-DLIB_DIR=\"$(libdir)\" -DSYSCONFDIR=\"$(sysconfdir)\" -DDLL_NAME=\"
all: $(ALL_LIBS) $(ALL_TOOLS)
install-config:
install -d $(DESTDIR)$(sysconfdir)
install $(INSTALL_FLAGS) 644 src/proxychains.conf $(DESTDIR)$(sysconfdir)/
install: install-libs install-tools
install:
install -d $(DESTDIR)$(bindir)/ $(DESTDIR)$(libdir)/
install $(INSTALL_FLAGS) 755 $(ALL_TOOLS) $(DESTDIR)$(bindir)/
install $(INSTALL_FLAGS) 644 $(ALL_LIBS) $(DESTDIR)$(libdir)/
$(DESTDIR)$(bindir)/%: %
$(INSTALL) -D -m 755 $< $@
$(DESTDIR)$(libdir)/%: %
$(INSTALL) -D -m 644 $< $@
$(DESTDIR)$(sysconfdir)/%: src/%
$(INSTALL) -D -m 644 $< $@
install-libs: $(ALL_LIBS:%=$(DESTDIR)$(libdir)/%)
install-tools: $(ALL_TOOLS:%=$(DESTDIR)$(bindir)/%)
install-config: $(ALL_CONFIGS:src/%=$(DESTDIR)$(sysconfdir)/%)
clean:
rm -f $(ALL_LIBS)
rm -f $(ALL_TOOLS)
rm -f $(OBJS)
rm -f $(GENH)
src/version.h: $(wildcard VERSION .git)
printf '#define VERSION "%s"\n' "$$(sh tools/version.sh)" > $@
src/version.o: src/version.h
%.o: %.c
$(CC) $(CFLAGS) $(CFLAGS_MAIN) $(INC) $(PIC) -c -o $@ $<
$(CC) $(CPPFLAGS) $(CFLAGS) $(CFLAGS_MAIN) $(INC) $(PIC) -c -o $@ $<
$(LDSO_PATHNAME): $(LOBJS)
$(CC) $(LDFLAGS) $(LD_SET_SONAME)$(LDSO_PATHNAME) -o $@ $(LOBJS)
$(CC) $(LDFLAGS) $(LD_SET_SONAME)$(LDSO_PATHNAME) $(USER_LDFLAGS) \
-o $@ $(LOBJS)
$(ALL_TOOLS): $(OBJS)
$(CC) src/main.o src/common.o -o $(PXCHAINS)
$(CC) src/main.o src/common.o $(USER_LDFLAGS) -o $(PXCHAINS)
.PHONY: all clean install install-config
.PHONY: all clean install install-config install-libs install-tools
+62 -15
View File
@@ -1,4 +1,4 @@
ProxyChains-NG ver 4.8 README
ProxyChains-NG ver 4.11 README
=============================
ProxyChains is a UNIX program, that hooks network-related libc functions
@@ -7,13 +7,13 @@ ProxyChains-NG ver 4.8 README
It supports TCP only (no UDP/ICMP etc).
The way it works is basically a HACK; so it is possible that it doesn't
work with your program, especially when it's a script, or starts
work with your program, especially when it's a script, or starts
numerous processes like background daemons or uses dlopen() to load
"modules" (bug in glibc dynlinker).
It should work with simple compiled (C/C++) dynamically linked programs
though.
If your program doesn't work with proxychains, consider using an
If your program doesn't work with proxychains, consider using an
iptables based solution instead; this is much more robust.
Supported Platforms: Linux, BSD, Mac.
@@ -35,8 +35,8 @@ ProxyChains-NG ver 4.8 README
ONLY USE PROXYCHAINS IF YOU KNOW WHAT YOU'RE DOING.
THE AUTHORS AND MAINTAINERS OF PROXYCHAINS DO NOT TAKE ANY
RESPONSIBILITY FOR ANY ABUSE OR MISUSE OF THIS SOFTWARE AND
THE AUTHORS AND MAINTAINERS OF PROXYCHAINS DO NOT TAKE ANY
RESPONSIBILITY FOR ANY ABUSE OR MISUSE OF THIS SOFTWARE AND
THE RESULTING CONSEQUENCES.
*** Installation ***
@@ -52,20 +52,43 @@ ProxyChains-NG ver 4.8 README
Changelog:
----------
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:
- fix regression in 4.8 install-config Makefile target
Version 4.8:
- fix for odd cornercase where getaddrinfo was used with AI_NUMERICHOST
to test for a numeric ip instead of resolving it (fixes nmap).
- allow usage with programs that rely on LD_PRELOAD themselves
- reject wrong entries in config file
- print version number on startup
Version 4.7:
- new round_robin chaintype by crazz.
- new round_robin chaintype by crass.
- fix bug with lazy allocation when GCC constructor was not used.
- new configure flag --fat-binary to create a "fat" binary/library on OS X
- return EBADF rather than EINTR in close hook.
- return EBADF rather than EINTR in close hook.
it's legal for a program to retry close() calls when they receive
EINTR, which could cause an infinite loop, as seen in chromium.
Version 4.6:
- some cosmetic fixes to Makefile, fix a bug when non-numeric ip was
user as proxy server address.
used as proxy server address.
Version 4.5:
- hook close() to prevent OpenSSH from messing with internal infrastructure.
this caused ssh client to segfault when proxified.
@@ -85,13 +108,13 @@ Version 4.2:
- fixes compilation issues with ubuntu 12.04 toolchain
- fixes segfault in rare codepath
Version 4.1
Version 4.1
- support for mac os x (all archs)
- all internal functions are threadsafe when compiled with -DTHREAD_SAFE
- all internal functions are threadsafe when compiled with -DTHREAD_SAFE
(default).
Version 4.0
- replaced dnsresolver script (which required a dynamically linked "dig"
- replaced dnsresolver script (which required a dynamically linked "dig"
binary to be present) with remote DNS lookup.
this speeds up any operation involving DNS, as the old script had to use TCP.
additionally it allows to use .onion urls when used with TOR.
@@ -101,7 +124,7 @@ Version 4.0
environment variables.
Version 3.0
- support for DNS resolving through proxy
- support for DNS resolving through proxy
supports SOCKS4, SOCKS5 and HTTP CONNECT proxy servers.
Auth-types: socks - "user/pass" , http - "basic".
@@ -123,7 +146,7 @@ Some cool features:
random order from the list ( user defined length of chain ).
exact order (as they appear in the list )
dynamic order (smart exclude dead proxies from chain)
* You can use it with most TCP client applications, possibly even network
* You can use it with most TCP client applications, possibly even network
scanners, as long as they use standard libc functionality.
pcap based scanning does not work.
* You can use it with servers, like squid, sendmail, or whatever.
@@ -151,9 +174,9 @@ specified by proxychains.conf
Usage Example:
$ proxychains -f /etc/proxychains-other.conf targethost2.com
$ proxychains -f /etc/proxychains-other.conf telnet targethost2.com
in this example it will use different configuration file then proxychains.conf
in this example it will use different configuration file then proxychains.conf
to connect to targethost2.com host.
Usage Example:
@@ -163,6 +186,30 @@ Usage Example:
in this example it will resolve targethost.com through proxy(or chained proxies)
specified by proxychains.conf
Known Problems:
---------------
- newer versions of nmap try to determine the network interface to use
even if it's not needed (like when doing simple syn scans which use the
standard POSIX socket API. this results in errors when proxychains hands
out an ip address to a reserved address space.
possible workarounds: disable proxy_dns, use a numeric ip, or use nmap's
native support for SOCKS proxies.
- Mac OS X 10.11 (El Capitan) ships with a new security feature called SIP
that prevents hooking of system apps.
workarounds are to partially disable SIP by issuing
csrutil enable --without debug in recovery mode,
or to copy the system binary into the home directory and run it from there.
see github issue #78 for details.
- the glibc dynlinker has a bug or security feature that inhibits dlopen()ed
modules from being subject to the same dlsym hooks as installed for the main
program. this mainly affects scripting languages such as perl or python
that heavily rely on dlopen() for modules written in C to work.
there are unconfirmed reports that it works as root though.
musl libc is unaffected from the bug.
Community:
----------
#proxychains on irc.freenode.net
+1
View File
@@ -0,0 +1 @@
4.11
Vendored
+70 -10
View File
@@ -14,14 +14,56 @@ isbsd() {
uname -s | grep BSD >/dev/null
}
isopenbsd() {
uname -s | grep OpenBSD >/dev/null
}
check_compile() {
printf "checking %s ... " "$1"
local tmp=$(mktemp)
printf "$3" > "$tmp".c
local res=0
$CC $CPPFLAGS $2 $CFLAGS -c "$tmp".c -o "$tmp".o >/dev/null 2>&1 \
|| res=1
rm -f "$tmp".c "$tmp".o
test x$res = x0 && \
{ printf "yes\n" ; test x"$2" = x || CPPFLAGS="$CPPFLAGS $2" ; } \
|| printf "no\n"
return $res
}
check_define() {
printf "checking whether \$CC defines %s ... " "$1"
local res=1
$CC $CPPFLAGS $CFLAGS -dM -E - </dev/null | grep "$1" >/dev/null && res=0
test x$res = x0 && printf "yes\n" || printf "no\n"
return $res
}
check_compile_run() {
printf "checking %s ... " "$1"
local tmp=$(mktemp)
printf "$2" > "$tmp".c
local res=0
$CC $CPPFLAGS $CFLAGS "$tmp".c -o "$tmp".out >/dev/null 2>&1 \
|| res=1
test x$res = x0 && { "$tmp".out || res=1 ; }
rm -f "$tmp".c "$tmp".o "$tmp".out
test x$res = x0 && printf "yes\n" || printf "no\n"
return $res
}
usage() {
echo "supported arguments"
echo "--prefix=/path default: $prefix"
echo "--exec_prefix=/path default: $prefix/bin"
echo "--bindir=/path default: $prefix/bin"
echo "--libdir=/path default: $prefix/lib"
echo "--includedir=/path default: $prefix/include"
echo "--sysconfdir=/path default: $prefix/etc"
echo "--prefix=/path default: $prefix"
echo "--exec_prefix=/path default: $prefix/bin"
echo "--bindir=/path default: $prefix/bin"
echo "--libdir=/path default: $prefix/lib"
echo "--includedir=/path default: $prefix/include"
echo "--sysconfdir=/path default: $prefix/etc"
echo "--ignore-cve default: no"
echo " if set to yes ignores CVE-2015-3887 and makes it possible"
echo " to preload from current dir (insecure)"
ismac && isx86_64 && echo "--fat-binary : build for both i386 and x86_64 architectures on 64-bit Macs"
echo "--help : show this text"
exit 1
@@ -35,7 +77,7 @@ spliteq() {
}
fat_binary=
ignore_cve=no
parsearg() {
case "$1" in
--prefix=*) prefix=`spliteq $1`;;
@@ -44,6 +86,8 @@ parsearg() {
--libdir=*) libdir=`spliteq $1`;;
--includedir=*) includedir=`spliteq $1`;;
--sysconfdir=*) sysconfdir=`spliteq $1`;;
--ignore-cve) ignore_cve=1;;
--ignore-cve=*) ignore_cve=`spliteq $1`;;
--fat-binary) fat_binary=1;;
--help) usage;;
esac
@@ -80,15 +124,31 @@ if [ -z "$CC" ] ; then
CC=cc
fi
check_compile 'whether netinet/in.h defines s6_addr16' "" \
'#include <netinet/in.h>\nint main(int a, char**c){struct in6_addr x={.s6_addr32[0]=a};return x.s6_addr16[0]; }' \
|| {
check_compile 'whether netinet/in.h defines __u6_addr.__u6_addr16' \
'-Ds6_addr16=__u6_addr.__u6_addr16 -Ds6_addr32=__u6_addr.__u6_addr32' \
'#include <netinet/in.h>\nint main(int a, char**c){struct in6_addr x={.s6_addr32[0]=a};return x.s6_addr16[0]; }'
}
check_define __OpenBSD__ && \
check_compile_run 'whether OpenBSDs fclose() (illegally) calls close()' \
'#include <stdio.h>\n#include<stdlib.h>\nint close(int x){exit(0);}int main(){fclose(stdin);return 1;}' && \
CPPFLAGS="$CPPFLAGS -DBROKEN_FCLOSE"
echo CC?=$CC>config.mak
[ -z "$CPPFLAGS" ] || echo CPPFLAGS?=$CPPFLAGS>>config.mak
[ -z "$CFLAGS" ] || echo USER_CFLAGS?=$CFLAGS>>config.mak
[ -z "$LDFLAGS" ] || echo USER_LDFLAGS?=$LDFLAGS>>config.mak
echo prefix=$prefix>>config.mak
echo exec_prefix=$exec_prefix>>config.mak
echo bindir=$bindir>>config.mak
echo libdir=$libdir>>config.mak
echo includedir=$includedir>>config.mak
echo sysconfdir=$sysconfdir>>config.mak
[ "$ignore_cve" = "no" ] && echo CPPFLAGS+= -DSUPER_SECURE>>config.mak
make_cmd=make
if ismac ; then
echo NO_AS_NEEDED=>>config.mak
echo LDSO_SUFFIX=dylib>>config.mak
@@ -99,11 +159,11 @@ if ismac ; then
echo LDFLAGS+=-arch i386 -arch x86_64>>config.mak
fi
echo LD_SET_SONAME=-Wl,-install_name,>>config.mak
echo INSTALL_FLAGS=-m>>config.mak
elif isbsd ; then
echo LIBDL=>>config.mak
echo "CFLAGS+=-DIS_BSD">>config.mak
echo INSTALL_FLAGS=-m>>config.mak
isopenbsd && echo "CFLAGS+=-DIS_OPENBSD">>config.mak
make_cmd=gmake
fi
echo "Done, now run make && make install"
echo "Done, now run $make_cmd && $make_cmd install"
-11
View File
@@ -1,11 +0,0 @@
### config.mak template for proxychains
#######################################
# just copy into proxychains root dir and adapt to your needs.
prefix = /usr/local/
libdir = $(prefix)/lib
exec_prefix = /usr/local
bindir = $(exec_prefix)/bin
+23 -19
View File
@@ -10,12 +10,10 @@
#include <stddef.h>
#include <errno.h>
#include "allocator_thread.h"
#include "shm.h"
#include "debug.h"
#include "ip_type.h"
#include "mutex.h"
#include "hash.h"
#include "stringdump.h"
/* stuff for our internal translation table */
@@ -30,20 +28,26 @@ typedef struct {
string_hash_tuple** list;
} internal_ip_lookup_table;
static void *dumpstring(char* s, size_t len) {
char* p = malloc(len);
if(p) memcpy(p, s, len);
return p;
}
pthread_mutex_t internal_ips_lock;
internal_ip_lookup_table *internal_ips = NULL;
internal_ip_lookup_table internal_ips_buf;
uint32_t index_from_internal_ip(ip_type internalip) {
uint32_t index_from_internal_ip(ip_type4 internalip) {
PFUNC();
ip_type tmp = internalip;
ip_type4 tmp = internalip;
uint32_t ret;
ret = tmp.octet[3] + (tmp.octet[2] << 8) + (tmp.octet[1] << 16);
ret -= 1;
return ret;
}
char *string_from_internal_ip(ip_type internalip) {
char *string_from_internal_ip(ip_type4 internalip) {
PFUNC();
char *res = NULL;
uint32_t index = index_from_internal_ip(internalip);
@@ -53,11 +57,11 @@ char *string_from_internal_ip(ip_type internalip) {
}
extern unsigned int remote_dns_subnet;
ip_type make_internal_ip(uint32_t index) {
ip_type ret;
ip_type4 make_internal_ip(uint32_t index) {
ip_type4 ret;
index++; // so we can start at .0.0.1
if(index > 0xFFFFFF)
return ip_type_invalid;
return ip_type_invalid.addr.v4;
ret.octet[0] = remote_dns_subnet & 0xFF;
ret.octet[1] = (index & 0xFF0000) >> 16;
ret.octet[2] = (index & 0xFF00) >> 8;
@@ -65,10 +69,10 @@ ip_type make_internal_ip(uint32_t index) {
return ret;
}
static ip_type ip_from_internal_list(char* name, size_t len) {
static ip_type4 ip_from_internal_list(char* name, size_t len) {
uint32_t hash = dalias_hash((char *) name);
size_t i;
ip_type res;
ip_type4 res;
void* new_mem;
// see if we already have this dns entry saved.
if(internal_ips->counter) {
@@ -95,7 +99,7 @@ static ip_type ip_from_internal_list(char* name, size_t len) {
}
res = make_internal_ip(internal_ips->counter);
if(res.as_int == ip_type_invalid.as_int)
if(res.as_int == ip_type_invalid.addr.v4.as_int)
goto err_plus_unlock;
string_hash_tuple tmp = { 0 };
@@ -124,7 +128,7 @@ static ip_type ip_from_internal_list(char* name, size_t len) {
err_plus_unlock:
PDEBUG("return err\n");
return ip_type_invalid;
return ip_type_invalid.addr.v4;
}
/* stuff for communication with the allocator thread */
@@ -201,7 +205,7 @@ static void* threadfunc(void* x) {
struct at_msghdr msg;
union {
char host[MSG_LEN_MAX];
ip_type ip;
ip_type4 ip;
} readbuf;
while((ret = getmessage(ATD_SERVER, &msg, &readbuf))) {
switch(msg.msgtype) {
@@ -209,7 +213,7 @@ static void* threadfunc(void* x) {
/* client wants an ip for a DNS name. iterate our list and check if we have an existing entry.
* if not, create a new one. */
readbuf.ip = ip_from_internal_list(readbuf.host, msg.datalen - 1);
msg.datalen = sizeof(ip_type);
msg.datalen = sizeof(ip_type4);
break;
case ATM_GETNAME: {
char *host = string_from_internal_ip(readbuf.ip);
@@ -233,8 +237,8 @@ static void* threadfunc(void* x) {
/* API to access the internal ip mapping */
ip_type at_get_ip_for_host(char* host, size_t len) {
ip_type readbuf;
ip_type4 at_get_ip_for_host(char* host, size_t len) {
ip_type4 readbuf;
MUTEX_LOCK(&internal_ips_lock);
if(len > MSG_LEN_MAX) goto inv;
struct at_msghdr msg = {.msgtype = ATM_GETIP, .datalen = len + 1 };
@@ -242,14 +246,14 @@ ip_type at_get_ip_for_host(char* host, size_t len) {
getmessage(ATD_CLIENT, &msg, &readbuf));
else {
inv:
readbuf = ip_type_invalid;
readbuf = ip_type_invalid.addr.v4;
}
MUTEX_UNLOCK(&internal_ips_lock);
return readbuf;
}
size_t at_get_host_for_ip(ip_type ip, char* readbuf) {
struct at_msghdr msg = {.msgtype = ATM_GETNAME, .datalen = sizeof(ip_type) };
size_t at_get_host_for_ip(ip_type4 ip, char* readbuf) {
struct at_msghdr msg = {.msgtype = ATM_GETNAME, .datalen = sizeof(ip_type4) };
size_t res = 0;
MUTEX_LOCK(&internal_ips_lock);
if(sendmessage(ATD_SERVER, &msg, &ip) && getmessage(ATD_CLIENT, &msg, readbuf)) {
+2 -2
View File
@@ -11,8 +11,8 @@ extern int resp_pipefd[2];
void at_init(void);
void at_close(void);
size_t at_get_host_for_ip(ip_type ip, char* readbuf);
ip_type at_get_ip_for_host(char* host, size_t len);
size_t at_get_host_for_ip(ip_type4 ip, char* readbuf);
ip_type4 at_get_ip_for_host(char* host, size_t len);
//RcB: DEP "allocator_thread.c"
#endif
+3 -3
View File
@@ -59,7 +59,7 @@ char *get_config_path(char* default_path, char* pbuf, size_t bufsize) {
char *path = default_path;
if(check_path(path))
goto have;
// priority 1: env var PROXYCHAINS_CONF_FILE
path = getenv(PROXYCHAINS_CONF_FILE_ENV_VAR);
if(check_path(path))
@@ -88,10 +88,10 @@ char *get_config_path(char* default_path, char* pbuf, size_t bufsize) {
path = "/etc/" PROXYCHAINS_CONF_FILE;
if(check_path(path))
goto have;
perror("couldnt find configuration file");
exit(1);
return NULL;
have:
return path;
+221 -219
View File
@@ -37,7 +37,6 @@
#include "core.h"
#include "common.h"
#include "shm.h"
#include "allocator_thread.h"
extern int tcp_read_time_out;
@@ -199,8 +198,8 @@ static int tunnel_to(int sock, ip_type ip, unsigned short port, proxy_type pt, c
// the range 224-255.* is reserved, and it won't go outside (unless the app does some other stuff with
// the results returned from gethostbyname et al.)
// the hardcoded number 224 can now be changed using the config option remote_dns_subnet to i.e. 127
if(ip.octet[0] == remote_dns_subnet) {
dns_len = at_get_host_for_ip(ip, hostnamebuf);
if(!ip.is_v6 && ip.addr.v4.octet[0] == remote_dns_subnet) {
dns_len = at_get_host_for_ip(ip.addr.v4, hostnamebuf);
if(!dns_len) goto err;
else dns_name = hostnamebuf;
}
@@ -217,209 +216,196 @@ static int tunnel_to(int sock, ip_type ip, unsigned short port, proxy_type pt, c
int len;
unsigned char buff[BUFF_SIZE];
char ip_buf[16];
char ip_buf[INET6_ADDRSTRLEN];
int v6 = ip.is_v6;
//memset (buff, 0, sizeof(buff));
switch (pt) {
case HTTP_TYPE:{
if(!dns_len) {
pc_stringfromipv4(&ip.octet[0], ip_buf);
dns_name = ip_buf;
}
snprintf((char *) buff, sizeof(buff), "CONNECT %s:%d HTTP/1.0\r\n", dns_name,
ntohs(port));
if(user[0]) {
#define HTTP_AUTH_MAX ((0xFF * 2) + 1 + 1)
// 2 * 0xff: username and pass, plus 1 for ':' and 1 for zero terminator.
char src[HTTP_AUTH_MAX];
char dst[(4 * HTTP_AUTH_MAX)];
memcpy(src, user, ulen);
memcpy(src + ulen, ":", 1);
memcpy(src + ulen + 1, pass, passlen);
src[ulen + 1 + passlen] = 0;
encode_base_64(src, dst, sizeof(dst));
strcat((char *) buff, "Proxy-Authorization: Basic ");
strcat((char *) buff, dst);
strcat((char *) buff, "\r\n\r\n");
} else
strcat((char *) buff, "\r\n");
len = strlen((char *) buff);
if(len != send(sock, buff, len, 0))
if(!dns_len) {
if(!inet_ntop(v6?AF_INET6:AF_INET,ip.addr.v6,ip_buf,sizeof ip_buf)) {
proxychains_write_log(LOG_PREFIX "error: ip address conversion failed\n");
goto err;
len = 0;
// read header byte by byte.
while(len < BUFF_SIZE) {
if(1 == read_n_bytes(sock, (char *) (buff + len), 1))
len++;
else
goto err;
if(len > 4 &&
buff[len - 1] == '\n' &&
buff[len - 2] == '\r' && buff[len - 3] == '\n' && buff[len - 4] == '\r')
break;
}
// if not ok (200) or response greather than BUFF_SIZE return BLOCKED;
if(len == BUFF_SIZE || !(buff[9] == '2' && buff[10] == '0' && buff[11] == '0')) {
PDEBUG("HTTP proxy blocked: buff=\"%s\"\n", buff);
return BLOCKED;
}
return SUCCESS;
dns_name = ip_buf;
}
break;
#define HTTP_AUTH_MAX ((0xFF * 2) + 1 + 1) /* 2 * 0xff: username and pass, plus 1 for ':' and 1 for zero terminator. */
char src[HTTP_AUTH_MAX];
char dst[(4 * HTTP_AUTH_MAX)];
if(ulen) {
snprintf(src, sizeof(src), "%s:%s", user, pass);
encode_base_64(src, dst, sizeof(dst));
} else dst[0] = 0;
len = snprintf((char *) buff, sizeof(buff),
"CONNECT %s:%d HTTP/1.0\r\n%s%s%s\r\n",
dns_name, ntohs(port),
ulen ? "Proxy-Authorization: Basic " : dst,
dst, ulen ? "\r\n" : dst);
if(len != send(sock, buff, len, 0))
goto err;
len = 0;
// read header byte by byte.
while(len < BUFF_SIZE) {
if(1 == read_n_bytes(sock, (char *) (buff + len), 1))
len++;
else
goto err;
if(len > 4 &&
buff[len - 1] == '\n' &&
buff[len - 2] == '\r' && buff[len - 3] == '\n' && buff[len - 4] == '\r')
break;
}
// if not ok (200) or response greather than BUFF_SIZE return BLOCKED;
if(len == BUFF_SIZE || !(buff[9] == '2' && buff[10] == '0' && buff[11] == '0')) {
PDEBUG("HTTP proxy blocked: buff=\"%s\"\n", buff);
return BLOCKED;
}
return SUCCESS;
}
break;
case SOCKS4_TYPE:{
buff[0] = 4; // socks version
buff[1] = 1; // connect command
memcpy(&buff[2], &port, 2); // dest port
if(dns_len) {
ip.octet[0] = 0;
ip.octet[1] = 0;
ip.octet[2] = 0;
ip.octet[3] = 1;
}
memcpy(&buff[4], &ip, 4); // dest host
len = ulen + 1; // username
if(len > 1)
memcpy(&buff[8], user, len);
else {
buff[8] = 0;
}
// do socksv4a dns resolution on the server
if(dns_len) {
memcpy(&buff[8 + len], dns_name, dns_len + 1);
len += dns_len + 1;
}
if((len + 8) != write_n_bytes(sock, (char *) buff, (8 + len)))
goto err;
if(8 != read_n_bytes(sock, (char *) buff, 8))
goto err;
if(buff[0] != 0 || buff[1] != 90)
return BLOCKED;
return SUCCESS;
if(v6) {
proxychains_write_log(LOG_PREFIX "error: SOCKS4 doesnt support ipv6 addresses\n");
goto err;
}
break;
buff[0] = 4; // socks version
buff[1] = 1; // connect command
memcpy(&buff[2], &port, 2); // dest port
if(dns_len) {
ip.addr.v4.octet[0] = 0;
ip.addr.v4.octet[1] = 0;
ip.addr.v4.octet[2] = 0;
ip.addr.v4.octet[3] = 1;
}
memcpy(&buff[4], &ip.addr.v4, 4); // dest host
len = ulen + 1; // username
if(len > 1)
memcpy(&buff[8], user, len);
else {
buff[8] = 0;
}
// do socksv4a dns resolution on the server
if(dns_len) {
memcpy(&buff[8 + len], dns_name, dns_len + 1);
len += dns_len + 1;
}
if((len + 8) != write_n_bytes(sock, (char *) buff, (8 + len)))
goto err;
if(8 != read_n_bytes(sock, (char *) buff, 8))
goto err;
if(buff[0] != 0 || buff[1] != 90)
return BLOCKED;
return SUCCESS;
}
break;
case SOCKS5_TYPE:{
if(user) {
buff[0] = 5; //version
buff[1] = 2; //nomber of methods
buff[2] = 0; // no auth method
buff[3] = 2; /// auth method -> username / password
if(4 != write_n_bytes(sock, (char *) buff, 4))
goto err;
} else {
buff[0] = 5; //version
buff[1] = 1; //nomber of methods
buff[2] = 0; // no auth method
if(3 != write_n_bytes(sock, (char *) buff, 3))
goto err;
}
int n_methods = ulen ? 2 : 1;
buff[0] = 5; // version
buff[1] = n_methods ; // number of methods
buff[2] = 0; // no auth method
if(ulen) buff[3] = 2; /// auth method -> username / password
if(2+n_methods != write_n_bytes(sock, (char *) buff, 2+n_methods))
goto err;
if(2 != read_n_bytes(sock, (char *) buff, 2))
if(2 != read_n_bytes(sock, (char *) buff, 2))
goto err;
if(buff[0] != 5 || (buff[1] != 0 && buff[1] != 2)) {
if(buff[0] == 5 && buff[1] == 0xFF)
return BLOCKED;
else
goto err;
if(buff[0] != 5 || (buff[1] != 0 && buff[1] != 2)) {
if(buff[0] == 5 && buff[1] == 0xFF)
return BLOCKED;
else
goto err;
}
if(buff[1] == 2) {
// authentication
char in[2];
char out[515];
char *cur = out;
size_t c;
*cur++ = 1; // version
c = ulen & 0xFF;
*cur++ = c;
memcpy(cur, user, c);
cur += c;
c = passlen & 0xFF;
*cur++ = c;
memcpy(cur, pass, c);
cur += c;
if((cur - out) != write_n_bytes(sock, out, cur - out))
goto err;
if(2 != read_n_bytes(sock, in, 2))
goto err;
if(in[0] != 1 || in[1] != 0) {
if(in[0] != 1)
goto err;
else
return BLOCKED;
}
}
int buff_iter = 0;
buff[buff_iter++] = 5; // version
buff[buff_iter++] = 1; // connect
buff[buff_iter++] = 0; // reserved
if(!dns_len) {
buff[buff_iter++] = 1; // ip v4
memcpy(buff + buff_iter, &ip, 4); // dest host
buff_iter += 4;
} else {
buff[buff_iter++] = 3; //dns
buff[buff_iter++] = dns_len & 0xFF;
memcpy(buff + buff_iter, dns_name, dns_len);
buff_iter += dns_len;
}
memcpy(buff + buff_iter, &port, 2); // dest port
buff_iter += 2;
if(buff_iter != write_n_bytes(sock, (char *) buff, buff_iter))
goto err;
if(4 != read_n_bytes(sock, (char *) buff, 4))
goto err;
if(buff[0] != 5 || buff[1] != 0)
goto err;
switch (buff[3]) {
case 1:
len = 4;
break;
case 4:
len = 16;
break;
case 3:
len = 0;
if(1 != read_n_bytes(sock, (char *) &len, 1))
goto err;
break;
default:
goto err;
}
if(len + 2 != read_n_bytes(sock, (char *) buff, len + 2))
goto err;
return SUCCESS;
}
break;
if(buff[1] == 2) {
// authentication
char in[2];
char out[515];
char *cur = out;
size_t c;
*cur++ = 1; // version
c = ulen & 0xFF;
*cur++ = c;
memcpy(cur, user, c);
cur += c;
c = passlen & 0xFF;
*cur++ = c;
memcpy(cur, pass, c);
cur += c;
if((cur - out) != write_n_bytes(sock, out, cur - out))
goto err;
if(2 != read_n_bytes(sock, in, 2))
goto err;
if(in[0] != 1 || in[1] != 0) {
if(in[0] != 1)
goto err;
else
return BLOCKED;
}
}
int buff_iter = 0;
buff[buff_iter++] = 5; // version
buff[buff_iter++] = 1; // connect
buff[buff_iter++] = 0; // reserved
if(!dns_len) {
buff[buff_iter++] = v6 ? 4 : 1; // ip v4/v6
memcpy(buff + buff_iter, ip.addr.v6, v6?16:4); // dest host
buff_iter += v6?16:4;
} else {
buff[buff_iter++] = 3; //dns
buff[buff_iter++] = dns_len & 0xFF;
memcpy(buff + buff_iter, dns_name, dns_len);
buff_iter += dns_len;
}
memcpy(buff + buff_iter, &port, 2); // dest port
buff_iter += 2;
if(buff_iter != write_n_bytes(sock, (char *) buff, buff_iter))
goto err;
if(4 != read_n_bytes(sock, (char *) buff, 4))
goto err;
if(buff[0] != 5 || buff[1] != 0)
goto err;
switch (buff[3]) {
case 1:
len = 4;
break;
case 4:
len = 16;
break;
case 3:
len = 0;
if(1 != read_n_bytes(sock, (char *) &len, 1))
goto err;
break;
default:
goto err;
}
if(len + 2 != read_n_bytes(sock, (char *) buff, len + 2))
goto err;
return SUCCESS;
}
break;
}
err:
@@ -433,22 +419,30 @@ static int tunnel_to(int sock, ip_type ip, unsigned short port, proxy_type pt, c
#define RRT "Round Robin chain"
static int start_chain(int *fd, proxy_data * pd, char *begin_mark) {
struct sockaddr_in addr;
char ip_buf[16];
int v6 = pd->ip.is_v6;
*fd = socket(PF_INET, SOCK_STREAM, 0);
*fd = socket(v6?PF_INET6:PF_INET, SOCK_STREAM, 0);
if(*fd == -1)
goto error;
pc_stringfromipv4(&pd->ip.octet[0], ip_buf);
char ip_buf[INET6_ADDRSTRLEN];
if(!inet_ntop(v6?AF_INET6:AF_INET,pd->ip.addr.v6,ip_buf,sizeof ip_buf))
goto error;
proxychains_write_log(LOG_PREFIX "%s " TP " %s:%d ",
begin_mark, ip_buf, htons(pd->port));
pd->ps = PLAY_STATE;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = (in_addr_t) pd->ip.as_int;
addr.sin_port = pd->port;
if(timed_connect(*fd, (struct sockaddr *) &addr, sizeof(addr))) {
struct sockaddr_in addr = {
.sin_family = AF_INET,
.sin_port = pd->port,
.sin_addr.s_addr = (in_addr_t) pd->ip.addr.v4.as_int
};
struct sockaddr_in6 addr6 = {
.sin6_family = AF_INET6,
.sin6_port = pd->port,
};
if(v6) memcpy(&addr6.sin6_addr.s6_addr, pd->ip.addr.v6, 16);
if(timed_connect(*fd, (struct sockaddr *) (v6?(void*)&addr6:(void*)&addr), v6?sizeof(addr6):sizeof(addr))) {
pd->ps = DOWN_STATE;
goto error1;
}
@@ -519,16 +513,22 @@ static int chain_step(int ns, proxy_data * pfrom, proxy_data * pto) {
int retcode = -1;
char *hostname;
char hostname_buf[MSG_LEN_MAX];
char ip_buf[16];
char ip_buf[INET6_ADDRSTRLEN];
int v6 = pto->ip.is_v6;
PFUNC();
if(pto->ip.octet[0] == remote_dns_subnet) {
if(!at_get_host_for_ip(pto->ip, hostname_buf)) goto usenumericip;
if(!v6 && pto->ip.addr.v4.octet[0] == remote_dns_subnet) {
if(!at_get_host_for_ip(pto->ip.addr.v4, hostname_buf)) goto usenumericip;
else hostname = hostname_buf;
} else {
usenumericip:
pc_stringfromipv4(&pto->ip.octet[0], ip_buf);
if(!inet_ntop(v6?AF_INET6:AF_INET,pto->ip.addr.v6,ip_buf,sizeof ip_buf)) {
pto->ps = DOWN_STATE;
proxychains_write_log("<--ip conversion error!\n");
close(ns);
return SOCKET_ERROR;
}
hostname = ip_buf;
}
@@ -719,11 +719,7 @@ int connect_proxy_chain(int sock, ip_type target_ip,
return -1;
}
#include "hostentdb.h"
struct hostent_list hl;
void core_initialize(void) {
hdb_init(&hl);
}
void core_unload(void) {
@@ -734,6 +730,7 @@ static void gethostbyname_data_setstring(struct gethostbyname_data* data, char*
data->hostent_space.h_name = data->addr_name;
}
extern ip_type4 hostsreader_get_numeric_ip_for_name(const char* name);
struct hostent *proxy_gethostbyname(const char *name, struct gethostbyname_data* data) {
PFUNC();
char buff[256];
@@ -754,21 +751,19 @@ struct hostent *proxy_gethostbyname(const char *name, struct gethostbyname_data*
if(!strcmp(buff, name)) {
data->resolved_addr = inet_addr(buff);
if(data->resolved_addr == (in_addr_t) (-1))
data->resolved_addr = (in_addr_t) (ip_type_localhost.as_int);
data->resolved_addr = (in_addr_t) (ip_type_localhost.addr.v4.as_int);
goto retname;
}
memset(buff, 0, sizeof(buff));
// this iterates over the "known hosts" db, usually /etc/hosts
ip_type hdb_res = hdb_get(&hl, (char*) name);
if(hdb_res.as_int != ip_type_invalid.as_int) {
ip_type4 hdb_res = hostsreader_get_numeric_ip_for_name(name);
if(hdb_res.as_int != ip_type_invalid.addr.v4.as_int) {
data->resolved_addr = hdb_res.as_int;
goto retname;
}
data->resolved_addr = at_get_ip_for_host((char*) name, strlen(name)).as_int;
if(data->resolved_addr == (in_addr_t) ip_type_invalid.as_int) return NULL;
if(data->resolved_addr == (in_addr_t) ip_type_invalid.addr.v4.as_int) return NULL;
retname:
@@ -790,8 +785,12 @@ void proxy_freeaddrinfo(struct addrinfo *res) {
free(res);
}
#ifdef IS_MAC
/* getservbyname on mac is using thread local storage, so we dont need mutex */
#if defined(IS_MAC) || defined(IS_OPENBSD)
#ifdef IS_OPENBSD /* OpenBSD has its own incompatible getservbyname_r */
#define getservbyname_r mygetservbyname_r
#endif
/* getservbyname on mac is using thread local storage, so we dont need mutex
TODO: check if the same applies to OpenBSD */
static int getservbyname_r(const char* name, const char* proto, struct servent* result_buf,
char* buf, size_t buflen, struct servent** result) {
PFUNC();
@@ -847,7 +846,7 @@ int proxy_getaddrinfo(const char *node, const char *service, const struct addrin
p->ai_addr = &space->sockaddr_space;
if(node)
strncpy(space->addr_name, node, sizeof(space->addr_name));
snprintf(space->addr_name, sizeof(space->addr_name), "%s", node);
p->ai_canonname = space->addr_name;
p->ai_next = NULL;
p->ai_family = space->sockaddr_space.sa_family = AF_INET;
@@ -858,6 +857,9 @@ int proxy_getaddrinfo(const char *node, const char *service, const struct addrin
p->ai_flags = hints->ai_flags;
p->ai_protocol = hints->ai_protocol;
} else {
#ifndef AI_V4MAPPED
#define AI_V4MAPPED 0
#endif
p->ai_flags = (AI_V4MAPPED | AI_ADDRCONFIG);
}
+4
View File
@@ -95,6 +95,10 @@ typedef int (*getaddrinfo_t)(const char *, const char *, const struct addrinfo *
typedef int (*getnameinfo_t) (const struct sockaddr *, socklen_t, char *,
socklen_t, char *, socklen_t, int);
typedef ssize_t (*sendto_t) (int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen);
extern connect_t true_connect;
extern gethostbyname_t true_gethostbyname;
+6 -2
View File
@@ -3,11 +3,15 @@
# include "core.h"
# include "common.h"
# include "debug.h"
#include <arpa/inet.h>
void DUMP_PROXY_CHAIN(proxy_data *pchain, unsigned int count) {
char ip_buf[16];
char ip_buf[INET6_ADDRSTRLEN];
for (; count; pchain++, count--) {
pc_stringfromipv4(&pchain->ip.octet[0], ip_buf);
if(!inet_ntop(pchain->ip.is_v6?AF_INET6:AF_INET,pchain->ip.addr.v6,ip_buf,sizeof ip_buf)) {
proxychains_write_log(LOG_PREFIX "error: ip address conversion failed\n");
continue;
}
PDEBUG("[%s] %s %s:%d", proxy_state_strmap[pchain->ps],
proxy_type_strmap[pchain->pt],
ip_buf, htons(pchain->port));
+2
View File
@@ -5,12 +5,14 @@
# include <stdio.h>
# define PSTDERR(fmt, args...) do { dprintf(2,fmt, ## args); } while(0)
# define PDEBUG(fmt, args...) PSTDERR("DEBUG:"fmt, ## args)
# define DEBUGDECL(args...) args
# include "core.h"
void DUMP_PROXY_CHAIN(proxy_data *pchain, unsigned int count);
#else
# define PDEBUG(fmt, args...) do {} while (0)
# define DEBUGDECL(args...)
# define DUMP_PROXY_CHAIN(args...) do {} while (0)
#endif
-63
View File
@@ -1,63 +0,0 @@
#include <stdint.h>
#include <string.h>
#include <netdb.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include "ip_type.h"
#include "hash.h"
#include "stringdump.h"
#include "hostentdb.h"
#include "common.h"
#include "debug.h"
#define STEP 16
static void hdb_add(struct hostent_list* hl, char* host, ip_type ip) {
if(hl->count +1 > hl->capa) {
void * nu = realloc(hl->entries, (hl->capa + STEP) * sizeof(struct hostent_entry));
if(!nu) return;
hl->entries = nu;
hl->capa += STEP;
}
struct hostent_entry *h = &hl->entries[hl->count];
h->hash = dalias_hash(host);
h->ip.as_int = ip.as_int;
h->str = dumpstring(host, strlen(host) + 1);
if(h->str) hl->count++;
}
static void hdb_fill(struct hostent_list *hl) {
#ifndef IS_BSD
struct hostent* hp;
while((hp = gethostent()))
if(hp->h_addrtype == AF_INET && hp->h_length == sizeof(in_addr_t)) {
hdb_add(hl, hp->h_name, (ip_type) { .as_int = *((in_addr_t*)(hp->h_addr_list[0])) });
}
#else
/* FreeBSD hangs on gethostent(). since this feature is not crucial, we just do nothing */
(void) hl;
#endif
}
void hdb_init(struct hostent_list *hl) {
memset(hl, 0, sizeof *hl);
hdb_fill(hl);
}
ip_type hdb_get(struct hostent_list *hl, char* host) {
size_t i;
PFUNC();
uint32_t hash = dalias_hash(host);
for(i = 0; i < hl->count; i++) {
if(hl->entries[i].hash == hash && !strcmp(hl->entries[i].str, host)) {
#ifdef DEBUG
char ipbuf[16];
pc_stringfromipv4(hl->entries[i].ip.octet, ipbuf);
PDEBUG("got ip %s for hostent entry %s\n", ipbuf, host);
#endif
return hl->entries[i].ip;
}
}
return ip_type_invalid;
}
-23
View File
@@ -1,23 +0,0 @@
#ifndef HOSTENTDB_H
#define HOSTENTDB_H
#include "ip_type.h"
#include <unistd.h>
struct hostent_entry {
uint32_t hash;
ip_type ip;
char* str;
};
struct hostent_list {
size_t count;
size_t capa;
struct hostent_entry *entries;
};
void hdb_init(struct hostent_list *hl);
ip_type hdb_get(struct hostent_list *hl, char* host);
//RcB: DEP "hostendb.c"
#endif
+123
View File
@@ -0,0 +1,123 @@
#include <stdio.h>
#include <ctype.h>
#include <string.h>
/*
simple reader for /etc/hosts
it only supports comments, blank lines and lines consisting of an ipv4 hostname pair.
this is required so we can return entries from the host db without messing up the
non-thread-safe state of libc's gethostent().
*/
struct hostsreader {
FILE *f;
char* ip, *name;
};
int hostsreader_open(struct hostsreader *ctx) {
if(!(ctx->f = fopen("/etc/hosts", "r"))) return 0;
return 1;
}
void hostsreader_close(struct hostsreader *ctx) {
fclose(ctx->f);
}
static int isnumericipv4(const char* ipstring);
int hostsreader_get(struct hostsreader *ctx, char* buf, size_t bufsize) {
while(1) {
if(!fgets(buf, bufsize, ctx->f)) return 0;
if(*buf == '#') continue;
char *p = buf;
size_t l = bufsize;
ctx->ip = p;
while(*p && !isspace(*p) && l) {
p++;
l--;
}
if(!l || !*p || p == ctx->ip) continue;
*p = 0;
p++;
while(*p && isspace(*p) && l) {
p++;
l--;
}
if(!l || !*p) continue;
ctx->name = p;
while(*p && !isspace(*p) && l) {
p++;
l--;
}
if(!l || !*p) continue;
*p = 0;
if(isnumericipv4(ctx->ip)) return 1;
}
}
char* hostsreader_get_ip_for_name(const char* name, char* buf, size_t bufsize) {
struct hostsreader ctx;
char *res = 0;
if(!hostsreader_open(&ctx)) return 0;
while(hostsreader_get(&ctx, buf, bufsize)) {
if(!strcmp(ctx.name, name)) {
res = ctx.ip;
break;
}
}
hostsreader_close(&ctx);
return res;
}
#include "ip_type.h"
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
ip_type4 hostsreader_get_numeric_ip_for_name(const char* name) {
char *hres;
char buf[320];
if((hres = hostsreader_get_ip_for_name(name, buf, sizeof buf))) {
struct in_addr c;
inet_aton(hres, &c);
ip_type4 res;
memcpy(res.octet, &c.s_addr, 4);
return res;
} else return ip_type_invalid.addr.v4;
}
#ifdef HOSTSREADER_TEST
#include "ip_type.c"
int main(int a, char**b) {
char buf[256];
if(a != 2) return 1;
char * ret = hostsreader_get_ip_for_name(b[1], buf, sizeof buf);
printf("%s\n", ret ? ret : "null");
}
#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;
}
+2 -2
View File
@@ -1,5 +1,5 @@
#include "ip_type.h"
const ip_type ip_type_invalid = { .as_int = -1 };
const ip_type ip_type_localhost = { {127, 0, 0, 1} };
const ip_type ip_type_invalid = { .addr.v4.as_int = -1 };
const ip_type ip_type_localhost = { .addr.v4 = {127, 0, 0, 1} };
+8
View File
@@ -6,6 +6,14 @@
typedef union {
unsigned char octet[4];
uint32_t as_int;
} ip_type4;
typedef struct {
union {
ip_type4 v4;
unsigned char v6[16];
} addr;
char is_v6;
} ip_type;
extern const ip_type ip_type_invalid;
+117 -73
View File
@@ -52,6 +52,7 @@ getaddrinfo_t true_getaddrinfo;
freeaddrinfo_t true_freeaddrinfo;
getnameinfo_t true_getnameinfo;
gethostbyaddr_t true_gethostbyaddr;
sendto_t true_sendto;
int tcp_read_time_out;
int tcp_connect_time_out;
@@ -76,7 +77,7 @@ static inline void get_chain_data(proxy_data * pd, unsigned int *proxy_count, ch
static void* load_sym(char* symname, void* proxyfunc) {
void *funcptr = dlsym(RTLD_NEXT, symname);
if(!funcptr) {
fprintf(stderr, "Cannot load symbol '%s' %s\n", symname, dlerror());
exit(1);
@@ -94,43 +95,36 @@ static void* load_sym(char* symname, void* proxyfunc) {
#define SETUP_SYM(X) do { true_ ## X = load_sym( # X, X ); } while(0)
#include "shm.h"
#include "allocator_thread.h"
#include "stringdump.h"
static void do_init(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);
const char *proxychains_get_version(void);
proxychains_write_log(LOG_PREFIX "DLL init\n");
static void setup_hooks(void) {
SETUP_SYM(connect);
SETUP_SYM(sendto);
SETUP_SYM(gethostbyname);
SETUP_SYM(getaddrinfo);
SETUP_SYM(freeaddrinfo);
SETUP_SYM(gethostbyaddr);
SETUP_SYM(getnameinfo);
SETUP_SYM(close);
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();
static void do_init(void) {
srand(time(NULL));
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_hooks();
init_l = 1;
}
#endif
static void init_lib_wrapper(const char* caller) {
#ifndef DEBUG
@@ -168,7 +162,7 @@ static void get_chain_data(proxy_data * pd, unsigned int *proxy_count, chain_typ
tcp_read_time_out = 4 * 1000;
tcp_connect_time_out = 10 * 1000;
*ct = DYNAMIC_TYPE;
env = get_config_path(getenv(PROXYCHAINS_CONF_FILE_ENV_VAR), buff, sizeof(buff));
if( ( file = fopen(env, "r") ) == NULL )
{
@@ -186,21 +180,27 @@ static void get_chain_data(proxy_data * pd, unsigned int *proxy_count, chain_typ
if(list) {
if(count >= MAX_CHAIN)
break;
memset(&pd[count], 0, sizeof(proxy_data));
pd[count].ps = PLAY_STATE;
port_n = 0;
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) {
inv:
fprintf(stderr, "error: invalid item in proxylist section: %s", buff);
exit(1);
}
in_addr_t host_ip = inet_addr(host);
if(host_ip == INADDR_NONE) {
memset(&pd[count].ip, 0, sizeof(pd[count].ip));
pd[count].ip.is_v6 = !!strchr(host, ':');
pd[count].port = htons((unsigned short) port_n);
ip_type* host_ip = &pd[count].ip;
if(1 != inet_pton(host_ip->is_v6 ? AF_INET6 : AF_INET, host, host_ip->addr.v6)) {
fprintf(stderr, "proxy %s has invalid value or is not numeric\n", host);
exit(1);
}
pd[count].ip.as_int = (uint32_t) host_ip;
pd[count].port = htons((unsigned short) port_n);
if(!strcmp(type, "http")) {
pd[count].pt = HTTP_TYPE;
@@ -209,9 +209,9 @@ static void get_chain_data(proxy_data * pd, unsigned int *proxy_count, chain_typ
} else if(!strcmp(type, "socks5")) {
pd[count].pt = SOCKS5_TYPE;
} else
continue;
goto inv;
if(pd[count].ip.as_int && port_n && pd[count].ip.as_int != (uint32_t) - 1)
if(port_n)
count++;
} else {
if(strstr(buff, "[ProxyList]")) {
@@ -290,7 +290,13 @@ static void get_chain_data(proxy_data * pd, unsigned int *proxy_count, chain_typ
}
}
}
#ifndef BROKEN_FCLOSE
fclose(file);
#endif
if(!count) {
fprintf(stderr, "error: no valid proxy found in config\n");
exit(1);
}
*proxy_count = count;
proxychains_got_chain_data = 1;
}
@@ -307,39 +313,52 @@ int close(int fd) {
errno = EBADF;
return -1;
}
static int is_v4inv6(const struct in6_addr *a) {
return a->s6_addr32[0] == 0 && a->s6_addr32[1] == 0 &&
a->s6_addr16[4] == 0 && a->s6_addr16[5] == 0xffff;
}
int connect(int sock, const struct sockaddr *addr, unsigned int len) {
INIT();
PFUNC();
int socktype = 0, flags = 0, ret = 0;
socklen_t optlen = 0;
ip_type dest_ip;
#ifdef DEBUG
char str[256];
#endif
DEBUGDECL(char str[256]);
struct in_addr *p_addr_in;
struct in6_addr *p_addr_in6;
unsigned short port;
size_t i;
int remote_dns_connect = 0;
INIT();
optlen = sizeof(socktype);
sa_family_t fam = SOCKFAMILY(*addr);
getsockopt(sock, SOL_SOCKET, SO_TYPE, &socktype, &optlen);
if(!(SOCKFAMILY(*addr) == AF_INET && socktype == SOCK_STREAM))
if(!((fam == AF_INET || fam == AF_INET6) && socktype == SOCK_STREAM))
return true_connect(sock, addr, len);
int v6 = dest_ip.is_v6 = fam == AF_INET6;
p_addr_in = &((struct sockaddr_in *) addr)->sin_addr;
port = ntohs(((struct sockaddr_in *) addr)->sin_port);
p_addr_in6 = &((struct sockaddr_in6 *) addr)->sin6_addr;
port = !v6 ? ntohs(((struct sockaddr_in *) addr)->sin_port)
: ntohs(((struct sockaddr_in6 *) addr)->sin6_port);
struct in_addr v4inv6;
if(v6 && is_v4inv6(p_addr_in6)) {
memcpy(&v4inv6.s_addr, &p_addr_in6->s6_addr32[3], 4);
v6 = dest_ip.is_v6 = 0;
p_addr_in = &v4inv6;
}
#ifdef DEBUG
// PDEBUG("localnet: %s; ", inet_ntop(AF_INET,&in_addr_localnet, str, sizeof(str)));
// PDEBUG("netmask: %s; " , inet_ntop(AF_INET, &in_addr_netmask, str, sizeof(str)));
PDEBUG("target: %s\n", inet_ntop(AF_INET, p_addr_in, str, sizeof(str)));
PDEBUG("target: %s\n", inet_ntop(v6 ? AF_INET6 : AF_INET, v6 ? (void*)p_addr_in6 : (void*)p_addr_in, str, sizeof(str)));
PDEBUG("port: %d\n", port);
#endif
// check if connect called from proxydns
remote_dns_connect = (ntohl(p_addr_in->s_addr) >> 24 == remote_dns_subnet);
remote_dns_connect = !v6 && (ntohl(p_addr_in->s_addr) >> 24 == remote_dns_subnet);
for(i = 0; i < num_localnet_addr && !remote_dns_connect; i++) {
if (!v6) for(i = 0; i < num_localnet_addr && !remote_dns_connect; i++) {
if((localnet_addr[i].in_addr.s_addr & localnet_addr[i].netmask.s_addr)
== (p_addr_in->s_addr & localnet_addr[i].netmask.s_addr)) {
if(!localnet_addr[i].port || localnet_addr[i].port == port) {
@@ -353,11 +372,11 @@ int connect(int sock, const struct sockaddr *addr, unsigned int len) {
if(flags & O_NONBLOCK)
fcntl(sock, F_SETFL, !O_NONBLOCK);
dest_ip.as_int = SOCKADDR(*addr);
memcpy(dest_ip.addr.v6, v6 ? (void*)p_addr_in6 : (void*)p_addr_in, v6?16:4);
ret = connect_proxy_chain(sock,
dest_ip,
SOCKPORT(*addr),
htons(port),
proxychains_pd, proxychains_proxy_count, proxychains_ct, proxychains_max_chain);
fcntl(sock, F_SETFL, flags);
@@ -369,7 +388,6 @@ int connect(int sock, const struct sockaddr *addr, unsigned int len) {
static struct gethostbyname_data ghbndata;
struct hostent *gethostbyname(const char *name) {
INIT();
PDEBUG("gethostbyname: %s\n", name);
if(proxychains_resolver)
@@ -381,72 +399,79 @@ struct hostent *gethostbyname(const char *name) {
}
int getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res) {
int ret = 0;
INIT();
PDEBUG("getaddrinfo: %s %s\n", node ? node : "null", service ? service : "null");
if(proxychains_resolver)
ret = proxy_getaddrinfo(node, service, hints, res);
return proxy_getaddrinfo(node, service, hints, res);
else
ret = true_getaddrinfo(node, service, hints, res);
return ret;
return true_getaddrinfo(node, service, hints, res);
}
void freeaddrinfo(struct addrinfo *res) {
INIT();
PDEBUG("freeaddrinfo %p \n", res);
if(!proxychains_resolver)
true_freeaddrinfo(res);
else
proxy_freeaddrinfo(res);
return;
}
int pc_getnameinfo(const struct sockaddr *sa, socklen_t salen,
char *host, socklen_t hostlen, char *serv,
int pc_getnameinfo(const struct sockaddr *sa, socklen_t salen,
char *host, socklen_t hostlen, char *serv,
socklen_t servlen, int flags)
{
char ip_buf[16];
int ret = 0;
INIT();
PFUNC();
if(!proxychains_resolver) {
ret = true_getnameinfo(sa, salen, host, hostlen, serv, servlen, flags);
return true_getnameinfo(sa, salen, host, hostlen, serv, servlen, flags);
} else {
if(salen < sizeof(struct sockaddr_in) || SOCKFAMILY(*sa) != AF_INET)
if(!salen || !(SOCKFAMILY(*sa) == AF_INET || SOCKFAMILY(*sa) == AF_INET6))
return EAI_FAMILY;
int v6 = SOCKFAMILY(*sa) == AF_INET6;
if(salen < (v6?sizeof(struct sockaddr_in6):sizeof(struct sockaddr_in)))
return EAI_FAMILY;
if(hostlen) {
pc_stringfromipv4((unsigned char*) &(SOCKADDR_2(*sa)), ip_buf);
if(snprintf(host, hostlen, "%s", ip_buf) >= hostlen)
unsigned char v4inv6buf[4];
const void *ip = v6 ? (void*)&((struct sockaddr_in6*)sa)->sin6_addr
: (void*)&((struct sockaddr_in*)sa)->sin_addr;
unsigned scopeid = 0;
if(v6) {
if(is_v4inv6(&((struct sockaddr_in6*)sa)->sin6_addr)) {
memcpy(v4inv6buf, &((struct sockaddr_in6*)sa)->sin6_addr.s6_addr32[3], 4);
ip = v4inv6buf;
v6 = 0;
} else
scopeid = ((struct sockaddr_in6 *)sa)->sin6_scope_id;
}
if(!inet_ntop(v6?AF_INET6:AF_INET,ip,host,hostlen))
return EAI_OVERFLOW;
if(scopeid) {
size_t l = strlen(host);
if(snprintf(host+l, hostlen-l, "%%%u", scopeid) >= hostlen-l)
return EAI_OVERFLOW;
}
}
if(servlen) {
if(snprintf(serv, servlen, "%d", ntohs(SOCKPORT(*sa))) >= servlen)
return EAI_OVERFLOW;
}
}
return ret;
return 0;
}
struct hostent *gethostbyaddr(const void *addr, socklen_t len, int type) {
INIT();
PDEBUG("TODO: proper gethostbyaddr hook\n");
static char buf[16];
static char ipv4[4];
static char *list[2];
static char *aliases[1];
static struct hostent he;
INIT();
PDEBUG("TODO: proper gethostbyaddr hook\n");
if(!proxychains_resolver)
return true_gethostbyaddr(addr, len, type);
else {
@@ -468,3 +493,22 @@ struct hostent *gethostbyaddr(const void *addr, socklen_t len, int type) {
}
return NULL;
}
#ifndef MSG_FASTOPEN
# define MSG_FASTOPEN 0x20000000
#endif
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen) {
INIT();
PFUNC();
if (flags & MSG_FASTOPEN) {
if (!connect(sockfd, dest_addr, addrlen) && errno != EINPROGRESS) {
return -1;
}
dest_addr = NULL;
addrlen = 0;
flags &= ~MSG_FASTOPEN;
}
return true_sendto(sockfd, buf, len, flags, dest_addr, addrlen);
}
+24 -8
View File
@@ -33,7 +33,9 @@ static const char *dll_name = DLL_NAME;
static char own_dir[256];
static const char *dll_dirs[] = {
#ifndef SUPER_SECURE /* CVE-2015-3887 */
".",
#endif
own_dir,
LIB_DIR,
"/lib",
@@ -48,7 +50,11 @@ static void set_own_dir(const char *argv0) {
while(l && argv0[l - 1] != '/')
l--;
if(l == 0)
#ifdef SUPER_SECURE
memcpy(own_dir, "/dev/null/", 11);
#else
memcpy(own_dir, ".", 2);
#endif
else {
memcpy(own_dir, argv0, l - 1);
own_dir[l] = 0;
@@ -89,7 +95,7 @@ int main(int argc, char *argv[]) {
/* check if path of config file has not been passed via command line */
path = get_config_path(path, pbuf, sizeof(pbuf));
if(!quiet)
fprintf(stderr, LOG_PREFIX "config file found: %s\n", path);
@@ -103,7 +109,7 @@ int main(int argc, char *argv[]) {
// search DLL
set_own_dir(argv[0]);
i = 0;
while(dll_dirs[i]) {
@@ -122,14 +128,24 @@ int main(int argc, char *argv[]) {
if(!quiet)
fprintf(stderr, LOG_PREFIX "preloading %s/%s\n", prefix, dll_name);
#ifndef IS_MAC
snprintf(buf, sizeof(buf), "LD_PRELOAD=%s/%s", prefix, dll_name);
putenv(buf);
#else
snprintf(buf, sizeof(buf), "DYLD_INSERT_LIBRARIES=%s/%s", prefix, dll_name);
putenv(buf);
#ifdef IS_MAC
putenv("DYLD_FORCE_FLAT_NAMESPACE=1");
#define LD_PRELOAD_ENV "DYLD_INSERT_LIBRARIES"
#define LD_PRELOAD_SEP ":"
#else
#define LD_PRELOAD_ENV "LD_PRELOAD"
/* all historic implementations of BSD and linux dynlinkers seem to support
space as LD_PRELOAD separator, with colon added only recently.
we use the old syntax for maximum compat */
#define LD_PRELOAD_SEP " "
#endif
char *old_val = getenv(LD_PRELOAD_ENV);
snprintf(buf, sizeof(buf), LD_PRELOAD_ENV "=%s/%s%s%s",
prefix, dll_name,
/* append previous LD_PRELOAD content, if existent */
old_val ? LD_PRELOAD_SEP : "",
old_val ? old_val : "");
putenv(buf);
execvp(argv[start_argv], &argv[start_argv]);
perror("proxychains can't load process....");
-53
View File
@@ -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;
}
-17
View File
@@ -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
-13
View File
@@ -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);
}
-12
View File
@@ -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
+6
View File
@@ -0,0 +1,6 @@
#include "version.h"
static const char version[] = VERSION;
const char *proxychains_get_version(void) {
return version;
}
+62 -18
View File
@@ -11,73 +11,117 @@
#define SOCKPORT(x) (satosin(x)->sin_port)
#define SOCKFAMILY(x) (satosin(x)->sin_family)
#define ASSERT(X) { if(!(X)) printf("ASSERTION FAILED: %s @%s:%d\n", # X, __FILE__, __LINE__); }
#define CLR() { hbuf[0] = 0; sbuf[0] = 0; }
int main() {
struct sockaddr a = {0}, *sa = &a;
struct sockaddr_in a = {0}, *sa = &a;
char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
SOCKPORT(a) = htons(80);
memcpy( &( (struct sockaddr_in*) sa ) ->sin_addr , (char[]) {127,0,0,1}, 4);
a.sin_port = htons(80);
memcpy( &a.sin_addr , (char[]) {127,0,0,1}, 4);
int ret;
if ((ret = getnameinfo(sa, 0, hbuf, sizeof(hbuf), sbuf,
if ((ret = getnameinfo((void*)sa, 0, hbuf, sizeof(hbuf), sbuf,
sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV)) == 0)
printf("host=%s, serv=%s\n", hbuf, sbuf);
else
printf("%s\n", gai_strerror(ret));
assert(ret == EAI_FAMILY);
ASSERT(ret == EAI_FAMILY);
CLR();
if ((ret = getnameinfo(sa, sizeof a, hbuf, sizeof(hbuf), sbuf,
if ((ret = getnameinfo((void*)sa, sizeof a, hbuf, sizeof(hbuf), sbuf,
sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV)) == 0)
printf("host=%s, serv=%s\n", hbuf, sbuf);
else
printf("%s\n", gai_strerror(ret));
assert(ret == EAI_FAMILY);
ASSERT(ret == EAI_FAMILY);
CLR();
SOCKFAMILY(a) = AF_INET;
if ((ret = getnameinfo(sa, sizeof a, hbuf, 1, sbuf,
if ((ret = getnameinfo((void*)sa, sizeof a, hbuf, 1, sbuf,
sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV)) == 0)
printf("host=%s, serv=%s\n", hbuf, sbuf);
else
printf("%s\n", gai_strerror(ret));
assert(ret == EAI_OVERFLOW);
ASSERT(ret == EAI_OVERFLOW);
CLR();
if ((ret = getnameinfo(sa, sizeof a, hbuf, 0, sbuf,
if ((ret = getnameinfo((void*)sa, sizeof a, hbuf, 0, sbuf,
1, NI_NUMERICHOST | NI_NUMERICSERV)) == 0)
printf("host=%s, serv=%s\n", hbuf, sbuf);
else
printf("%s\n", gai_strerror(ret));
assert(ret == EAI_OVERFLOW);
ASSERT(ret == EAI_OVERFLOW);
CLR();
if ((ret = getnameinfo(sa, sizeof a, hbuf, 0, sbuf,
if ((ret = getnameinfo((void*)sa, sizeof(a) - 1, hbuf, 0, sbuf,
sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV)) == 0)
printf("host=%s, serv=%s\n", hbuf, sbuf);
else
printf("%s\n", gai_strerror(ret));
assert(ret == 0);
ASSERT(ret == EAI_FAMILY);
CLR();
if ((ret = getnameinfo(sa, sizeof a, hbuf, sizeof hbuf, sbuf,
if ((ret = getnameinfo((void*)sa, sizeof a, hbuf, 0, sbuf,
sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV)) == 0)
printf("host=%s, serv=%s\n", hbuf, sbuf);
else
printf("%s\n", gai_strerror(ret));
ASSERT(ret == 0 && !strcmp("80", sbuf));
CLR();
if ((ret = getnameinfo((void*)sa, sizeof a, hbuf, sizeof hbuf, sbuf,
0, NI_NUMERICHOST | NI_NUMERICSERV)) == 0)
printf("host=%s, serv=%s\n", hbuf, sbuf);
else
printf("%s\n", gai_strerror(ret));
assert(ret == 0);
ASSERT(ret == 0 && !strcmp("127.0.0.1",hbuf));
CLR();
if ((ret = getnameinfo(sa, sizeof a, hbuf, sizeof(hbuf), sbuf,
if ((ret = getnameinfo((void*)sa, sizeof a, hbuf, sizeof(hbuf), sbuf,
sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV)) == 0)
printf("host=%s, serv=%s\n", hbuf, sbuf);
else
printf("%s\n", gai_strerror(ret));
assert(ret == 0);
ASSERT(ret == 0 && !strcmp("127.0.0.1",hbuf) && !strcmp("80", sbuf));
CLR();
struct sockaddr_in6 b = {0}, *sb = &b;
b.sin6_port = htons(8080);
b.sin6_family = AF_INET6;
memcpy(&b.sin6_addr,"\0\0\0\0\0\0\0\0\0\0\xff\xff\xc0\xa8\1\2", 16);
if ((ret = getnameinfo((void*)sb, sizeof b, hbuf, sizeof(hbuf), sbuf,
sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV)) == 0)
printf("host=%s, serv=%s\n", hbuf, sbuf);
else
printf("%s\n", gai_strerror(ret));
ASSERT(ret == 0 && !strcmp("192.168.1.2",hbuf) && !strcmp("8080", sbuf));
CLR();
b.sin6_scope_id = 3;
memcpy(&b.sin6_addr,"\0\0\xaa\0\0\0\0\0\0\0\0\xff\xc0\xa8\1\2", 16);
if ((ret = getnameinfo((void*)sb, sizeof b, hbuf, sizeof(hbuf), sbuf,
sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV | NI_NUMERICSCOPE)) == 0)
printf("host=%s, serv=%s\n", hbuf, sbuf);
else
printf("%s\n", gai_strerror(ret));
ASSERT(ret == 0);
return 0;
}
+66
View File
@@ -0,0 +1,66 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#ifndef MSG_FASTOPEN
# define MSG_FASTOPEN 0x20000000
#endif
void error(const char *msg)
{
perror(msg);
exit(1);
}
int main(int argc, char *argv[])
{
if (argc < 4) {
printf("Usage: %s host port method(connect or sendto)\n", argv[0]);
return 1;
}
const char *hostname = argv[1];
const int portno = atoi(argv[2]);
const char *method = argv[3];
char request[BUFSIZ];
sprintf(request, "GET / HTTP/1.0\r\nHost: %s\r\n\r\n", hostname);
int sockfd, n;
struct sockaddr_in serv_addr;
struct hostent *server;
char buffer[BUFSIZ];
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) error("ERROR opening socket");
server = gethostbyname(hostname);
if (server == NULL) {
fprintf(stderr, "%s: no such host\n", hostname);
return 1;
}
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
memcpy(&serv_addr.sin_addr.s_addr, server->h_addr, server->h_length);
serv_addr.sin_port = htons(portno);
if (!strcmp(method, "connect")) {
if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
error("connect");
n = send(sockfd, request, strlen(request), 0);
} else if (!strcmp(method, "sendto")) {
n = sendto(sockfd, request, strlen(request), MSG_FASTOPEN, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
} else {
printf("Unknown method %s\n", method);
return 1;
}
if (n < 0)
error("send");
memset(buffer, 0, BUFSIZ);
n = read(sockfd, buffer, BUFSIZ - 1);
if (n < 0)
error("ERROR reading from socket");
printf("%s\n", buffer);
close(sockfd);
return 0;
}
+42
View File
@@ -0,0 +1,42 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/socket.h>
static void v4_to_v6(const struct in_addr *v4, struct in6_addr *v6) {
memset(v6, 0, sizeof(*v6));
v6->s6_addr[10]=0xff;
v6->s6_addr[11]=0xff;
memcpy(&v6->s6_addr[12], &v4->s_addr, 4);
}
int main(void) {
struct addrinfo *result;
struct addrinfo *res;
const struct addrinfo hints = { .ai_family = AF_INET };
int error, sock;
/* resolve the domain name into a list of addresses */
error = getaddrinfo("www.example.com", NULL, &hints, &result);
if (error != 0) {
fprintf(stderr, "error in getaddrinfo: %s\n", gai_strerror(error));
return EXIT_FAILURE;
}
if((sock=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
perror("socket");
return EXIT_FAILURE;
}
struct sockaddr_in6 a = { .sin6_family = AF_INET6,
.sin6_port = htons(80) };
v4_to_v6(&((struct sockaddr_in *)result->ai_addr)->sin_addr, &a.sin6_addr);
freeaddrinfo(result);
if((error = connect(sock, (struct sockaddr *)&a, sizeof(a))) == -1) {
perror("connect");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
+64
View File
@@ -0,0 +1,64 @@
#!/bin/sh
#
# This is an actually-safe install command which installs the new
# file atomically in the new location, rather than overwriting
# existing files.
#
usage() {
printf "usage: %s [-D] [-l] [-m mode] src dest\n" "$0" 1>&2
exit 1
}
mkdirp=
symlink=
mode=755
while getopts Dlm: name ; do
case "$name" in
D) mkdirp=yes ;;
l) symlink=yes ;;
m) mode=$OPTARG ;;
?) usage ;;
esac
done
shift $(($OPTIND - 1))
test "$#" -eq 2 || usage
src=$1
dst=$2
tmp="$dst.tmp.$$"
case "$dst" in
*/) printf "%s: %s ends in /\n", "$0" "$dst" 1>&2 ; exit 1 ;;
esac
set -C
set -e
if test "$mkdirp" ; then
umask 022
case "$2" in
*/*) mkdir -p "${dst%/*}" ;;
esac
fi
trap 'rm -f "$tmp"' EXIT INT QUIT TERM HUP
umask 077
if test "$symlink" ; then
ln -s "$1" "$tmp"
else
cat < "$1" > "$tmp"
chmod "$mode" "$tmp"
fi
mv -f "$tmp" "$2"
test -d "$2" && {
rm -f "$2/$tmp"
printf "%s: %s is a directory\n" "$0" "$dst" 1>&2
exit 1
}
exit 0
+12
View File
@@ -0,0 +1,12 @@
#!/bin/sh
if test -d .git ; then
if type git >/dev/null 2>&1 ; then
git describe --tags --match 'v[0-9]*' 2>/dev/null \
| sed -e 's/^v//' -e 's/-/-git-/'
else
sed 's/$/-git/' < VERSION
fi
else
cat VERSION
fi