1
0
mirror of https://github.com/rofl0r/proxychains-ng synced 2025-01-21 15:42:58 +08:00

Compare commits

...

7 Commits

Author SHA1 Message Date
rofl0r
2ab631918d add support for "proxy_dns_old" to use old 3.1 DNS lookup method
some lamer on IRC by the name of annoner/R3M0RS3/penis was complaining
that 3.1 is a lot better than proxychains-ng, because it happens to
work with the browser he's interested in.
since this wasn't the first time this is requested, let's give this
those lamers what they want: lame code!
2020-09-20 22:11:17 +01:00
rofl0r
3e791fd797 make sure allocator thread is only used if proxy_dns is requested 2020-09-20 18:21:40 +01:00
rofl0r
3a5050bec2 initialize allocator thread from get_chain_data if needed
since we caved in to demands that it should be possible to allow
hostnames in the proxy list section, we now got to deal with the
fallout. the code was calling at_get... assuming that the allocator
thread is always used.
2020-09-20 18:18:31 +01:00
rofl0r
3dfda493d8 only start allocator thread if proxy_dns is requested
this should fix problems with programs that do whacky
non-async-signal-safe stuff.
2020-09-20 18:17:51 +01:00
rofl0r
ed8f8444ab allocator_thread: rework message sending structures
simplify code by adding a new at_msg struct that contains both
the message header and the message body.
this allow e.g. atomic writes of the whole message instead of doing
it in 2 steps. unfortunately reads still have to be done in at least
2 steps, since there are no atomicity guarantees[0].
additionally the message header shrunk from 8 to 4 bytes.

[0]: https://stackoverflow.com/questions/14661708/under-what-conditions-are-pipe-reads-atomic
2020-09-20 18:17:51 +01:00
rofl0r
12e5da1b90 get_chain_data: print debug info 2020-09-20 17:02:21 +01:00
rofl0r
121c582d9c debug: fix DUMP_PROXY_CHAIN() hack 2020-09-20 17:00:10 +01:00
9 changed files with 206 additions and 69 deletions

View File

