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

Compare commits

...

21 Commits

18 changed files with 273 additions and 208 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.
+7 -6
View File
@@ -16,9 +16,9 @@ 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
@@ -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) \
-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
+17 -2
View File
@@ -1,4 +1,4 @@
ProxyChains-NG ver 4.8 README
ProxyChains-NG ver 4.10 README
=============================
ProxyChains is a UNIX program, that hooks network-related libc functions
@@ -52,6 +52,19 @@ ProxyChains-NG ver 4.8 README
Changelog:
----------
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).
@@ -66,9 +79,11 @@ Version 4.7:
- 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.
+1 -1
View File
@@ -1 +1 @@
4.8
4.10
Vendored
+13 -1
View File
@@ -14,6 +14,10 @@ isbsd() {
uname -s | grep BSD >/dev/null
}
isopenbsd() {
uname -s | grep OpenBSD >/dev/null
}
usage() {
echo "supported arguments"
echo "--prefix=/path default: $prefix"
@@ -22,6 +26,9 @@ usage() {
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 +42,7 @@ spliteq() {
}
fat_binary=
ignore_cve=no
parsearg() {
case "$1" in
--prefix=*) prefix=`spliteq $1`;;
@@ -44,6 +51,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
@@ -83,12 +92,14 @@ fi
echo CC?=$CC>config.mak
[ -z "$CPPFLAGS" ] || echo CPPFLAGS?=$CPPFLAGS>>config.mak
[ -z "$CFLAGS" ] || echo USER_CFLAGS?=$CFLAGS>>config.mak
[ -z "$LDFLAGS" ] || echo USER_LDFLAGS?=$LDFLAGS>>config.mak
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
@@ -103,6 +114,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
+6 -2
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,6 +28,12 @@ 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;
+11 -10
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;
@@ -719,11 +718,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 +729,7 @@ static void gethostbyname_data_setstring(struct gethostbyname_data* data, char*
data->hostent_space.h_name = data->addr_name;
}
extern ip_type hostsreader_get_numeric_ip_for_name(const char* name);
struct hostent *proxy_gethostbyname(const char *name, struct gethostbyname_data* data) {
PFUNC();
char buff[256];
@@ -758,10 +754,8 @@ struct hostent *proxy_gethostbyname(const char *name, struct gethostbyname_data*
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);
ip_type hdb_res = hostsreader_get_numeric_ip_for_name(name);
if(hdb_res.as_int != ip_type_invalid.as_int) {
data->resolved_addr = hdb_res.as_int;
goto retname;
@@ -790,8 +784,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 +856,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;
-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
+121
View File
@@ -0,0 +1,121 @@
#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 = buf;
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_type hostsreader_get_numeric_ip_for_name(const char* name) {
char *hres;
char buf[320];
if((hres = hostsreader_get_ip_for_name(name, buf, sizeof buf))) {
struct in_addr c;
inet_aton(hres, &c);
ip_type res;
memcpy(res.octet, &c.s_addr, 4);
return res;
} else return ip_type_invalid;
}
#ifdef HOSTSREADER_TEST
int main() {
char buf[256];
char * ret = hostsreader_get_ip_for_name("goo", 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;
}
+19 -3
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;
@@ -94,15 +95,12 @@ 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"
const char *proxychains_get_version(void);
static void do_init(void) {
srand(time(NULL));
dumpstring_init(); // global string garbage can
core_initialize();
at_init();
@@ -113,6 +111,7 @@ static void do_init(void) {
proxychains_write_log(LOG_PREFIX "DLL init: proxychains-ng %s\n", proxychains_get_version());
SETUP_SYM(connect);
SETUP_SYM(sendto);
SETUP_SYM(gethostbyname);
SETUP_SYM(getaddrinfo);
SETUP_SYM(freeaddrinfo);
@@ -479,3 +478,20 @@ 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) {
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);
}
+6
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;
-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
+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;
}