1
0
mirror of https://github.com/rofl0r/proxychains-ng synced 2026-05-13 17:03:07 +08:00

Compare commits

...

70 Commits

26 changed files with 905 additions and 565 deletions
+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.
+8 -7
View File
@@ -16,16 +16,16 @@ sysconfdir=$(prefix)/etc
SRCS = $(sort $(wildcard src/*.c))
OBJS = $(SRCS:.c=.o)
LOBJS = src/nameinfo.o src/version.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
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
LIBDL = -ldl
LDFLAGS = -shared -fPIC $(NO_AS_NEEDED) $(LIBDL) -lpthread
LDFLAGS = -fPIC $(NO_AS_NEEDED) $(LIBDL) -lpthread
INC =
PIC = -fPIC
AR = $(CROSS_COMPILE)ar
@@ -59,7 +59,7 @@ $(DESTDIR)$(bindir)/%: %
$(DESTDIR)$(libdir)/%: %
$(INSTALL) -D -m 644 $< $@
$(DESTDIR)$(sysconfdir)/%: %
$(DESTDIR)$(sysconfdir)/%: src/%
$(INSTALL) -D -m 644 $< $@
install-libs: $(ALL_LIBS:%=$(DESTDIR)$(libdir)/%)
@@ -81,10 +81,11 @@ src/version.o: src/version.h
$(CC) $(CPPFLAGS) $(CFLAGS) $(CFLAGS_MAIN) $(INC) $(PIC) -c -o $@ $<
$(LDSO_PATHNAME): $(LOBJS)
$(CC) $(LDFLAGS) $(LD_SET_SONAME)$(LDSO_PATHNAME) -o $@ $(LOBJS)
$(CC) $(LDFLAGS) $(LD_SET_SONAME)$(LDSO_PATHNAME) $(USER_LDFLAGS) \
-shared -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 install-libs install-tools
+68 -14
View File
@@ -1,4 +1,4 @@
ProxyChains-NG ver 4.8 README
ProxyChains-NG ver 4.12 README
=============================
ProxyChains is a UNIX program, that hooks network-related libc functions
@@ -7,13 +7,13 @@ ProxyChains-NG ver 4.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,6 +52,34 @@ ProxyChains-NG ver 4.8 README
Changelog:
----------
Version 4.12
- fix several build issues
- for MAC
- with -pie
- with custom CC
- compatibility fix for some GUI apps (8870140)
- compatibility fix for some HTTP proxies (cf9a16d)
- fix several warnings for cleaner build on debian
- fix random_chain on OSX (0f6b226)
Version 4.11
- preliminary IPv6 support
- fixed bug in hostsreader
- preliminary support for usage on OpenBSD (caveat emptor)
Version 4.10
- fix regression in linking order with custom LDFLAGS
- fix segfault in DNS mapping code in programs with > ~400 different lookups
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).
@@ -63,12 +91,14 @@ Version 4.7:
- new round_robin chaintype by crass.
- fix bug with lazy allocation when GCC constructor was not used.
- new configure flag --fat-binary to create a "fat" binary/library on OS X
- return EBADF rather than EINTR in close hook.
- return EBADF rather than EINTR in close hook.
it's legal for a program to retry close() calls when they receive
EINTR, which could cause an infinite loop, as seen in chromium.
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.
@@ -88,13 +118,13 @@ Version 4.2:
- fixes compilation issues with ubuntu 12.04 toolchain
- fixes segfault in rare codepath
Version 4.1
Version 4.1
- support for mac os x (all archs)
- all internal functions are threadsafe when compiled with -DTHREAD_SAFE
- all internal functions are threadsafe when compiled with -DTHREAD_SAFE
(default).
Version 4.0
- replaced dnsresolver script (which required a dynamically linked "dig"
- replaced dnsresolver script (which required a dynamically linked "dig"
binary to be present) with remote DNS lookup.
this speeds up any operation involving DNS, as the old script had to use TCP.
additionally it allows to use .onion urls when used with TOR.
@@ -104,7 +134,7 @@ Version 4.0
environment variables.
Version 3.0
- support for DNS resolving through proxy
- support for DNS resolving through proxy
supports SOCKS4, SOCKS5 and HTTP CONNECT proxy servers.
Auth-types: socks - "user/pass" , http - "basic".
@@ -126,7 +156,7 @@ Some cool features:
random order from the list ( user defined length of chain ).
exact order (as they appear in the list )
dynamic order (smart exclude dead proxies from chain)
* You can use it with most TCP client applications, possibly even network
* You can use it with most TCP client applications, possibly even network
scanners, as long as they use standard libc functionality.
pcap based scanning does not work.
* You can use it with servers, like squid, sendmail, or whatever.
@@ -154,9 +184,9 @@ specified by proxychains.conf
Usage Example:
$ proxychains -f /etc/proxychains-other.conf targethost2.com
$ proxychains -f /etc/proxychains-other.conf telnet targethost2.com
in this example it will use different configuration file then proxychains.conf
in this example it will use different configuration file then proxychains.conf
to connect to targethost2.com host.
Usage Example:
@@ -166,6 +196,30 @@ Usage Example:
in this example it will resolve targethost.com through proxy(or chained proxies)
specified by proxychains.conf
Known Problems:
---------------
- newer versions of nmap try to determine the network interface to use
even if it's not needed (like when doing simple syn scans which use the
standard POSIX socket API. this results in errors when proxychains hands
out an ip address to a reserved address space.
possible workarounds: disable proxy_dns, use a numeric ip, or use nmap's
native support for SOCKS proxies.
- Mac OS X 10.11 (El Capitan) ships with a new security feature called SIP
that prevents hooking of system apps.
workarounds are to partially disable SIP by issuing
csrutil enable --without debug in recovery mode,
or to copy the system binary into the home directory and run it from there.
see github issue #78 for details.
- the glibc dynlinker has a bug or security feature that inhibits dlopen()ed
modules from being subject to the same dlsym hooks as installed for the main
program. this mainly affects scripting languages such as perl or python
that heavily rely on dlopen() for modules written in C to work.
there are unconfirmed reports that it works as root though.
musl libc is unaffected from the bug.
Community:
----------
#proxychains on irc.freenode.net
+1 -1
View File
@@ -1 +1 @@
4.8
4.12
Vendored
+80 -10
View File
@@ -1,6 +1,18 @@
#!/bin/sh
prefix=/usr/local
OUR_CPPFLAGS=
# Get a temporary filename
i=0
set -C
while : ; do i=$(($i+1))
tmpc="./conf$$-$PPID-$i.c"
2>|/dev/null > "$tmpc" && break
test "$i" -gt 50 && fail "$0: cannot create temporary file $tmpc"
done
set +C
trap 'rm "$tmpc"' EXIT INT QUIT TERM HUP
ismac() {
uname -s | grep Darwin >/dev/null
@@ -14,14 +26,53 @@ isbsd() {
uname -s | grep BSD >/dev/null
}
isopenbsd() {
uname -s | grep OpenBSD >/dev/null
}
check_compile() {
printf "checking %s ... " "$1"
printf "$3" > "$tmpc"
local res=0
$CC $OUR_CPPFLAGS $CPPFLAGS $2 $CFLAGS -c "$tmpc" -o /dev/null >/dev/null 2>&1 \
|| res=1
test x$res = x0 && \
{ printf "yes\n" ; test x"$2" = x || OUR_CPPFLAGS="$OUR_CPPFLAGS $2" ; } \
|| printf "no\n"
return $res
}
check_define() {
printf "checking whether \$CC defines %s ... " "$1"
local res=1
$CC $OUR_CPPFLAGS $CPPFLAGS $CFLAGS -dM -E - </dev/null | grep "$1" >/dev/null && res=0
test x$res = x0 && printf "yes\n" || printf "no\n"
return $res
}
check_compile_run() {
printf "checking %s ... " "$1"
printf "$2" > "$tmpc"
local res=0
$CC $OUR_CPPFLAGS $CPPFLAGS $CFLAGS "$tmpc" -o "$tmpc".out >/dev/null 2>&1 \
|| res=1
test x$res = x0 && { "$tmpc".out || res=1 ; }
rm -f "$tmpc".out
test x$res = x0 && printf "yes\n" || printf "no\n"
return $res
}
usage() {
echo "supported arguments"
echo "--prefix=/path default: $prefix"
echo "--exec_prefix=/path default: $prefix/bin"
echo "--bindir=/path default: $prefix/bin"
echo "--libdir=/path default: $prefix/lib"
echo "--includedir=/path default: $prefix/include"
echo "--sysconfdir=/path default: $prefix/etc"
echo "--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 +86,7 @@ spliteq() {
}
fat_binary=
ignore_cve=no
parsearg() {
case "$1" in
--prefix=*) prefix=`spliteq $1`;;
@@ -44,6 +95,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 +133,31 @@ if [ -z "$CC" ] ; then
CC=cc
fi
echo CC?=$CC>config.mak
[ -z "$CPPFLAGS" ] || echo CPPFLAGS?=$CPPFLAGS>>config.mak
[ -z "$CFLAGS" ] || echo USER_CFLAGS?=$CFLAGS>>config.mak
check_compile 'whether netinet/in.h defines s6_addr16' "" \
'#include <netinet/in.h>\nint main(int a, char**c){struct in6_addr x={.s6_addr32[0]=a};return x.s6_addr16[0]; }' \
|| {
check_compile 'whether netinet/in.h defines __u6_addr.__u6_addr16' \
'-Ds6_addr16=__u6_addr.__u6_addr16 -Ds6_addr32=__u6_addr.__u6_addr32' \
'#include <netinet/in.h>\nint main(int a, char**c){struct in6_addr x={.s6_addr32[0]=a};return x.s6_addr16[0]; }'
}
check_define __OpenBSD__ && \
check_compile_run 'whether OpenBSDs fclose() (illegally) calls close()' \
'#include <stdio.h>\n#include<stdlib.h>\nint close(int x){exit(0);}int main(){fclose(stdin);return 1;}' && \
OUR_CPPFLAGS="$OUR_CPPFLAGS -DBROKEN_FCLOSE"
echo "CC=$CC">config.mak
[ -z "$CPPFLAGS" ] || echo "CPPFLAGS=$CPPFLAGS">>config.mak
[ -z "$CFLAGS" ] || echo "USER_CFLAGS=$CFLAGS">>config.mak
[ -z "$LDFLAGS" ] || echo "USER_LDFLAGS=$LDFLAGS">>config.mak
echo prefix=$prefix>>config.mak
echo exec_prefix=$exec_prefix>>config.mak
echo bindir=$bindir>>config.mak
echo libdir=$libdir>>config.mak
echo includedir=$includedir>>config.mak
echo sysconfdir=$sysconfdir>>config.mak
[ "$ignore_cve" = "no" ] && echo "CPPFLAGS+= -DSUPER_SECURE">>config.mak
[ -z "$OUR_CPPFLAGS" ] || echo "CPPFLAGS+= $OUR_CPPFLAGS" >>config.mak
make_cmd=make
if ismac ; then
echo NO_AS_NEEDED=>>config.mak
@@ -103,6 +172,7 @@ if ismac ; then
elif isbsd ; then
echo LIBDL=>>config.mak
echo "CFLAGS+=-DIS_BSD">>config.mak
isopenbsd && echo "CFLAGS+=-DIS_OPENBSD">>config.mak
make_cmd=gmake
fi
-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
+66 -25
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 */
@@ -172,24 +176,61 @@ static int wait_data(int readfd) {
return 1;
}
static int trywrite(int fd, void* buf, size_t bytes) {
ssize_t ret;
unsigned char *out = buf;
again:
ret = write(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 sendmessage(enum at_direction dir, struct at_msghdr *hdr, void* data) {
static int* destfd[ATD_MAX] = { [ATD_SERVER] = &req_pipefd[1], [ATD_CLIENT] = &resp_pipefd[1] };
int ret = write(*destfd[dir], hdr, sizeof *hdr) == sizeof *hdr;
int ret = trywrite(*destfd[dir], hdr, sizeof *hdr);
if(ret && hdr->datalen) {
assert(hdr->datalen <= MSG_LEN_MAX);
ret = write(*destfd[dir], data, hdr->datalen) == hdr->datalen;
ret = trywrite(*destfd[dir], data, hdr->datalen);
}
return ret;
}
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 getmessage(enum at_direction dir, struct at_msghdr *hdr, void* data) {
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]))) {
ret = read(*readfd[dir], hdr, sizeof *hdr) == sizeof(*hdr);
if(!tryread(*readfd[dir], hdr, sizeof *hdr))
return 0;
assert(hdr->datalen <= MSG_LEN_MAX);
if(ret && hdr->datalen) {
ret = read(*readfd[dir], data, hdr->datalen) == hdr->datalen;
if(hdr->datalen) {
ret = tryread(*readfd[dir], data, hdr->datalen);
}
}
return ret;
@@ -201,7 +242,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 +250,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 +274,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 +283,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
+235 -222
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;
@@ -155,10 +154,19 @@ static int timed_connect(int sock, const struct sockaddr *addr, socklen_t len) {
pfd[0].fd = sock;
pfd[0].events = POLLOUT;
fcntl(sock, F_SETFL, O_NONBLOCK);
int flags = fcntl(sock, F_GETFL, 0);
/* put socket temporarily into nonblocking mode so we can enforce
* the timeout. */
if(!(flags & O_NONBLOCK))
fcntl(sock, F_SETFL, flags | O_NONBLOCK);
ret = true_connect(sock, addr, len);
PDEBUG("\nconnect ret=%d\n", ret);
/* if the socket was already non-blocking, we assume the app takes
* care of handling the timeouts itself. */
if(flags & O_NONBLOCK)
return ret;
if(ret == -1 && errno == EINPROGRESS) {
ret = poll_retry(pfd, 1, tcp_connect_time_out);
PDEBUG("\npoll ret=%d\n", ret);
@@ -182,7 +190,7 @@ static int timed_connect(int sock, const struct sockaddr *addr, socklen_t len) {
ret = -1;
}
fcntl(sock, F_SETFL, !O_NONBLOCK);
fcntl(sock, F_SETFL, flags);
return ret;
}
@@ -199,8 +207,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 +225,198 @@ static int tunnel_to(int sock, ip_type ip, unsigned short port, proxy_type pt, c
int len;
unsigned char buff[BUFF_SIZE];
char ip_buf[16];
char ip_buf[INET6_ADDRSTRLEN];
int v6 = ip.is_v6;
//memset (buff, 0, sizeof(buff));
switch (pt) {
case HTTP_TYPE:{
if(!dns_len) {
pc_stringfromipv4(&ip.octet[0], ip_buf);
dns_name = ip_buf;
}
snprintf((char *) buff, sizeof(buff), "CONNECT %s:%d HTTP/1.0\r\n", dns_name,
ntohs(port));
if(user[0]) {
#define HTTP_AUTH_MAX ((0xFF * 2) + 1 + 1)
// 2 * 0xff: username and pass, plus 1 for ':' and 1 for zero terminator.
char src[HTTP_AUTH_MAX];
char dst[(4 * HTTP_AUTH_MAX)];
memcpy(src, user, ulen);
memcpy(src + ulen, ":", 1);
memcpy(src + ulen + 1, pass, passlen);
src[ulen + 1 + passlen] = 0;
encode_base_64(src, dst, sizeof(dst));
strcat((char *) buff, "Proxy-Authorization: Basic ");
strcat((char *) buff, dst);
strcat((char *) buff, "\r\n\r\n");
} else
strcat((char *) buff, "\r\n");
len = strlen((char *) buff);
if(len != send(sock, buff, len, 0))
if(!dns_len) {
if(!inet_ntop(v6?AF_INET6:AF_INET,ip.addr.v6,ip_buf,sizeof ip_buf)) {
proxychains_write_log(LOG_PREFIX "error: ip address conversion failed\n");
goto err;
len = 0;
// read header byte by byte.
while(len < BUFF_SIZE) {
if(1 == read_n_bytes(sock, (char *) (buff + len), 1))
len++;
else
goto err;
if(len > 4 &&
buff[len - 1] == '\n' &&
buff[len - 2] == '\r' && buff[len - 3] == '\n' && buff[len - 4] == '\r')
break;
}
// if not ok (200) or response greather than BUFF_SIZE return BLOCKED;
if(len == BUFF_SIZE || !(buff[9] == '2' && buff[10] == '0' && buff[11] == '0')) {
PDEBUG("HTTP proxy blocked: buff=\"%s\"\n", buff);
return BLOCKED;
}
return SUCCESS;
dns_name = ip_buf;
}
break;
#define HTTP_AUTH_MAX ((0xFF * 2) + 1 + 1) /* 2 * 0xff: username and pass, plus 1 for ':' and 1 for zero terminator. */
char src[HTTP_AUTH_MAX];
char dst[(4 * HTTP_AUTH_MAX)];
if(ulen) {
snprintf(src, sizeof(src), "%s:%s", user, pass);
encode_base_64(src, dst, sizeof(dst));
} else dst[0] = 0;
uint16_t hs_port = ntohs(port);
len = snprintf((char *) buff, sizeof(buff),
"CONNECT %s:%d HTTP/1.0\r\nHost: %s:%d\r\n%s%s%s\r\n",
dns_name, hs_port,
dns_name, hs_port,
ulen ? "Proxy-Authorization: Basic " : dst,
dst, ulen ? "\r\n" : dst);
if(len < 0 || len != send(sock, buff, len, 0))
goto err;
len = 0;
// read header byte by byte.
while(len < BUFF_SIZE) {
if(1 == read_n_bytes(sock, (char *) (buff + len), 1))
len++;
else
goto err;
if(len > 4 &&
buff[len - 1] == '\n' &&
buff[len - 2] == '\r' && buff[len - 3] == '\n' && buff[len - 4] == '\r')
break;
}
// if not ok (200) or response greather than BUFF_SIZE return BLOCKED;
if(len == BUFF_SIZE || !(buff[9] == '2' && buff[10] == '0' && buff[11] == '0')) {
PDEBUG("HTTP proxy blocked: buff=\"%s\"\n", buff);
return BLOCKED;
}
return SUCCESS;
}
break;
case SOCKS4_TYPE:{
buff[0] = 4; // socks version
buff[1] = 1; // connect command
memcpy(&buff[2], &port, 2); // dest port
if(dns_len) {
ip.octet[0] = 0;
ip.octet[1] = 0;
ip.octet[2] = 0;
ip.octet[3] = 1;
}
memcpy(&buff[4], &ip, 4); // dest host
len = ulen + 1; // username
if(len > 1)
memcpy(&buff[8], user, len);
else {
buff[8] = 0;
}
// do socksv4a dns resolution on the server
if(dns_len) {
memcpy(&buff[8 + len], dns_name, dns_len + 1);
len += dns_len + 1;
}
if((len + 8) != write_n_bytes(sock, (char *) buff, (8 + len)))
goto err;
if(8 != read_n_bytes(sock, (char *) buff, 8))
goto err;
if(buff[0] != 0 || buff[1] != 90)
return BLOCKED;
return SUCCESS;
if(v6) {
proxychains_write_log(LOG_PREFIX "error: SOCKS4 doesn't support ipv6 addresses\n");
goto err;
}
break;
buff[0] = 4; // socks version
buff[1] = 1; // connect command
memcpy(&buff[2], &port, 2); // dest port
if(dns_len) {
ip.addr.v4.octet[0] = 0;
ip.addr.v4.octet[1] = 0;
ip.addr.v4.octet[2] = 0;
ip.addr.v4.octet[3] = 1;
}
memcpy(&buff[4], &ip.addr.v4, 4); // dest host
len = ulen + 1; // username
if(len > 1)
memcpy(&buff[8], user, len);
else {
buff[8] = 0;
}
// do socksv4a dns resolution on the server
if(dns_len) {
memcpy(&buff[8 + len], dns_name, dns_len + 1);
len += dns_len + 1;
}
if((len + 8) != write_n_bytes(sock, (char *) buff, (8 + len)))
goto err;
if(8 != read_n_bytes(sock, (char *) buff, 8))
goto err;
if(buff[0] != 0 || buff[1] != 90)
return BLOCKED;
return SUCCESS;
}
break;
case SOCKS5_TYPE:{
if(user) {
buff[0] = 5; //version
buff[1] = 2; //nomber of methods
buff[2] = 0; // no auth method
buff[3] = 2; /// auth method -> username / password
if(4 != write_n_bytes(sock, (char *) buff, 4))
goto err;
} else {
buff[0] = 5; //version
buff[1] = 1; //nomber of methods
buff[2] = 0; // no auth method
if(3 != write_n_bytes(sock, (char *) buff, 3))
goto err;
}
int n_methods = ulen ? 2 : 1;
buff[0] = 5; // version
buff[1] = n_methods ; // number of methods
buff[2] = 0; // no auth method
if(ulen) buff[3] = 2; /// auth method -> username / password
if(2+n_methods != write_n_bytes(sock, (char *) buff, 2+n_methods))
goto err;
if(2 != read_n_bytes(sock, (char *) buff, 2))
if(2 != read_n_bytes(sock, (char *) buff, 2))
goto err;
if(buff[0] != 5 || (buff[1] != 0 && buff[1] != 2)) {
if(buff[0] == 5 && buff[1] == 0xFF)
return BLOCKED;
else
goto err;
if(buff[0] != 5 || (buff[1] != 0 && buff[1] != 2)) {
if(buff[0] == 5 && buff[1] == 0xFF)
return BLOCKED;
else
goto err;
}
if(buff[1] == 2) {
// authentication
char in[2];
char out[515];
char *cur = out;
size_t c;
*cur++ = 1; // version
c = ulen & 0xFF;
*cur++ = c;
memcpy(cur, user, c);
cur += c;
c = passlen & 0xFF;
*cur++ = c;
memcpy(cur, pass, c);
cur += c;
if((cur - out) != write_n_bytes(sock, out, cur - out))
goto err;
if(2 != read_n_bytes(sock, in, 2))
goto err;
if(in[0] != 1 || in[1] != 0) {
if(in[0] != 1)
goto err;
else
return BLOCKED;
}
}
int buff_iter = 0;
buff[buff_iter++] = 5; // version
buff[buff_iter++] = 1; // connect
buff[buff_iter++] = 0; // reserved
if(!dns_len) {
buff[buff_iter++] = 1; // ip v4
memcpy(buff + buff_iter, &ip, 4); // dest host
buff_iter += 4;
} else {
buff[buff_iter++] = 3; //dns
buff[buff_iter++] = dns_len & 0xFF;
memcpy(buff + buff_iter, dns_name, dns_len);
buff_iter += dns_len;
}
memcpy(buff + buff_iter, &port, 2); // dest port
buff_iter += 2;
if(buff_iter != write_n_bytes(sock, (char *) buff, buff_iter))
goto err;
if(4 != read_n_bytes(sock, (char *) buff, 4))
goto err;
if(buff[0] != 5 || buff[1] != 0)
goto err;
switch (buff[3]) {
case 1:
len = 4;
break;
case 4:
len = 16;
break;
case 3:
len = 0;
if(1 != read_n_bytes(sock, (char *) &len, 1))
goto err;
break;
default:
goto err;
}
if(len + 2 != read_n_bytes(sock, (char *) buff, len + 2))
goto err;
return SUCCESS;
}
break;
if(buff[1] == 2) {
// authentication
char in[2];
char out[515];
char *cur = out;
size_t c;
*cur++ = 1; // version
c = ulen & 0xFF;
*cur++ = c;
memcpy(cur, user, c);
cur += c;
c = passlen & 0xFF;
*cur++ = c;
memcpy(cur, pass, c);
cur += c;
if((cur - out) != write_n_bytes(sock, out, cur - out))
goto err;
if(2 != read_n_bytes(sock, in, 2))
goto err;
if(in[0] != 1 || in[1] != 0) {
if(in[0] != 1)
goto err;
else
return BLOCKED;
}
}
int buff_iter = 0;
buff[buff_iter++] = 5; // version
buff[buff_iter++] = 1; // connect
buff[buff_iter++] = 0; // reserved
if(!dns_len) {
buff[buff_iter++] = v6 ? 4 : 1; // ip v4/v6
memcpy(buff + buff_iter, ip.addr.v6, v6?16:4); // dest host
buff_iter += v6?16:4;
} else {
buff[buff_iter++] = 3; //dns
buff[buff_iter++] = dns_len & 0xFF;
memcpy(buff + buff_iter, dns_name, dns_len);
buff_iter += dns_len;
}
memcpy(buff + buff_iter, &port, 2); // dest port
buff_iter += 2;
if(buff_iter != write_n_bytes(sock, (char *) buff, buff_iter))
goto err;
if(4 != read_n_bytes(sock, (char *) buff, 4))
goto err;
if(buff[0] != 5 || buff[1] != 0)
goto err;
switch (buff[3]) {
case 1:
len = 4;
break;
case 4:
len = 16;
break;
case 3:
len = 0;
if(1 != read_n_bytes(sock, (char *) &len, 1))
goto err;
break;
default:
goto err;
}
if(len + 2 != read_n_bytes(sock, (char *) buff, len + 2))
goto err;
return SUCCESS;
}
break;
}
err:
@@ -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"
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;
}
@@ -470,7 +475,7 @@ static proxy_data *select_proxy(select_type how, proxy_data * pd, unsigned int p
case RANDOMLY:
do {
k++;
i = 0 + (unsigned int) (proxy_count * 1.0 * rand() / (RAND_MAX + 1.0));
i = rand() % proxy_count;
} while(pd[i].ps != PLAY_STATE && k < proxy_count * 100);
break;
case FIFOLY:
@@ -519,16 +524,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 +730,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 +741,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 +762,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 +796,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();
@@ -858,6 +868,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;
+12 -2
View File
@@ -3,11 +3,15 @@
# include "core.h"
# include "common.h"
# include "debug.h"
#include <arpa/inet.h>
void DUMP_PROXY_CHAIN(proxy_data *pchain, unsigned int count) {
char ip_buf[16];
char ip_buf[INET6_ADDRSTRLEN];
for (; count; pchain++, count--) {
pc_stringfromipv4(&pchain->ip.octet[0], ip_buf);
if(!inet_ntop(pchain->ip.is_v6?AF_INET6:AF_INET,pchain->ip.addr.v6,ip_buf,sizeof ip_buf)) {
proxychains_write_log(LOG_PREFIX "error: ip address conversion failed\n");
continue;
}
PDEBUG("[%s] %s %s:%d", proxy_state_strmap[pchain->ps],
proxy_type_strmap[pchain->pt],
ip_buf, htons(pchain->port));
@@ -18,4 +22,10 @@ void DUMP_PROXY_CHAIN(proxy_data *pchain, unsigned int count) {
}
}
#else
// Do not allow this translation unit to end up empty
// for non-DEBUG builds, to satisfy ISO C standards.
typedef int __appease_iso_compilers__;
#endif
+2
View File
@@ -5,12 +5,14 @@
# include <stdio.h>
# define PSTDERR(fmt, args...) do { dprintf(2,fmt, ## args); } while(0)
# define PDEBUG(fmt, args...) PSTDERR("DEBUG:"fmt, ## args)
# define DEBUGDECL(args...) args
# include "core.h"
void DUMP_PROXY_CHAIN(proxy_data *pchain, unsigned int count);
#else
# define PDEBUG(fmt, args...) do {} while (0)
# define DEBUGDECL(args...)
# define DUMP_PROXY_CHAIN(args...) do {} while (0)
#endif
-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.octet = {127, 0, 0, 1} };
+8
View File
@@ -6,6 +6,14 @@
typedef union {
unsigned char octet[4];
uint32_t as_int;
} ip_type4;
typedef struct {
union {
ip_type4 v4;
unsigned char v6[16];
} addr;
char is_v6;
} ip_type;
extern const ip_type ip_type_invalid;
+115 -67
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;
@@ -92,17 +93,28 @@ static void* load_sym(char* symname, void* proxyfunc) {
#define INIT() init_lib_wrapper(__FUNCTION__)
#define SETUP_SYM(X) do { true_ ## X = load_sym( # X, X ); } while(0)
#define SETUP_SYM(X) do { if (! true_ ## X ) true_ ## X = load_sym( # X, X ); } while(0)
#include "shm.h"
#include "allocator_thread.h"
#include "stringdump.h"
const char *proxychains_get_version(void);
static void setup_hooks(void) {
SETUP_SYM(connect);
SETUP_SYM(sendto);
SETUP_SYM(gethostbyname);
SETUP_SYM(getaddrinfo);
SETUP_SYM(freeaddrinfo);
SETUP_SYM(gethostbyaddr);
SETUP_SYM(getnameinfo);
SETUP_SYM(close);
}
static int close_fds[16];
static int close_fds_cnt = 0;
static void do_init(void) {
srand(time(NULL));
dumpstring_init(); // global string garbage can
core_initialize();
at_init();
@@ -112,28 +124,13 @@ static void do_init(void) {
proxychains_write_log(LOG_PREFIX "DLL init: proxychains-ng %s\n", proxychains_get_version());
SETUP_SYM(connect);
SETUP_SYM(gethostbyname);
SETUP_SYM(getaddrinfo);
SETUP_SYM(freeaddrinfo);
SETUP_SYM(gethostbyaddr);
SETUP_SYM(getnameinfo);
SETUP_SYM(close);
setup_hooks();
while(close_fds_cnt) true_close(close_fds[--close_fds_cnt]);
init_l = 1;
}
#if 0
/* FIXME this is currently unused.
* it is not strictly needed.
* maybe let it be called by a gcc destructor, if that doesnt
* have negative consequences (e.g. when a child calles exit) */
static void unload(void) {
at_close();
core_unload();
}
#endif
static void init_lib_wrapper(const char* caller) {
#ifndef DEBUG
(void) caller;
@@ -201,13 +198,14 @@ static void get_chain_data(proxy_data * pd, unsigned int *proxy_count, chain_typ
exit(1);
}
in_addr_t host_ip = inet_addr(host);
if(host_ip == INADDR_NONE) {
memset(&pd[count].ip, 0, sizeof(pd[count].ip));
pd[count].ip.is_v6 = !!strchr(host, ':');
pd[count].port = htons((unsigned short) port_n);
ip_type* host_ip = &pd[count].ip;
if(1 != inet_pton(host_ip->is_v6 ? AF_INET6 : AF_INET, host, host_ip->addr.v6)) {
fprintf(stderr, "proxy %s has invalid value or is not numeric\n", host);
exit(1);
}
pd[count].ip.as_int = (uint32_t) host_ip;
pd[count].port = htons((unsigned short) port_n);
if(!strcmp(type, "http")) {
pd[count].pt = HTTP_TYPE;
@@ -218,7 +216,7 @@ static void get_chain_data(proxy_data * pd, unsigned int *proxy_count, chain_typ
} else
goto inv;
if(pd[count].ip.as_int && port_n && pd[count].ip.as_int != (uint32_t) - 1)
if(port_n)
count++;
} else {
if(strstr(buff, "[ProxyList]")) {
@@ -236,7 +234,7 @@ static void get_chain_data(proxy_data * pd, unsigned int *proxy_count, chain_typ
} else if(strstr(buff, "tcp_connect_time_out")) {
sscanf(buff, "%s %d", user, &tcp_connect_time_out);
} else if(strstr(buff, "remote_dns_subnet")) {
sscanf(buff, "%s %d", user, &remote_dns_subnet);
sscanf(buff, "%s %u", user, &remote_dns_subnet);
if(remote_dns_subnet >= 256) {
fprintf(stderr,
"remote_dns_subnet: invalid value. requires a number between 0 and 255.\n");
@@ -287,6 +285,10 @@ static void get_chain_data(proxy_data * pd, unsigned int *proxy_count, chain_typ
char *pc;
int len;
pc = strchr(buff, '=');
if(!pc) {
fprintf(stderr, "error: missing equals sign '=' in chain_len directive.\n");
exit(1);
}
len = atoi(++pc);
proxychains_max_chain = (len ? len : 1);
} else if(strstr(buff, "quiet_mode")) {
@@ -297,7 +299,9 @@ static void get_chain_data(proxy_data * pd, unsigned int *proxy_count, chain_typ
}
}
}
#ifndef BROKEN_FCLOSE
fclose(file);
#endif
if(!count) {
fprintf(stderr, "error: no valid proxy found in config\n");
exit(1);
@@ -309,48 +313,67 @@ static void get_chain_data(proxy_data * pd, unsigned int *proxy_count, chain_typ
/******* HOOK FUNCTIONS *******/
int close(int fd) {
INIT();
if(!init_l) {
if(close_fds_cnt>=(sizeof close_fds/sizeof close_fds[0])) goto err;
close_fds[close_fds_cnt++] = fd;
errno = 0;
return 0;
}
/* prevent rude programs (like ssh) from closing our pipes */
if(fd != req_pipefd[0] && fd != req_pipefd[1] &&
fd != resp_pipefd[0] && fd != resp_pipefd[1]) {
return true_close(fd);
}
err:
errno = EBADF;
return -1;
}
static int is_v4inv6(const struct in6_addr *a) {
return a->s6_addr32[0] == 0 && a->s6_addr32[1] == 0 &&
a->s6_addr16[4] == 0 && a->s6_addr16[5] == 0xffff;
}
int connect(int sock, const struct sockaddr *addr, unsigned int len) {
INIT();
PFUNC();
int socktype = 0, flags = 0, ret = 0;
socklen_t optlen = 0;
ip_type dest_ip;
#ifdef DEBUG
char str[256];
#endif
DEBUGDECL(char str[256]);
struct in_addr *p_addr_in;
struct in6_addr *p_addr_in6;
unsigned short port;
size_t i;
int remote_dns_connect = 0;
INIT();
optlen = sizeof(socktype);
sa_family_t fam = SOCKFAMILY(*addr);
getsockopt(sock, SOL_SOCKET, SO_TYPE, &socktype, &optlen);
if(!(SOCKFAMILY(*addr) == AF_INET && socktype == SOCK_STREAM))
if(!((fam == AF_INET || fam == AF_INET6) && socktype == SOCK_STREAM))
return true_connect(sock, addr, len);
int v6 = dest_ip.is_v6 = fam == AF_INET6;
p_addr_in = &((struct sockaddr_in *) addr)->sin_addr;
port = ntohs(((struct sockaddr_in *) addr)->sin_port);
p_addr_in6 = &((struct sockaddr_in6 *) addr)->sin6_addr;
port = !v6 ? ntohs(((struct sockaddr_in *) addr)->sin_port)
: ntohs(((struct sockaddr_in6 *) addr)->sin6_port);
struct in_addr v4inv6;
if(v6 && is_v4inv6(p_addr_in6)) {
memcpy(&v4inv6.s_addr, &p_addr_in6->s6_addr32[3], 4);
v6 = dest_ip.is_v6 = 0;
p_addr_in = &v4inv6;
}
#ifdef DEBUG
// PDEBUG("localnet: %s; ", inet_ntop(AF_INET,&in_addr_localnet, str, sizeof(str)));
// PDEBUG("netmask: %s; " , inet_ntop(AF_INET, &in_addr_netmask, str, sizeof(str)));
PDEBUG("target: %s\n", inet_ntop(AF_INET, p_addr_in, str, sizeof(str)));
PDEBUG("target: %s\n", inet_ntop(v6 ? AF_INET6 : AF_INET, v6 ? (void*)p_addr_in6 : (void*)p_addr_in, str, sizeof(str)));
PDEBUG("port: %d\n", port);
#endif
// check if connect called from proxydns
remote_dns_connect = (ntohl(p_addr_in->s_addr) >> 24 == remote_dns_subnet);
remote_dns_connect = !v6 && (ntohl(p_addr_in->s_addr) >> 24 == remote_dns_subnet);
for(i = 0; i < num_localnet_addr && !remote_dns_connect; i++) {
if (!v6) for(i = 0; i < num_localnet_addr && !remote_dns_connect; i++) {
if((localnet_addr[i].in_addr.s_addr & localnet_addr[i].netmask.s_addr)
== (p_addr_in->s_addr & localnet_addr[i].netmask.s_addr)) {
if(!localnet_addr[i].port || localnet_addr[i].port == port) {
@@ -364,11 +387,11 @@ int connect(int sock, const struct sockaddr *addr, unsigned int len) {
if(flags & O_NONBLOCK)
fcntl(sock, F_SETFL, !O_NONBLOCK);
dest_ip.as_int = SOCKADDR(*addr);
memcpy(dest_ip.addr.v6, v6 ? (void*)p_addr_in6 : (void*)p_addr_in, v6?16:4);
ret = connect_proxy_chain(sock,
dest_ip,
SOCKPORT(*addr),
htons(port),
proxychains_pd, proxychains_proxy_count, proxychains_ct, proxychains_max_chain);
fcntl(sock, F_SETFL, flags);
@@ -380,7 +403,6 @@ int connect(int sock, const struct sockaddr *addr, unsigned int len) {
static struct gethostbyname_data ghbndata;
struct hostent *gethostbyname(const char *name) {
INIT();
PDEBUG("gethostbyname: %s\n", name);
if(proxychains_resolver)
@@ -392,72 +414,79 @@ struct hostent *gethostbyname(const char *name) {
}
int getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res) {
int ret = 0;
INIT();
PDEBUG("getaddrinfo: %s %s\n", node ? node : "null", service ? service : "null");
if(proxychains_resolver)
ret = proxy_getaddrinfo(node, service, hints, res);
return proxy_getaddrinfo(node, service, hints, res);
else
ret = true_getaddrinfo(node, service, hints, res);
return ret;
return true_getaddrinfo(node, service, hints, res);
}
void freeaddrinfo(struct addrinfo *res) {
INIT();
PDEBUG("freeaddrinfo %p \n", res);
PDEBUG("freeaddrinfo %p \n", (void *) res);
if(!proxychains_resolver)
true_freeaddrinfo(res);
else
proxy_freeaddrinfo(res);
return;
}
int pc_getnameinfo(const struct sockaddr *sa, socklen_t salen,
char *host, socklen_t hostlen, char *serv,
socklen_t servlen, int flags)
{
char ip_buf[16];
int ret = 0;
INIT();
PFUNC();
if(!proxychains_resolver) {
ret = true_getnameinfo(sa, salen, host, hostlen, serv, servlen, flags);
return true_getnameinfo(sa, salen, host, hostlen, serv, servlen, flags);
} else {
if(salen < sizeof(struct sockaddr_in) || SOCKFAMILY(*sa) != AF_INET)
if(!salen || !(SOCKFAMILY(*sa) == AF_INET || SOCKFAMILY(*sa) == AF_INET6))
return EAI_FAMILY;
int v6 = SOCKFAMILY(*sa) == AF_INET6;
if(salen < (v6?sizeof(struct sockaddr_in6):sizeof(struct sockaddr_in)))
return EAI_FAMILY;
if(hostlen) {
pc_stringfromipv4((unsigned char*) &(SOCKADDR_2(*sa)), ip_buf);
if(snprintf(host, hostlen, "%s", ip_buf) >= hostlen)
unsigned char v4inv6buf[4];
const void *ip = v6 ? (void*)&((struct sockaddr_in6*)sa)->sin6_addr
: (void*)&((struct sockaddr_in*)sa)->sin_addr;
unsigned scopeid = 0;
if(v6) {
if(is_v4inv6(&((struct sockaddr_in6*)sa)->sin6_addr)) {
memcpy(v4inv6buf, &((struct sockaddr_in6*)sa)->sin6_addr.s6_addr32[3], 4);
ip = v4inv6buf;
v6 = 0;
} else
scopeid = ((struct sockaddr_in6 *)sa)->sin6_scope_id;
}
if(!inet_ntop(v6?AF_INET6:AF_INET,ip,host,hostlen))
return EAI_OVERFLOW;
if(scopeid) {
size_t l = strlen(host);
if(snprintf(host+l, hostlen-l, "%%%u", scopeid) >= hostlen-l)
return EAI_OVERFLOW;
}
}
if(servlen) {
if(snprintf(serv, servlen, "%d", ntohs(SOCKPORT(*sa))) >= servlen)
return EAI_OVERFLOW;
}
}
return ret;
return 0;
}
struct hostent *gethostbyaddr(const void *addr, socklen_t len, int type) {
INIT();
PDEBUG("TODO: proper gethostbyaddr hook\n");
static char buf[16];
static char ipv4[4];
static char *list[2];
static char *aliases[1];
static struct hostent he;
INIT();
PDEBUG("TODO: proper gethostbyaddr hook\n");
if(!proxychains_resolver)
return true_gethostbyaddr(addr, len, type);
else {
@@ -479,3 +508,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);
}
+7 -1
View File
@@ -24,7 +24,7 @@
static int usage(char **argv) {
printf("\nUsage:\t%s -q -f config_file program_name [arguments]\n"
"\t-q makes proxychains quiet - this overrides the config setting\n"
"\t-f allows to manually specify a configfile to use\n"
"\t-f allows one to manually specify a configfile to use\n"
"\tfor example : proxychains telnet somehost.com\n" "More help in README file\n\n", argv[0]);
return EXIT_FAILURE;
}
@@ -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;
-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
+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;
}