@ -20,6 +20,7 @@
#include "ip_type.h"
#include "mutex.h"
#include "hash.h"
#include "remotedns.h"
/* stuff for our internal translation table */
@ -117,7 +118,7 @@ static ip_type4 ip_from_internal_list(char* name, size_t len) {
internal_ips->list[internal_ips->counter] = new_mem;
internal_ips->list[internal_ips->counter]->hash = hash;
new_mem = dumpstring((char*) name, len + 1);
new_mem = dumpstring((char*) name, len);
if(!new_mem) {
internal_ips->list[internal_ips->counter] = 0;
@ -138,23 +139,12 @@ static ip_type4 ip_from_internal_list(char* name, size_t len) {
/* stuff for communication with the allocator thread */
enum at_msgtype {
ATM_GETIP,
ATM_GETNAME,
ATM_EXIT,
};
enum at_direction {
ATD_SERVER = 0,
ATD_CLIENT,
ATD_MAX,
};
struct at_msghdr {
enum at_msgtype msgtype;
size_t datalen;
};
static pthread_t allocator_thread;
int req_pipefd[2];
int resp_pipefd[2];
@ -198,13 +188,11 @@ again:
}
}
static int sendmessage(enum at_direction dir, struct at_msghdr *hdr, void* data) {
static int sendmessage(enum at_direction dir, struct at_msg *msg) {
static int* destfd[ATD_MAX] = { [ATD_SERVER] = &req_pipefd[1], [ATD_CLIENT] = &resp_pipefd[1] };
int ret = trywrite(*destfd[dir], hdr, sizeof *hdr);
if(ret && hdr->datalen) {
assert(hdr->datalen <= MSG_LEN_MAX);
ret = trywrite(*destfd[dir], data, hdr->datalen);
}
assert(msg->h.datalen <= MSG_LEN_MAX);
int ret = trywrite(*destfd[dir], msg, sizeof (msg->h)+msg->h.datalen);
assert(msg->h.datalen <= MSG_LEN_MAX);
return ret;
}
@ -225,17 +213,19 @@ again:
goto again;
}
}
static int readmsg(int fd, struct at_msg *msg) {
int ret = tryread(fd, msg, sizeof(msg->h));
if(ret != 1) return ret;
return tryread(fd, &msg->m, msg->h.datalen);
}
static int getmessage(enum at_direction dir, struct at_msghdr *hdr, void* data) {
static int getmessage(enum at_direction dir, struct at_msg *msg) {
static int* readfd[ATD_MAX] = { [ATD_SERVER] = &req_pipefd[0], [ATD_CLIENT] = &resp_pipefd[0] };
ssize_t ret;
if((ret = wait_data(*readfd[dir]))) {
if(!tryread(*readfd[dir], hdr, sizeof *hdr))
if(!readmsg(*readfd[dir], msg))
return 0;
assert(hdr->datalen <= MSG_LEN_MAX);
if(hdr->datalen) {
ret = tryread(*readfd[dir], data, hdr->datalen);
}
assert(msg->h.datalen <= MSG_LEN_MAX);
}
return ret;
}
@ -243,26 +233,24 @@ static int getmessage(enum at_direction dir, struct at_msghdr *hdr, void* data)
static void* threadfunc(void* x) {
(void) x;
int ret;
struct at_msghdr msg;
union {
char host[MSG_LEN_MAX];
ip_type4 ip;
} readbuf;
while((ret = getmessage(ATD_SERVER, &msg, &readbuf))) {
switch(msg.msgtype) {
struct at_msg msg;
while((ret = getmessage(ATD_SERVER, &msg))) {
switch(msg.h.msgtype) {
case ATM_GETIP:
/* 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_type4);
msg.m.ip = ip_from_internal_list(msg.m.host, msg.h.datalen);
msg.h.datalen = sizeof(ip_type4);
break;
case ATM_GETNAME: {
char *host = string_from_internal_ip(readbuf.ip);
char *host = string_from_internal_ip(msg.m.ip);
if(host) {
size_t l = strlen(host);
assert(l < MSG_LEN_MAX);
memcpy(readbuf.host, host, l + 1);
msg.datalen = l + 1;
assert(l+1 < MSG_LEN_MAX);
memcpy(msg.m.host, host, l + 1);
msg.h.datalen = l + 1;
} else {
msg.h.datalen = 0;
}
break;
}
@ -271,7 +259,7 @@ static void* threadfunc(void* x) {
default:
abort();
}
ret = sendmessage(ATD_CLIENT, &msg, &readbuf);
ret = sendmessage(ATD_CLIENT, &msg);
}
return 0;
}
@ -282,27 +270,31 @@ 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 };
if(sendmessage(ATD_SERVER, &msg, host) &&
getmessage(ATD_CLIENT, &msg, &readbuf));
struct at_msg msg = {.h.msgtype = ATM_GETIP, .h.datalen = len + 1 };
memcpy(msg.m.host, host, len+1);
if(sendmessage(ATD_SERVER, &msg) &&
getmessage(ATD_CLIENT, &msg)) readbuf = msg.m.ip;
else {
inv:
readbuf = ip_type_invalid.addr.v4;
}
assert(msg.msgtype == ATM_GETIP);
assert(msg.h.msgtype == ATM_GETIP);
MUTEX_UNLOCK(internal_ips_lock);
return readbuf;
}
size_t at_get_host_for_ip(ip_type4 ip, char* readbuf) {
struct at_msghdr msg = {.msgtype = ATM_GETNAME, .datalen = sizeof(ip_type4) };
struct at_msg msg = {.h.msgtype = ATM_GETNAME, .h.datalen = sizeof(ip_type4), .m.ip = ip };
size_t res = 0;
MUTEX_LOCK(internal_ips_lock);
if(sendmessage(ATD_SERVER, &msg, &ip) && getmessage(ATD_CLIENT, &msg, readbuf)) {
if((ptrdiff_t) msg.datalen <= 0) res = 0;
else res = msg.datalen - 1;
if(sendmessage(ATD_SERVER, &msg) && getmessage(ATD_CLIENT, &msg)) {
if((int16_t) msg.h.datalen <= 0) res = 0;
else {
memcpy(readbuf, msg.m.host, msg.h.datalen);
res = msg.h.datalen - 1;
}
}
assert(msg.msgtype == ATM_GETNAME);
assert(msg.h.msgtype == ATM_GETNAME);
MUTEX_UNLOCK(internal_ips_lock);
return res;
}

View File

@ -43,6 +43,7 @@
extern int tcp_read_time_out;
extern int tcp_connect_time_out;
extern int proxychains_quiet_mode;
extern int proxychains_resolver;
extern unsigned int proxychains_proxy_offset;
extern unsigned int remote_dns_subnet;
@ -199,7 +200,7 @@ 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.is_v6 && ip.addr.v4.octet[0] == remote_dns_subnet) {
if(!ip.is_v6 && proxychains_resolver && 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;
@ -524,7 +525,7 @@ static int chain_step(int ns, proxy_data * pfrom, proxy_data * pto) {
PFUNC();
if(!v6 && pto->ip.addr.v4.octet[0] == remote_dns_subnet) {
if(!v6 && proxychains_resolver && 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 {
@ -744,6 +745,86 @@ static void gethostbyname_data_setstring(struct gethostbyname_data* data, char*
}
extern ip_type4 hostsreader_get_numeric_ip_for_name(const char* name);
struct hostent* proxy_gethostbyname_old(const char *name)
{
static struct hostent hostent_space;
static in_addr_t resolved_addr;
static char* resolved_addr_p;
static char addr_name[1024*8];
int pipe_fd[2];
char buff[256];
in_addr_t addr;
pid_t pid;
int status;
size_t l;
struct hostent* hp;
hostent_space.h_addr_list = &resolved_addr_p;
*hostent_space.h_addr_list = (char*)&resolved_addr;
resolved_addr = 0;
gethostname(buff,sizeof(buff));
if(!strcmp(buff,name))
goto got_buff;
memset(buff, 0, sizeof(buff));
// TODO: this works only once, so cache it ...
// later
while ((hp=gethostent()))
if (!strcmp(hp->h_name,name))
return hp;
if(pipe(pipe_fd))
goto err;
pid = fork();
switch(pid) {
case 0: // child
proxychains_write_log("|DNS-request| %s \n", name);
close(pipe_fd[0]);
dup2(pipe_fd[1],1);
close(pipe_fd[1]);
// putenv("LD_PRELOAD=");
execlp("proxyresolv","proxyresolv",name,NULL);
perror("can't exec proxyresolv");
exit(2);
case -1: //error
close(pipe_fd[0]);
close(pipe_fd[1]);
perror("can't fork");
goto err;
default:
close(pipe_fd[1]);
waitpid(pid, &status, 0);
buff[0] = 0;
read(pipe_fd[0],&buff,sizeof(buff));
close(pipe_fd[0]);
got_buff:
l = strlen(buff);
if(l && buff[l-1] == '\n') buff[l-1] = 0;
addr = inet_addr(buff);
if (addr == (in_addr_t) (-1))
goto err_dns;
memcpy(*(hostent_space.h_addr_list),
&addr ,sizeof(struct in_addr));
hostent_space.h_name = addr_name;
hostent_space.h_length = sizeof (in_addr_t);
}
proxychains_write_log("|DNS-response| %s is %s\n",
name, inet_ntoa(*(struct in_addr*)&addr));
return &hostent_space;
err_dns:
proxychains_write_log("|DNS-response|: %s does not exist\n", name);
perror("err_dns");
err:
return NULL;
}
struct hostent *proxy_gethostbyname(const char *name, struct gethostbyname_data* data) {
PFUNC();
char buff[256];
@ -871,7 +952,11 @@ int proxy_getaddrinfo(const char *node, const char *service, const struct addrin
free(space);
return EAI_NONAME;
}
hp = proxy_gethostbyname(node, &ghdata);
if(proxychains_resolver == 2)
hp = proxy_gethostbyname_old(node);
else
hp = proxy_gethostbyname(node, &ghdata);
if(hp)
memcpy(&((struct sockaddr_in *) &space->sockaddr_space)->sin_addr,
*(hp->h_addr_list), sizeof(in_addr_t));

View File

@ -121,6 +121,7 @@ struct gethostbyname_data {
};
struct hostent* proxy_gethostbyname(const char *name, struct gethostbyname_data *data);
struct hostent* proxy_gethostbyname_old(const char *name);
int proxy_getaddrinfo(const char *node, const char *service,
const struct addrinfo *hints, struct addrinfo **res);

View File

@ -5,7 +5,7 @@
# include "debug.h"
#include <arpa/inet.h>
void DUMP_PROXY_CHAIN(proxy_data *pchain, unsigned int count) {
void dump_proxy_chain(proxy_data *pchain, unsigned int count) {
char ip_buf[INET6_ADDRSTRLEN];
for (; count; pchain++, count--) {
if(!inet_ntop(pchain->ip.is_v6?AF_INET6:AF_INET,pchain->ip.addr.v6,ip_buf,sizeof ip_buf)) {

View File

@ -1,15 +1,13 @@
#ifndef DEBUG_H
#define DEBUG_H
#ifdef DEBUG
# include <stdio.h>
#ifdef DEBUG
# 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);
# define DUMP_PROXY_CHAIN(A, B) dump_proxy_chain(A, B)
#else
# define PDEBUG(fmt, args...) do {} while (0)
# define DEBUGDECL(args...)
@ -18,5 +16,9 @@ void DUMP_PROXY_CHAIN(proxy_data *pchain, unsigned int count);
# define PFUNC() do { PDEBUG("pid[%d]:%s\n", getpid(), __FUNCTION__); } while(0)
#include "core.h"
void dump_proxy_chain(proxy_data *pchain, unsigned int count);
#endif

View File

@ -116,19 +116,24 @@ static void setup_hooks(void) {
SETUP_SYM(freeaddrinfo);
SETUP_SYM(gethostbyaddr);
SETUP_SYM(getnameinfo);
SETUP_SYM(close);
#ifdef IS_SOLARIS
SETUP_SYM(__xnet_connect);
#endif
SETUP_SYM(close);
}
static int close_fds[16];
static int close_fds_cnt = 0;
static void rdns_init(void) {
static int init_done = 0;
if(!init_done) at_init();
init_done = 1;
}
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);
@ -139,8 +144,9 @@ static void do_init(void) {
setup_hooks();
while(close_fds_cnt) true_close(close_fds[--close_fds_cnt]);
init_l = 1;
if(proxychains_resolver == 1) rdns_init();
}
static void init_lib_wrapper(const char* caller) {
@ -278,6 +284,8 @@ static void get_chain_data(proxy_data * pd, unsigned int *proxy_count, chain_typ
if(proxychains_got_chain_data)
return;
PFUNC();
//Some defaults
tcp_read_time_out = 4 * 1000;
tcp_connect_time_out = 10 * 1000;
@ -320,8 +328,9 @@ static void get_chain_data(proxy_data * pd, unsigned int *proxy_count, chain_typ
pd[count].port = htons((unsigned short) port_n);
ip_type* host_ip = &pd[count].ip;
if(1 != inet_pton(host_ip->is_v6 ? AF_INET6 : AF_INET, host, host_ip->addr.v6)) {
if(*ct == STRICT_TYPE && proxychains_resolver && count > 0) {
if(*ct == STRICT_TYPE && proxychains_resolver == 1 && count > 0) {
/* we can allow dns hostnames for all but the first proxy in the list if chaintype is strict, as remote lookup can be done */
rdns_init();
ip_type4 internal_ip = at_get_ip_for_host(host, strlen(host));
pd[count].ip.is_v6 = 0;
host_ip->addr.v4 = internal_ip;
@ -422,6 +431,8 @@ inv_host:
proxychains_max_chain = (len ? len : 1);
} else if(strstr(buff, "quiet_mode")) {
proxychains_quiet_mode = 1;
} else if(strstr(buff, "proxy_dns_old")) {
proxychains_resolver = 2;
} else if(strstr(buff, "proxy_dns")) {
proxychains_resolver = 1;
} else if(strstr(buff, "dnat")) {
@ -486,7 +497,7 @@ inv_host:
}
*proxy_count = count;
proxychains_got_chain_data = 1;
PDEBUG("proxy_dns: %s\n", proxychains_resolver ? "ON" : "OFF");
PDEBUG("proxy_dns: %s\n", proxychains_resolver ? (proxychains_resolver == 2 ? "OLD" : "ON") : "OFF");
}
/******* HOOK FUNCTIONS *******/
@ -498,6 +509,8 @@ int close(int fd) {
errno = 0;
return 0;
}
if(proxychains_resolver != 1) return true_close(fd);
/* 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]) {
@ -611,8 +624,10 @@ struct hostent *gethostbyname(const char *name) {
INIT();
PDEBUG("gethostbyname: %s\n", name);
if(proxychains_resolver)
if(proxychains_resolver == 1)
return proxy_gethostbyname(name, &ghbndata);
else if(proxychains_resolver == 2)
return proxy_gethostbyname_old(name);
else
return true_gethostbyname(name);

View File

@ -49,7 +49,15 @@ strict_chain
#quiet_mode
# Proxy DNS requests - no leak for DNS data
proxy_dns
# this uses the proxychains4 style method to do remote dns
proxy_dns
# use the old proxyresolv script to proxy DNS requests
# in proxychains 3.1 style. requires proxyresolv in $PATH
# plus a dynamically linked `dig` binary.
# this is a lot slower than `proxy_dns`, doesn't support .onion URLs,
# but might be more compatible with complex software like webbrowsers.
#proxy_dns_old
# set the class A subnet number to use for the internal remote DNS mapping
# we use the reserved 224.x.x.x range by default,

View File

@ -1,10 +1,8 @@
#!/bin/sh
# This is a legacy script that uses "dig" to do DNS lookups via TCP.
# it is not actively maintained since proxychains no longer depends
# on it. i leave it here as a bonus.
# This is a legacy script that uses "dig" or "drill" to do DNS lookups via TCP.
# DNS server used to resolve names
DNS_SERVER=8.8.8.8
test -z "$DNS_SERVER" && DNS_SERVER=8.8.8.8
if [ $# = 0 ] ; then
@ -14,5 +12,12 @@ if [ $# = 0 ] ; then
fi
export LD_PRELOAD=libproxychains4.so
dig $1 @$DNS_SERVER +tcp | awk '/A.?[0-9]+\.[0-9]+\.[0-9]/{print $5;}'
test -z $LD_PRELOAD && export LD_PRELOAD=libproxychains4.so
if type dig 1>/dev/null 2>&1 ; then
dig $1 @$DNS_SERVER +tcp | awk '/A.?[0-9]+\.[0-9]+\.[0-9]/{print $5;}'
elif type drill 1>/dev/null 2>&1 ; then
drill -t4 $1 @$DNS_SERVER | awk '/A.+[0-9]+\.[0-9]+\.[0-9]/{print $5;}'
else
echo "error: neither dig nor drill found" >&2
fi

29
src/remotedns.h Normal file
View File

@ -0,0 +1,29 @@
#ifndef REMOTEDNS_H
#define REMOTEDNS_H
#include <unistd.h>
#include "ip_type.h"
enum at_msgtype {
ATM_GETIP = 0,
ATM_GETNAME,
ATM_FAIL,
ATM_EXIT,
};
struct at_msghdr {
unsigned char msgtype; /* at_msgtype */
char reserved;
unsigned short datalen;
};
struct at_msg {
struct at_msghdr h;
union {
char host[260];
ip_type4 ip;
} m;
};
#endif