mirror of
https://github.com/rofl0r/proxychains-ng
synced 2025-01-21 15:42:58 +08:00
Compare commits
3 Commits
e6c4764660
...
7fe8139496
Author | SHA1 | Date | |
---|---|---|---|
|
7fe8139496 | ||
|
1e00b9ac1e | ||
|
1221c5e93a |
25
Makefile
25
Makefile
@ -13,13 +13,18 @@ includedir = $(prefix)/include
|
||||
libdir = $(prefix)/lib
|
||||
sysconfdir=$(prefix)/etc
|
||||
|
||||
SRCS = $(sort $(wildcard src/*.c))
|
||||
OBJS = $(SRCS:.c=.o)
|
||||
OBJS = src/common.o src/main.o
|
||||
|
||||
DOBJS = src/daemon/hsearch.o \
|
||||
src/daemon/sblist.o src/daemon/sblist_delete.o \
|
||||
src/daemon/daemon.o src/daemon/udpserver.o
|
||||
|
||||
LOBJS = src/nameinfo.o src/version.o \
|
||||
src/core.o src/common.o src/libproxychains.o \
|
||||
src/allocator_thread.o src/ip_type.o \
|
||||
src/allocator_thread.o src/rdns.o \
|
||||
src/hostsreader.o src/hash.o src/debug.o
|
||||
|
||||
|
||||
GENH = src/version.h
|
||||
|
||||
CFLAGS += -Wall -O0 -g -std=c99 -D_GNU_SOURCE -pipe
|
||||
@ -41,7 +46,8 @@ LDSO_PATHNAME = libproxychains4.$(LDSO_SUFFIX)
|
||||
SHARED_LIBS = $(LDSO_PATHNAME)
|
||||
ALL_LIBS = $(SHARED_LIBS)
|
||||
PXCHAINS = proxychains4
|
||||
ALL_TOOLS = $(PXCHAINS)
|
||||
PXCHAINS_D = proxychains4-daemon
|
||||
ALL_TOOLS = $(PXCHAINS) $(PXCHAINS_D)
|
||||
ALL_CONFIGS = src/proxychains.conf
|
||||
|
||||
-include config.mak
|
||||
@ -70,7 +76,7 @@ install-config: $(ALL_CONFIGS:src/%=$(DESTDIR)$(sysconfdir)/%)
|
||||
clean:
|
||||
rm -f $(ALL_LIBS)
|
||||
rm -f $(ALL_TOOLS)
|
||||
rm -f $(OBJS)
|
||||
rm -f $(OBJS) $(LOBJS) $(DOBJS)
|
||||
rm -f $(GENH)
|
||||
|
||||
src/version.h: $(wildcard VERSION .git)
|
||||
@ -83,10 +89,13 @@ src/version.o: src/version.h
|
||||
|
||||
$(LDSO_PATHNAME): $(LOBJS)
|
||||
$(CC) $(LDFLAGS) $(LD_SET_SONAME)$(LDSO_PATHNAME) $(USER_LDFLAGS) \
|
||||
-shared -o $@ $(LOBJS) $(SOCKET_LIBS)
|
||||
-shared -o $@ $^ $(SOCKET_LIBS)
|
||||
|
||||
$(ALL_TOOLS): $(OBJS)
|
||||
$(CC) src/main.o src/common.o $(USER_LDFLAGS) $(LIBDL) -o $(PXCHAINS)
|
||||
$(PXCHAINS): $(OBJS)
|
||||
$(CC) $^ $(USER_LDFLAGS) $(LIBDL) -o $@
|
||||
|
||||
$(PXCHAINS_D): $(DOBJS)
|
||||
$(CC) $^ $(USER_LDFLAGS) -o $@
|
||||
|
||||
|
||||
.PHONY: all clean install install-config install-libs install-tools
|
||||
|
3
configure
vendored
3
configure
vendored
@ -159,6 +159,9 @@ check_compile 'whether we have GNU-style getservbyname_r()' "-DHAVE_GNU_GETSERVB
|
||||
check_compile 'whether we have pipe2() and O_CLOEXEC' "-DHAVE_PIPE2" \
|
||||
'#define _GNU_SOURCE\n#include <fcntl.h>\n#include <unistd.h>\nint main() {\nint pipefd[2];\npipe2(pipefd, O_CLOEXEC);\nreturn 0;}'
|
||||
|
||||
check_compile 'whether we have SOCK_CLOEXEC' "-DHAVE_SOCK_CLOEXEC" \
|
||||
'#define _GNU_SOURCE\n#include <sys/socket.h>\nint main() {\nreturn socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC, 0);}'
|
||||
|
||||
check_define __APPLE__ && {
|
||||
mac_detected=true
|
||||
check_define __x86_64__ && mac_64=true
|
||||
|
@ -67,7 +67,7 @@ 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.addr.v4;
|
||||
return IPT4_INVALID;
|
||||
ret.octet[0] = remote_dns_subnet & 0xFF;
|
||||
ret.octet[1] = (index & 0xFF0000) >> 16;
|
||||
ret.octet[2] = (index & 0xFF00) >> 8;
|
||||
@ -105,7 +105,7 @@ static ip_type4 ip_from_internal_list(char* name, size_t len) {
|
||||
}
|
||||
|
||||
res = make_internal_ip(internal_ips->counter);
|
||||
if(res.as_int == ip_type_invalid.addr.v4.as_int)
|
||||
if(res.as_int == IPT4_INVALID.as_int)
|
||||
goto err_plus_unlock;
|
||||
|
||||
string_hash_tuple tmp = { 0 };
|
||||
@ -134,7 +134,7 @@ static ip_type4 ip_from_internal_list(char* name, size_t len) {
|
||||
err_plus_unlock:
|
||||
|
||||
PDEBUG("return err\n");
|
||||
return ip_type_invalid.addr.v4;
|
||||
return IPT4_INVALID;
|
||||
}
|
||||
|
||||
/* stuff for communication with the allocator thread */
|
||||
@ -276,7 +276,7 @@ ip_type4 at_get_ip_for_host(char* host, size_t len) {
|
||||
getmessage(ATD_CLIENT, &msg)) readbuf = msg.m.ip;
|
||||
else {
|
||||
inv:
|
||||
readbuf = ip_type_invalid.addr.v4;
|
||||
readbuf = IPT4_INVALID;
|
||||
}
|
||||
assert(msg.h.msgtype == ATM_GETIP);
|
||||
MUTEX_UNLOCK(internal_ips_lock);
|
||||
|
@ -4,8 +4,6 @@
|
||||
#include <unistd.h>
|
||||
#include "ip_type.h"
|
||||
|
||||
#define MSG_LEN_MAX 256
|
||||
|
||||
extern int req_pipefd[2];
|
||||
extern int resp_pipefd[2];
|
||||
|
||||
|
21
src/core.c
21
src/core.c
@ -37,13 +37,12 @@
|
||||
|
||||
#include "core.h"
|
||||
#include "common.h"
|
||||
#include "allocator_thread.h"
|
||||
#include "rdns.h"
|
||||
#include "mutex.h"
|
||||
|
||||
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;
|
||||
|
||||
@ -200,8 +199,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.is_v6 && proxychains_resolver && ip.addr.v4.octet[0] == remote_dns_subnet) {
|
||||
dns_len = at_get_host_for_ip(ip.addr.v4, hostnamebuf);
|
||||
if(!ip.is_v6 && proxychains_resolver >= DNSLF_RDNS_START && ip.addr.v4.octet[0] == remote_dns_subnet) {
|
||||
dns_len = rdns_get_host_for_ip(ip.addr.v4, hostnamebuf);
|
||||
if(!dns_len) goto err;
|
||||
else dns_name = hostnamebuf;
|
||||
}
|
||||
@ -525,8 +524,8 @@ static int chain_step(int ns, proxy_data * pfrom, proxy_data * pto) {
|
||||
|
||||
PFUNC();
|
||||
|
||||
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;
|
||||
if(!v6 && proxychains_resolver >= DNSLF_RDNS_START && pto->ip.addr.v4.octet[0] == remote_dns_subnet) {
|
||||
if(!rdns_get_host_for_ip(pto->ip.addr.v4, hostname_buf)) goto usenumericip;
|
||||
else hostname = hostname_buf;
|
||||
} else {
|
||||
usenumericip:
|
||||
@ -854,19 +853,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.addr.v4.as_int);
|
||||
data->resolved_addr = (in_addr_t) (IPT4_LOCALHOST.as_int);
|
||||
goto retname;
|
||||
}
|
||||
|
||||
// this iterates over the "known hosts" db, usually /etc/hosts
|
||||
ip_type4 hdb_res = hostsreader_get_numeric_ip_for_name(name);
|
||||
if(hdb_res.as_int != ip_type_invalid.addr.v4.as_int) {
|
||||
if(hdb_res.as_int != IPT4_INVALID.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.addr.v4.as_int) return NULL;
|
||||
data->resolved_addr = rdns_get_ip_for_host((char*) name, strlen(name)).as_int;
|
||||
if(data->resolved_addr == (in_addr_t) IPT4_INVALID.as_int) return NULL;
|
||||
|
||||
retname:
|
||||
|
||||
@ -961,7 +960,7 @@ int proxy_getaddrinfo(const char *node, const char *service, const struct addrin
|
||||
free(space);
|
||||
return EAI_NONAME;
|
||||
}
|
||||
if(proxychains_resolver == 2)
|
||||
if(proxychains_resolver == DNSLF_FORKEXEC)
|
||||
hp = proxy_gethostbyname_old(node);
|
||||
else
|
||||
hp = proxy_gethostbyname(node, &ghdata);
|
||||
|
231
src/daemon/daemon.c
Normal file
231
src/daemon/daemon.c
Normal file
@ -0,0 +1,231 @@
|
||||
/*
|
||||
proxychains-ng DNS daemon
|
||||
|
||||
Copyright (C) 2020 rofl0r.
|
||||
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <unistd.h>
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
#include <sys/select.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include "udpserver.h"
|
||||
#include "sblist.h"
|
||||
#include "hsearch.h"
|
||||
#include "../remotedns.h"
|
||||
#include "../ip_type.h"
|
||||
|
||||
#ifndef MAX
|
||||
#define MAX(x, y) ((x) > (y) ? (x) : (y))
|
||||
#endif
|
||||
|
||||
static struct htab *ip_lookup_table;
|
||||
static sblist *hostnames;
|
||||
static unsigned remote_subnet;
|
||||
static const struct server* server;
|
||||
|
||||
#ifndef CONFIG_LOG
|
||||
#define CONFIG_LOG 1
|
||||
#endif
|
||||
#if CONFIG_LOG
|
||||
/* we log to stderr because it's not using line buffering, i.e. malloc which would need
|
||||
locking when called from different threads. for the same reason we use dprintf,
|
||||
which writes directly to an fd. */
|
||||
#define dolog(...) dprintf(2, __VA_ARGS__)
|
||||
#else
|
||||
static void dolog(const char* fmt, ...) { }
|
||||
#endif
|
||||
|
||||
static char* my_inet_ntoa(unsigned char *ip_buf_4_bytes, char *outbuf_16_bytes) {
|
||||
unsigned char *p;
|
||||
char *o = outbuf_16_bytes;
|
||||
unsigned char n;
|
||||
for(p = ip_buf_4_bytes; p < ip_buf_4_bytes + 4; p++) {
|
||||
n = *p;
|
||||
if(*p >= 100) {
|
||||
if(*p >= 200)
|
||||
*(o++) = '2';
|
||||
else
|
||||
*(o++) = '1';
|
||||
n %= 100;
|
||||
}
|
||||
if(*p >= 10) {
|
||||
*(o++) = (n / 10) + '0';
|
||||
n %= 10;
|
||||
}
|
||||
*(o++) = n + '0';
|
||||
*(o++) = '.';
|
||||
}
|
||||
o[-1] = 0;
|
||||
return outbuf_16_bytes;
|
||||
}
|
||||
|
||||
|
||||
/* buf needs to be long enough for an ipv6 addr, i.e. INET6_ADDRSTRLEN + 1 */
|
||||
static char* ipstr(union sockaddr_union *su, char* buf) {
|
||||
int af = SOCKADDR_UNION_AF(su);
|
||||
void *ipdata = SOCKADDR_UNION_ADDRESS(su);
|
||||
inet_ntop(af, ipdata, buf, INET6_ADDRSTRLEN+1);
|
||||
char portbuf[7];
|
||||
snprintf(portbuf, sizeof portbuf, ":%u", (unsigned) ntohs(SOCKADDR_UNION_PORT(su)));
|
||||
strcat(buf, portbuf);
|
||||
return buf;
|
||||
}
|
||||
|
||||
static int usage(char *a0) {
|
||||
dprintf(2,
|
||||
"Proxychains-NG remote dns daemon\n"
|
||||
"--------------------------------\n"
|
||||
"usage: %s -i listenip -p port -r remotesubnet\n"
|
||||
"all arguments are optional.\n"
|
||||
"by default listenip is 127.0.0.1, port 1053 and remotesubnet 224.\n\n", a0
|
||||
);
|
||||
return 1;
|
||||
}
|
||||
|
||||
unsigned index_from_ip(ip_type4 internalip) {
|
||||
ip_type4 tmp = internalip;
|
||||
uint32_t ret;
|
||||
ret = tmp.octet[3] + (tmp.octet[2] << 8) + (tmp.octet[1] << 16);
|
||||
ret -= 1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
char *host_from_ip(ip_type4 internalip) {
|
||||
char *res = NULL;
|
||||
unsigned index = index_from_ip(internalip);
|
||||
if(index < sblist_getsize(hostnames)) {
|
||||
char **tmp = sblist_get(hostnames, index);
|
||||
if(tmp && *tmp) res = *tmp;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
ip_type4 get_ip_from_index(unsigned index) {
|
||||
ip_type4 ret;
|
||||
index++; // so we can start at .0.0.1
|
||||
if(index > 0xFFFFFF)
|
||||
return IPT4_INVALID;
|
||||
ret.octet[0] = remote_subnet & 0xFF;
|
||||
ret.octet[1] = (index & 0xFF0000) >> 16;
|
||||
ret.octet[2] = (index & 0xFF00) >> 8;
|
||||
ret.octet[3] = index & 0xFF;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ip_type4 get_ip(char* hn) {
|
||||
htab_value *v = htab_find(ip_lookup_table, hn);
|
||||
if(v) return get_ip_from_index(v->n);
|
||||
char *n = strdup(hn);
|
||||
if(!n) return IPT4_INVALID;
|
||||
if(!sblist_add(hostnames, &n)) {
|
||||
o_out:;
|
||||
free(n);
|
||||
return IPT4_INVALID;
|
||||
}
|
||||
if(!htab_insert(ip_lookup_table, n, HTV_N(sblist_getsize(hostnames)-1))) {
|
||||
sblist_delete(hostnames, sblist_getsize(hostnames)-1);
|
||||
goto o_out;
|
||||
}
|
||||
return get_ip_from_index(sblist_getsize(hostnames)-1);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
int ch;
|
||||
const char *listenip = "127.0.0.1";
|
||||
unsigned port = 1053;
|
||||
remote_subnet = 224;
|
||||
while((ch = getopt(argc, argv, ":r:i:p:")) != -1) {
|
||||
switch(ch) {
|
||||
case 'r':
|
||||
remote_subnet = atoi(optarg);
|
||||
break;
|
||||
case 'i':
|
||||
listenip = optarg;
|
||||
break;
|
||||
case 'p':
|
||||
port = atoi(optarg);
|
||||
break;
|
||||
case ':':
|
||||
dprintf(2, "error: option -%c requires an operand\n", optopt);
|
||||
/* fall through */
|
||||
case '?':
|
||||
return usage(argv[0]);
|
||||
}
|
||||
}
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
struct server s;
|
||||
if(server_setup(&s, listenip, port)) {
|
||||
perror("server_setup");
|
||||
return 1;
|
||||
}
|
||||
server = &s;
|
||||
|
||||
ip_lookup_table = htab_create(64);
|
||||
hostnames = sblist_new(sizeof(char*), 64);
|
||||
|
||||
while(1) {
|
||||
struct client c;
|
||||
char ipstr_buf[INET6_ADDRSTRLEN+6+1];
|
||||
char ip4str_buf[16];
|
||||
struct at_msg msg, out;
|
||||
size_t msgl = sizeof(msg);
|
||||
int failed = 0;
|
||||
|
||||
#define FAIL() do { failed=1; goto sendresp; } while(0)
|
||||
|
||||
if(server_waitclient(&s, &c, &msg, &msgl)) continue;
|
||||
msg.h.datalen = ntohs(msg.h.datalen);
|
||||
if(msgl != sizeof(msg.h)+msg.h.datalen) {
|
||||
dolog("%s: invalid datalen\n", ipstr(&c.addr, ipstr_buf));
|
||||
FAIL();
|
||||
}
|
||||
|
||||
out.h.msgtype = msg.h.msgtype;
|
||||
if(msg.h.msgtype == ATM_GETIP) {
|
||||
if(!memchr(msg.m.host, 0, msg.h.datalen)) {
|
||||
dolog("%s: nul terminator missing\n", ipstr(&c.addr, ipstr_buf));
|
||||
FAIL();
|
||||
}
|
||||
out.h.datalen = sizeof(ip_type4);
|
||||
out.m.ip = get_ip(msg.m.host);
|
||||
failed = !memcmp(&out.m.ip, &IPT4_INVALID, 4);
|
||||
dolog("%s requested ip for %s (%s)\n", ipstr(&c.addr, ipstr_buf),
|
||||
msg.m.host, failed?"FAIL":my_inet_ntoa((void*)&out.m.ip, ip4str_buf));
|
||||
if(failed) FAIL();
|
||||
} else if (msg.h.msgtype == ATM_GETNAME) {
|
||||
if(msg.h.datalen != 4) {
|
||||
dolog("%s: invalid len for getname request\n", ipstr(&c.addr, ipstr_buf));
|
||||
FAIL();
|
||||
}
|
||||
char *hn = host_from_ip(msg.m.ip);
|
||||
if(hn) {
|
||||
size_t l = strlen(hn);
|
||||
memcpy(out.m.host, hn, l+1);
|
||||
out.h.datalen = l+1;
|
||||
}
|
||||
dolog("%s requested name for %s (%s)\n", ipstr(&c.addr, ipstr_buf),
|
||||
my_inet_ntoa((void*) &msg.m.ip, ip4str_buf), hn?hn:"FAIL");
|
||||
if(!hn) FAIL();
|
||||
} else {
|
||||
dolog("%s: unknown request %u\n", ipstr(&c.addr, ipstr_buf),
|
||||
(unsigned) msg.h.msgtype);
|
||||
}
|
||||
sendresp:;
|
||||
if(failed) {
|
||||
out.h.msgtype = ATM_FAIL;
|
||||
out.h.datalen = 0;
|
||||
}
|
||||
unsigned short dlen = out.h.datalen;
|
||||
out.h.datalen = htons(dlen);
|
||||
sendto(server->fd, &out, sizeof(out.h)+dlen, 0, (void*) &c.addr, SOCKADDR_UNION_LENGTH(&c.addr));
|
||||
}
|
||||
}
|
188
src/daemon/hsearch.c
Normal file
188
src/daemon/hsearch.c
Normal file
@ -0,0 +1,188 @@
|
||||
/*
|
||||
musl license, hsearch.c originally written by Szabolcs Nagy
|
||||
|
||||
Copyright © 2005-2020 Rich Felker, et al.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "hsearch.h"
|
||||
|
||||
/*
|
||||
open addressing hash table with 2^n table size
|
||||
quadratic probing is used in case of hash collision
|
||||
tab indices and hash are size_t
|
||||
after resize fails with ENOMEM the state of tab is still usable
|
||||
*/
|
||||
|
||||
typedef struct htab_entry {
|
||||
char *key;
|
||||
htab_value data;
|
||||
} htab_entry;
|
||||
|
||||
struct elem {
|
||||
htab_entry item;
|
||||
size_t hash;
|
||||
};
|
||||
|
||||
struct htab {
|
||||
struct elem *elems;
|
||||
size_t mask;
|
||||
size_t used;
|
||||
};
|
||||
|
||||
#define MINSIZE 8
|
||||
#define MAXSIZE ((size_t)-1/2 + 1)
|
||||
|
||||
static size_t keyhash(char *k)
|
||||
{
|
||||
unsigned char *p = (void *)k;
|
||||
size_t h = 0;
|
||||
|
||||
while (*p)
|
||||
h = 31*h + *p++;
|
||||
return h;
|
||||
}
|
||||
|
||||
static int resize(struct htab *htab, size_t nel)
|
||||
{
|
||||
size_t newsize;
|
||||
size_t i, j;
|
||||
struct elem *e, *newe;
|
||||
struct elem *oldtab = htab->elems;
|
||||
struct elem *oldend = htab->elems + htab->mask + 1;
|
||||
|
||||
if (nel > MAXSIZE)
|
||||
nel = MAXSIZE;
|
||||
for (newsize = MINSIZE; newsize < nel; newsize *= 2);
|
||||
htab->elems = calloc(newsize, sizeof *htab->elems);
|
||||
if (!htab->elems) {
|
||||
htab->elems = oldtab;
|
||||
return 0;
|
||||
}
|
||||
htab->mask = newsize - 1;
|
||||
if (!oldtab)
|
||||
return 1;
|
||||
for (e = oldtab; e < oldend; e++)
|
||||
if (e->item.key) {
|
||||
for (i=e->hash,j=1; ; i+=j++) {
|
||||
newe = htab->elems + (i & htab->mask);
|
||||
if (!newe->item.key)
|
||||
break;
|
||||
}
|
||||
*newe = *e;
|
||||
}
|
||||
free(oldtab);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct elem *lookup(struct htab *htab, char *key, size_t hash)
|
||||
{
|
||||
size_t i, j;
|
||||
struct elem *e;
|
||||
|
||||
for (i=hash,j=1; ; i+=j++) {
|
||||
e = htab->elems + (i & htab->mask);
|
||||
if (!e->item.key ||
|
||||
(e->hash==hash && strcmp(e->item.key, key)==0))
|
||||
break;
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
struct htab *htab_create(size_t nel)
|
||||
{
|
||||
struct htab *r = calloc(1, sizeof *r);
|
||||
if(r && !resize(r, nel)) {
|
||||
free(r);
|
||||
r = 0;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
void htab_destroy(struct htab *htab)
|
||||
{
|
||||
free(htab->elems);
|
||||
free(htab);
|
||||
}
|
||||
|
||||
static htab_entry *htab_find_item(struct htab *htab, char* key)
|
||||
{
|
||||
size_t hash = keyhash(key);
|
||||
struct elem *e = lookup(htab, key, hash);
|
||||
|
||||
if (e->item.key) {
|
||||
return &e->item;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
htab_value* htab_find(struct htab *htab, char* key)
|
||||
{
|
||||
htab_entry *i = htab_find_item(htab, key);
|
||||
if(i) return &i->data;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int htab_delete(struct htab *htab, char* key)
|
||||
{
|
||||
htab_entry *i = htab_find_item(htab, key);
|
||||
if(!i) return 0;
|
||||
i->key = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int htab_insert(struct htab *htab, char* key, htab_value value)
|
||||
{
|
||||
size_t hash = keyhash(key);
|
||||
struct elem *e = lookup(htab, key, hash);
|
||||
if(e->item.key) {
|
||||
/* it's not allowed to overwrite existing data */
|
||||
return 0;
|
||||
}
|
||||
|
||||
e->item.key = key;
|
||||
e->item.data = value;
|
||||
e->hash = hash;
|
||||
if (++htab->used > htab->mask - htab->mask/4) {
|
||||
if (!resize(htab, 2*htab->used)) {
|
||||
htab->used--;
|
||||
e->item.key = 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
size_t htab_next(struct htab *htab, size_t iterator, char** key, htab_value **v)
|
||||
{
|
||||
size_t i;
|
||||
for(i=iterator;i<htab->mask+1;++i) {
|
||||
struct elem *e = htab->elems + i;
|
||||
if(e->item.key) {
|
||||
*key = e->item.key;
|
||||
*v = &e->item.data;
|
||||
return i+1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
21
src/daemon/hsearch.h
Normal file
21
src/daemon/hsearch.h
Normal file
@ -0,0 +1,21 @@
|
||||
#ifndef HSEARCH_H
|
||||
#define HSEARCH_H
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef union htab_value {
|
||||
void *p;
|
||||
size_t n;
|
||||
} htab_value;
|
||||
|
||||
#define HTV_N(N) (htab_value) {.n = N}
|
||||
#define HTV_P(P) (htab_value) {.p = P}
|
||||
|
||||
struct htab * htab_create(size_t);
|
||||
void htab_destroy(struct htab *);
|
||||
htab_value* htab_find(struct htab *, char* key);
|
||||
int htab_insert(struct htab *, char*, htab_value);
|
||||
int htab_delete(struct htab *htab, char* key);
|
||||
size_t htab_next(struct htab *, size_t iterator, char** key, htab_value **v);
|
||||
|
||||
#endif
|
73
src/daemon/sblist.c
Normal file
73
src/daemon/sblist.c
Normal file
@ -0,0 +1,73 @@
|
||||
#undef _POSIX_C_SOURCE
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
#include "sblist.h"
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#define MY_PAGE_SIZE 4096
|
||||
|
||||
sblist* sblist_new(size_t itemsize, size_t blockitems) {
|
||||
sblist* ret = (sblist*) malloc(sizeof(sblist));
|
||||
sblist_init(ret, itemsize, blockitems);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void sblist_clear(sblist* l) {
|
||||
l->items = NULL;
|
||||
l->capa = 0;
|
||||
l->count = 0;
|
||||
}
|
||||
|
||||
void sblist_init(sblist* l, size_t itemsize, size_t blockitems) {
|
||||
if(l) {
|
||||
l->blockitems = blockitems ? blockitems : MY_PAGE_SIZE / itemsize;
|
||||
l->itemsize = itemsize;
|
||||
sblist_clear(l);
|
||||
}
|
||||
}
|
||||
|
||||
void sblist_free_items(sblist* l) {
|
||||
if(l) {
|
||||
if(l->items) free(l->items);
|
||||
sblist_clear(l);
|
||||
}
|
||||
}
|
||||
|
||||
void sblist_free(sblist* l) {
|
||||
if(l) {
|
||||
sblist_free_items(l);
|
||||
free(l);
|
||||
}
|
||||
}
|
||||
|
||||
char* sblist_item_from_index(sblist* l, size_t idx) {
|
||||
return l->items + (idx * l->itemsize);
|
||||
}
|
||||
|
||||
void* sblist_get(sblist* l, size_t item) {
|
||||
if(item < l->count) return (void*) sblist_item_from_index(l, item);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int sblist_set(sblist* l, void* item, size_t pos) {
|
||||
if(pos >= l->count) return 0;
|
||||
memcpy(sblist_item_from_index(l, pos), item, l->itemsize);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int sblist_grow_if_needed(sblist* l) {
|
||||
char* temp;
|
||||
if(l->count == l->capa) {
|
||||
temp = realloc(l->items, (l->capa + l->blockitems) * l->itemsize);
|
||||
if(!temp) return 0;
|
||||
l->capa += l->blockitems;
|
||||
l->items = temp;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int sblist_add(sblist* l, void* item) {
|
||||
if(!sblist_grow_if_needed(l)) return 0;
|
||||
l->count++;
|
||||
return sblist_set(l, item, l->count - 1);
|
||||
}
|
92
src/daemon/sblist.h
Normal file
92
src/daemon/sblist.h
Normal file
@ -0,0 +1,92 @@
|
||||
#ifndef SBLIST_H
|
||||
#define SBLIST_H
|
||||
|
||||
/* this file is part of libulz, as of commit 8ab361a27743aaf025323ee43b8b8876dc054fdd
|
||||
modified for direct inclusion in microsocks. */
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
/*
|
||||
* simple buffer list.
|
||||
*
|
||||
* this thing here is basically a generic dynamic array
|
||||
* will realloc after every blockitems inserts
|
||||
* can store items of any size.
|
||||
*
|
||||
* so think of it as a by-value list, as opposed to a typical by-ref list.
|
||||
* you typically use it by having some struct on the stack, and pass a pointer
|
||||
* to sblist_add, which will copy the contents into its internal memory.
|
||||
*
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
size_t itemsize;
|
||||
size_t blockitems;
|
||||
size_t count;
|
||||
size_t capa;
|
||||
char* items;
|
||||
} sblist;
|
||||
|
||||
#define sblist_getsize(X) ((X)->count)
|
||||
#define sblist_get_count(X) ((X)->count)
|
||||
#define sblist_empty(X) ((X)->count == 0)
|
||||
|
||||
// for dynamic style
|
||||
sblist* sblist_new(size_t itemsize, size_t blockitems);
|
||||
void sblist_free(sblist* l);
|
||||
|
||||
//for static style
|
||||
void sblist_init(sblist* l, size_t itemsize, size_t blockitems);
|
||||
void sblist_free_items(sblist* l);
|
||||
|
||||
// accessors
|
||||
void* sblist_get(sblist* l, size_t item);
|
||||
// returns 1 on success, 0 on OOM
|
||||
int sblist_add(sblist* l, void* item);
|
||||
int sblist_set(sblist* l, void* item, size_t pos);
|
||||
void sblist_delete(sblist* l, size_t item);
|
||||
char* sblist_item_from_index(sblist* l, size_t idx);
|
||||
int sblist_grow_if_needed(sblist* l);
|
||||
int sblist_insert(sblist* l, void* item, size_t pos);
|
||||
/* same as sblist_add, but returns list index of new item, or -1 */
|
||||
size_t sblist_addi(sblist* l, void* item);
|
||||
void sblist_sort(sblist *l, int (*compar)(const void *, const void *));
|
||||
/* insert element into presorted list, returns listindex of new entry or -1*/
|
||||
size_t sblist_insert_sorted(sblist* l, void* o, int (*compar)(const void *, const void *));
|
||||
|
||||
#ifndef __COUNTER__
|
||||
#define __COUNTER__ __LINE__
|
||||
#endif
|
||||
|
||||
#define __sblist_concat_impl( x, y ) x##y
|
||||
#define __sblist_macro_concat( x, y ) __sblist_concat_impl( x, y )
|
||||
#define __sblist_iterator_name __sblist_macro_concat(sblist_iterator, __COUNTER__)
|
||||
|
||||
// use with custom iterator variable
|
||||
#define sblist_iter_counter(LIST, ITER, PTR) \
|
||||
for(size_t ITER = 0; (PTR = sblist_get(LIST, ITER)), ITER < sblist_getsize(LIST); ITER++)
|
||||
|
||||
// use with custom iterator variable, which is predeclared
|
||||
#define sblist_iter_counter2(LIST, ITER, PTR) \
|
||||
for(ITER = 0; (PTR = sblist_get(LIST, ITER)), ITER < sblist_getsize(LIST); ITER++)
|
||||
|
||||
// use with custom iterator variable, which is predeclared and signed
|
||||
// useful for a loop which can delete items from the list, and then decrease the iterator var.
|
||||
#define sblist_iter_counter2s(LIST, ITER, PTR) \
|
||||
for(ITER = 0; (PTR = sblist_get(LIST, ITER)), ITER < (ssize_t) sblist_getsize(LIST); ITER++)
|
||||
|
||||
|
||||
// uses "magic" iterator variable
|
||||
#define sblist_iter(LIST, PTR) sblist_iter_counter(LIST, __sblist_iterator_name, PTR)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#pragma RcB2 DEP "sblist.c" "sblist_delete.c"
|
||||
|
||||
#endif
|
9
src/daemon/sblist_delete.c
Normal file
9
src/daemon/sblist_delete.c
Normal file
@ -0,0 +1,9 @@
|
||||
#include "sblist.h"
|
||||
#include <string.h>
|
||||
|
||||
void sblist_delete(sblist* l, size_t item) {
|
||||
if (l->count && item < l->count) {
|
||||
memmove(sblist_item_from_index(l, item), sblist_item_from_index(l, item + 1), (sblist_getsize(l) - (item + 1)) * l->itemsize);
|
||||
l->count--;
|
||||
}
|
||||
}
|
41
src/daemon/udpclient.c
Normal file
41
src/daemon/udpclient.c
Normal file
@ -0,0 +1,41 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include "../remotedns.h"
|
||||
#include "../ip_type.h"
|
||||
|
||||
int main() {
|
||||
int fd;
|
||||
int port = 1053;
|
||||
char srvn[] = "127.0.0.1";
|
||||
struct sockaddr_in srva = {.sin_family = AF_INET, .sin_port = htons(port)};
|
||||
inet_pton(AF_INET, srvn, &srva.sin_addr);
|
||||
fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
char namebuf[260];
|
||||
while(fgets(namebuf, sizeof namebuf, stdin)) {
|
||||
size_t l = strlen(namebuf);
|
||||
if(namebuf[l-1] == '\n') {
|
||||
l--;
|
||||
namebuf[l] = 0;
|
||||
}
|
||||
struct at_msg msg = {0};
|
||||
unsigned msglen;
|
||||
if(isdigit(namebuf[0])) {
|
||||
msglen = 4;
|
||||
msg.h.msgtype = ATM_GETNAME;
|
||||
inet_aton(namebuf, (void*) &msg.m.ip);
|
||||
} else {
|
||||
msglen = l+1;
|
||||
msg.h.msgtype = ATM_GETIP;
|
||||
memcpy(msg.m.host, namebuf, msglen);
|
||||
}
|
||||
msg.h.datalen = htons(msglen);
|
||||
sendto(fd, &msg, sizeof(msg.h)+msglen, 0, (void*)&srva, sizeof(srva));
|
||||
char rcvbuf[512];
|
||||
recvfrom(fd, rcvbuf, sizeof rcvbuf, 0, (void*)0, (void*)0);
|
||||
}
|
||||
}
|
65
src/daemon/udpserver.c
Normal file
65
src/daemon/udpserver.c
Normal file
@ -0,0 +1,65 @@
|
||||
#include "udpserver.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int resolve(const char *host, unsigned short port, struct addrinfo** addr) {
|
||||
struct addrinfo hints = {
|
||||
.ai_family = AF_UNSPEC,
|
||||
.ai_socktype = SOCK_STREAM,
|
||||
.ai_flags = AI_PASSIVE,
|
||||
};
|
||||
char port_buf[8];
|
||||
snprintf(port_buf, sizeof port_buf, "%u", port);
|
||||
return getaddrinfo(host, port_buf, &hints, addr);
|
||||
}
|
||||
|
||||
int resolve_sa(const char *host, unsigned short port, union sockaddr_union *res) {
|
||||
struct addrinfo *ainfo = 0;
|
||||
int ret;
|
||||
SOCKADDR_UNION_AF(res) = AF_UNSPEC;
|
||||
if((ret = resolve(host, port, &ainfo))) return ret;
|
||||
memcpy(res, ainfo->ai_addr, ainfo->ai_addrlen);
|
||||
freeaddrinfo(ainfo);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bindtoip(int fd, union sockaddr_union *bindaddr) {
|
||||
socklen_t sz = SOCKADDR_UNION_LENGTH(bindaddr);
|
||||
if(sz)
|
||||
return bind(fd, (struct sockaddr*) bindaddr, sz);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int server_waitclient(struct server *server, struct client* client, void* buf, size_t *buflen) {
|
||||
socklen_t clen = sizeof client->addr;
|
||||
ssize_t ret = recvfrom(server->fd, buf, *buflen, 0, (void*)&client->addr, &clen);
|
||||
if(ret >= 0) {
|
||||
*buflen = ret;
|
||||
return 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int server_setup(struct server *server, const char* listenip, unsigned short port) {
|
||||
struct addrinfo *ainfo = 0;
|
||||
if(resolve(listenip, port, &ainfo)) return -1;
|
||||
struct addrinfo* p;
|
||||
int listenfd = -1;
|
||||
for(p = ainfo; p; p = p->ai_next) {
|
||||
if((listenfd = socket(p->ai_family, SOCK_DGRAM, 0)) < 0)
|
||||
continue;
|
||||
int yes = 1;
|
||||
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
|
||||
if(bind(listenfd, p->ai_addr, p->ai_addrlen) < 0) {
|
||||
close(listenfd);
|
||||
listenfd = -1;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
freeaddrinfo(ainfo);
|
||||
if(listenfd < 0) return -2;
|
||||
server->fd = listenfd;
|
||||
return 0;
|
||||
}
|
48
src/daemon/udpserver.h
Normal file
48
src/daemon/udpserver.h
Normal file
@ -0,0 +1,48 @@
|
||||
#ifndef SERVER_H
|
||||
#define SERVER_H
|
||||
|
||||
#undef _POSIX_C_SOURCE
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#pragma RcB2 DEP "udpserver.c"
|
||||
|
||||
union sockaddr_union {
|
||||
struct sockaddr_in v4;
|
||||
struct sockaddr_in6 v6;
|
||||
};
|
||||
|
||||
#define SOCKADDR_UNION_AF(PTR) (PTR)->v4.sin_family
|
||||
|
||||
#define SOCKADDR_UNION_LENGTH(PTR) ( \
|
||||
( SOCKADDR_UNION_AF(PTR) == AF_INET ) ? sizeof((PTR)->v4) : ( \
|
||||
( SOCKADDR_UNION_AF(PTR) == AF_INET6 ) ? sizeof((PTR)->v6) : 0 ) )
|
||||
|
||||
#define SOCKADDR_UNION_ADDRESS(PTR) ( \
|
||||
( SOCKADDR_UNION_AF(PTR) == AF_INET ) ? (void*) &(PTR)->v4.sin_addr : ( \
|
||||
( SOCKADDR_UNION_AF(PTR) == AF_INET6 ) ? (void*) &(PTR)->v6.sin6_addr : (void*) 0 ) )
|
||||
|
||||
#define SOCKADDR_UNION_PORT(PTR) ( \
|
||||
( SOCKADDR_UNION_AF(PTR) == AF_INET ) ? (PTR)->v4.sin_port : ( \
|
||||
( SOCKADDR_UNION_AF(PTR) == AF_INET6 ) ? (PTR)->v6.sin6_port : 0 ) )
|
||||
|
||||
struct client {
|
||||
union sockaddr_union addr;
|
||||
};
|
||||
|
||||
struct server {
|
||||
int fd;
|
||||
};
|
||||
|
||||
int resolve(const char *host, unsigned short port, struct addrinfo** addr);
|
||||
int resolve_sa(const char *host, unsigned short port, union sockaddr_union *res);
|
||||
int bindtoip(int fd, union sockaddr_union *bindaddr);
|
||||
|
||||
int server_waitclient(struct server *server, struct client* client, void* buf, size_t *buflen);
|
||||
int server_setup(struct server *server, const char* listenip, unsigned short port);
|
||||
|
||||
#endif
|
||||
|
@ -82,7 +82,7 @@ ip_type4 hostsreader_get_numeric_ip_for_name(const char* name) {
|
||||
ip_type4 res;
|
||||
memcpy(res.octet, &c.s_addr, 4);
|
||||
return res;
|
||||
} else return ip_type_invalid.addr.v4;
|
||||
} else return IPT4_INVALID;
|
||||
}
|
||||
|
||||
#ifdef HOSTSREADER_TEST
|
||||
|
@ -1,5 +0,0 @@
|
||||
#include "ip_type.h"
|
||||
|
||||
const ip_type ip_type_invalid = { .addr.v4.as_int = -1 };
|
||||
const ip_type ip_type_localhost = { .addr.v4.octet = {127, 0, 0, 1} };
|
||||
|
@ -16,8 +16,10 @@ typedef struct {
|
||||
char is_v6;
|
||||
} ip_type;
|
||||
|
||||
extern const ip_type ip_type_invalid;
|
||||
extern const ip_type ip_type_localhost;
|
||||
#define IPT4_INT(X) (ip_type4){.as_int = (X)}
|
||||
#define IPT4_INVALID IPT4_INT(-1)
|
||||
|
||||
#define IPT4_BYTES(A,B,C,D) (ip_type4){.octet = {(A), (B), (C), (D)} }
|
||||
#define IPT4_LOCALHOST IPT4_BYTES(127,0,0,1)
|
||||
|
||||
//RcB: DEP "ip_type.c"
|
||||
#endif
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <netdb.h>
|
||||
@ -37,6 +38,7 @@
|
||||
|
||||
#include "core.h"
|
||||
#include "common.h"
|
||||
#include "rdns.h"
|
||||
|
||||
#undef satosin
|
||||
#define satosin(x) ((struct sockaddr_in *) &(x))
|
||||
@ -70,7 +72,7 @@ unsigned int proxychains_proxy_offset = 0;
|
||||
int proxychains_got_chain_data = 0;
|
||||
unsigned int proxychains_max_chain = 1;
|
||||
int proxychains_quiet_mode = 0;
|
||||
int proxychains_resolver = 0;
|
||||
enum dns_lookup_flavor proxychains_resolver = DNSLF_LIBC;
|
||||
localaddr_arg localnet_addr[MAX_LOCALNET];
|
||||
size_t num_localnet_addr = 0;
|
||||
dnat_arg dnats[MAX_DNAT];
|
||||
@ -125,12 +127,6 @@ static void setup_hooks(void) {
|
||||
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();
|
||||
@ -146,7 +142,7 @@ static void do_init(void) {
|
||||
while(close_fds_cnt) true_close(close_fds[--close_fds_cnt]);
|
||||
init_l = 1;
|
||||
|
||||
if(proxychains_resolver == 1) rdns_init();
|
||||
rdns_init(proxychains_resolver);
|
||||
}
|
||||
|
||||
static void init_lib_wrapper(const char* caller) {
|
||||
@ -270,15 +266,17 @@ static const char* bool_str(int bool_val) {
|
||||
return "false";
|
||||
}
|
||||
|
||||
#define STR_STARTSWITH(P, LIT) (!strncmp(P, LIT, sizeof(LIT)-1))
|
||||
/* get configuration from config file */
|
||||
static void get_chain_data(proxy_data * pd, unsigned int *proxy_count, chain_type * ct) {
|
||||
int count = 0, port_n = 0, list = 0;
|
||||
char buff[1024], type[1024], host[1024], user[1024];
|
||||
char *env;
|
||||
char buf[1024], type[1024], host[1024], user[1024];
|
||||
char *buff, *env, *p;
|
||||
char local_in_addr_port[32];
|
||||
char local_in_addr[32], local_in_port[32], local_netmask[32];
|
||||
char dnat_orig_addr_port[32], dnat_new_addr_port[32];
|
||||
char dnat_orig_addr[32], dnat_orig_port[32], dnat_new_addr[32], dnat_new_port[32];
|
||||
char rdnsd_addr[32], rdnsd_port[8];
|
||||
FILE *file = NULL;
|
||||
|
||||
if(proxychains_got_chain_data)
|
||||
@ -291,7 +289,7 @@ static void get_chain_data(proxy_data * pd, unsigned int *proxy_count, chain_typ
|
||||
tcp_connect_time_out = 10 * 1000;
|
||||
*ct = DYNAMIC_TYPE;
|
||||
|
||||
env = get_config_path(getenv(PROXYCHAINS_CONF_FILE_ENV_VAR), buff, sizeof(buff));
|
||||
env = get_config_path(getenv(PROXYCHAINS_CONF_FILE_ENV_VAR), buf, sizeof(buf));
|
||||
if( ( file = fopen(env, "r") ) == NULL )
|
||||
{
|
||||
perror("couldnt read configuration file");
|
||||
@ -302,8 +300,17 @@ static void get_chain_data(proxy_data * pd, unsigned int *proxy_count, chain_typ
|
||||
if(env && *env == '1')
|
||||
proxychains_quiet_mode = 1;
|
||||
|
||||
while(fgets(buff, sizeof(buff), file)) {
|
||||
if(buff[0] != '\n' && buff[strspn(buff, " ")] != '#') {
|
||||
while(fgets(buf, sizeof(buf), file)) {
|
||||
buff = buf;
|
||||
/* remove leading whitespace */
|
||||
while(isspace(*buff)) buff++;
|
||||
/* remove trailing '\n' */
|
||||
if((p = strrchr(buff, '\n'))) *p = 0;
|
||||
p = buff + strlen(buff)-1;
|
||||
/* remove trailing whitespace */
|
||||
while(p >= buff && isspace(*p)) *(p--) = 0;
|
||||
if(!*buff || *buff == '#') continue; /* skip empty lines and comments */
|
||||
if(1) {
|
||||
/* proxylist has to come last */
|
||||
if(list) {
|
||||
if(count >= MAX_CHAIN)
|
||||
@ -328,19 +335,19 @@ 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 == 1 && count > 0) {
|
||||
if(*ct == STRICT_TYPE && proxychains_resolver >= DNSLF_RDNS_START && count > 0) {
|
||||
/* we can allow dns hostnames for all but the first proxy in the list if chaintype is strict, as remote lookup can be done */
|
||||
rdns_init();
|
||||
rdns_init(proxychains_resolver);
|
||||
ip_type4 internal_ip = at_get_ip_for_host(host, strlen(host));
|
||||
pd[count].ip.is_v6 = 0;
|
||||
host_ip->addr.v4 = internal_ip;
|
||||
if(internal_ip.as_int == ip_type_invalid.addr.v4.as_int)
|
||||
if(internal_ip.as_int == IPT4_INVALID.as_int)
|
||||
goto inv_host;
|
||||
} else {
|
||||
inv_host:
|
||||
fprintf(stderr, "proxy %s has invalid value or is not numeric\n", host);
|
||||
fprintf(stderr, "non-numeric ips are only allowed under the following circumstances:\n");
|
||||
fprintf(stderr, "chaintype == strict (%s), proxy is not first in list (%s), proxy_dns active (%s)\n\n", bool_str(*ct == STRICT_TYPE), bool_str(count > 0), bool_str(proxychains_resolver));
|
||||
fprintf(stderr, "chaintype == strict (%s), proxy is not first in list (%s), proxy_dns active (%s)\n\n", bool_str(*ct == STRICT_TYPE), bool_str(count > 0), rdns_resolver_string(proxychains_resolver));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
@ -357,28 +364,28 @@ inv_host:
|
||||
if(port_n)
|
||||
count++;
|
||||
} else {
|
||||
if(strstr(buff, "[ProxyList]")) {
|
||||
if(!strcmp(buff, "[ProxyList]")) {
|
||||
list = 1;
|
||||
} else if(strstr(buff, "random_chain")) {
|
||||
} else if(!strcmp(buff, "random_chain")) {
|
||||
*ct = RANDOM_TYPE;
|
||||
} else if(strstr(buff, "strict_chain")) {
|
||||
} else if(!strcmp(buff, "strict_chain")) {
|
||||
*ct = STRICT_TYPE;
|
||||
} else if(strstr(buff, "dynamic_chain")) {
|
||||
} else if(!strcmp(buff, "dynamic_chain")) {
|
||||
*ct = DYNAMIC_TYPE;
|
||||
} else if(strstr(buff, "round_robin_chain")) {
|
||||
} else if(!strcmp(buff, "round_robin_chain")) {
|
||||
*ct = ROUND_ROBIN_TYPE;
|
||||
} else if(strstr(buff, "tcp_read_time_out")) {
|
||||
} else if(STR_STARTSWITH(buff, "tcp_read_time_out")) {
|
||||
sscanf(buff, "%s %d", user, &tcp_read_time_out);
|
||||
} else if(strstr(buff, "tcp_connect_time_out")) {
|
||||
} else if(STR_STARTSWITH(buff, "tcp_connect_time_out")) {
|
||||
sscanf(buff, "%s %d", user, &tcp_connect_time_out);
|
||||
} else if(strstr(buff, "remote_dns_subnet")) {
|
||||
} else if(STR_STARTSWITH(buff, "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");
|
||||
exit(1);
|
||||
}
|
||||
} else if(strstr(buff, "localnet")) {
|
||||
} else if(STR_STARTSWITH(buff, "localnet")) {
|
||||
if(sscanf(buff, "%s %21[^/]/%15s", user, local_in_addr_port, local_netmask) < 3) {
|
||||
fprintf(stderr, "localnet format error");
|
||||
exit(1);
|
||||
@ -419,7 +426,7 @@ inv_host:
|
||||
} else {
|
||||
fprintf(stderr, "# of localnet exceed %d.\n", MAX_LOCALNET);
|
||||
}
|
||||
} else if(strstr(buff, "chain_len")) {
|
||||
} else if(STR_STARTSWITH(buff, "chain_len")) {
|
||||
char *pc;
|
||||
int len;
|
||||
pc = strchr(buff, '=');
|
||||
@ -429,13 +436,29 @@ inv_host:
|
||||
}
|
||||
len = atoi(++pc);
|
||||
proxychains_max_chain = (len ? len : 1);
|
||||
} else if(strstr(buff, "quiet_mode")) {
|
||||
} else if(!strcmp(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")) {
|
||||
} else if(!strcmp(buff, "proxy_dns_old")) {
|
||||
proxychains_resolver = DNSLF_FORKEXEC;
|
||||
} else if(!strcmp(buff, "proxy_dns")) {
|
||||
proxychains_resolver = DNSLF_RDNS_THREAD;
|
||||
} else if(STR_STARTSWITH(buff, "proxy_dns_daemon")) {
|
||||
struct sockaddr_in rdns_server_buffer;
|
||||
|
||||
if(sscanf(buff, "%s %15[^:]:%5s", user, rdnsd_addr, rdnsd_port) < 3) {
|
||||
fprintf(stderr, "proxy_dns_daemon format error\n");
|
||||
exit(1);
|
||||
}
|
||||
rdns_server_buffer.sin_family = AF_INET;
|
||||
int error = inet_pton(AF_INET, rdnsd_addr, &rdns_server_buffer.sin_addr);
|
||||
if(error <= 0) {
|
||||
fprintf(stderr, "bogus proxy_dns_daemon address\n");
|
||||
exit(1);
|
||||
}
|
||||
rdns_server_buffer.sin_port = htons(atoi(rdnsd_port));
|
||||
proxychains_resolver = DNSLF_RDNS_DAEMON;
|
||||
rdns_set_daemon(&rdns_server_buffer);
|
||||
} else if(STR_STARTSWITH(buff, "dnat")) {
|
||||
if(sscanf(buff, "%s %21[^ ] %21s\n", user, dnat_orig_addr_port, dnat_new_addr_port) < 3) {
|
||||
fprintf(stderr, "dnat format error");
|
||||
exit(1);
|
||||
@ -497,7 +520,7 @@ inv_host:
|
||||
}
|
||||
*proxy_count = count;
|
||||
proxychains_got_chain_data = 1;
|
||||
PDEBUG("proxy_dns: %s\n", proxychains_resolver ? (proxychains_resolver == 2 ? "OLD" : "ON") : "OFF");
|
||||
PDEBUG("proxy_dns: %s\n", rdns_resolver_string(proxychains_resolver));
|
||||
}
|
||||
|
||||
/******* HOOK FUNCTIONS *******/
|
||||
@ -509,7 +532,7 @@ int close(int fd) {
|
||||
errno = 0;
|
||||
return 0;
|
||||
}
|
||||
if(proxychains_resolver != 1) return true_close(fd);
|
||||
if(proxychains_resolver != DNSLF_RDNS_THREAD) return true_close(fd);
|
||||
|
||||
/* prevent rude programs (like ssh) from closing our pipes */
|
||||
if(fd != req_pipefd[0] && fd != req_pipefd[1] &&
|
||||
@ -624,12 +647,12 @@ struct hostent *gethostbyname(const char *name) {
|
||||
INIT();
|
||||
PDEBUG("gethostbyname: %s\n", name);
|
||||
|
||||
if(proxychains_resolver == 1)
|
||||
return proxy_gethostbyname(name, &ghbndata);
|
||||
else if(proxychains_resolver == 2)
|
||||
if(proxychains_resolver == DNSLF_FORKEXEC)
|
||||
return proxy_gethostbyname_old(name);
|
||||
else
|
||||
else if(proxychains_resolver == DNSLF_LIBC)
|
||||
return true_gethostbyname(name);
|
||||
else
|
||||
return proxy_gethostbyname(name, &ghbndata);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@ -638,7 +661,7 @@ int getaddrinfo(const char *node, const char *service, const struct addrinfo *hi
|
||||
INIT();
|
||||
PDEBUG("getaddrinfo: %s %s\n", node ? node : "null", service ? service : "null");
|
||||
|
||||
if(proxychains_resolver)
|
||||
if(proxychains_resolver != DNSLF_LIBC)
|
||||
return proxy_getaddrinfo(node, service, hints, res);
|
||||
else
|
||||
return true_getaddrinfo(node, service, hints, res);
|
||||
@ -648,7 +671,7 @@ void freeaddrinfo(struct addrinfo *res) {
|
||||
INIT();
|
||||
PDEBUG("freeaddrinfo %p \n", (void *) res);
|
||||
|
||||
if(!proxychains_resolver)
|
||||
if(proxychains_resolver == DNSLF_LIBC)
|
||||
true_freeaddrinfo(res);
|
||||
else
|
||||
proxy_freeaddrinfo(res);
|
||||
@ -661,7 +684,7 @@ int pc_getnameinfo(const struct sockaddr *sa, socklen_t salen,
|
||||
INIT();
|
||||
PFUNC();
|
||||
|
||||
if(!proxychains_resolver) {
|
||||
if(proxychains_resolver == DNSLF_LIBC) {
|
||||
return true_getnameinfo(sa, salen, host, hostlen, serv, servlen, flags);
|
||||
} else {
|
||||
if(!salen || !(SOCKFAMILY(*sa) == AF_INET || SOCKFAMILY(*sa) == AF_INET6))
|
||||
@ -708,7 +731,7 @@ struct hostent *gethostbyaddr(const void *addr, socklen_t len, int type) {
|
||||
static char *aliases[1];
|
||||
static struct hostent he;
|
||||
|
||||
if(!proxychains_resolver)
|
||||
if(proxychains_resolver == DNSLF_LIBC)
|
||||
return true_gethostbyaddr(addr, len, type);
|
||||
else {
|
||||
|
||||
|
@ -48,17 +48,33 @@ strict_chain
|
||||
# Quiet mode (no output from library)
|
||||
#quiet_mode
|
||||
|
||||
# Proxy DNS requests - no leak for DNS data
|
||||
# this uses the proxychains4 style method to do remote dns
|
||||
## Proxy DNS requests - no leak for DNS data
|
||||
# (disable all of the 3 items below to not proxy your DNS requests)
|
||||
|
||||
# method 1. this uses the proxychains4 style method to do remote dns:
|
||||
# a thread is spawned that serves DNS requests and hands down an ip
|
||||
# assigned from an internal list (via remote_dns_subset).
|
||||
# this is the easiest (setup-wise) and fastest method, however on
|
||||
# systems with buggy libcs and very complex software like webbrosers
|
||||
# this might not work and/or cause crashes.
|
||||
proxy_dns
|
||||
|
||||
# use the old proxyresolv script to proxy DNS requests
|
||||
# in proxychains 3.1 style. requires proxyresolv in $PATH
|
||||
# method 2. use the old proxyresolv script to proxy DNS requests
|
||||
# in proxychains 3.1 style. requires `proxyresolv` in $PATH
|
||||
# plus a dynamically linked `dig` binary.
|
||||
# this is a lot slower than `proxy_dns`, doesn't support .onion URLs,
|
||||
# but might be more compatible with complex software like webbrowsers.
|
||||
#proxy_dns_old
|
||||
|
||||
# method 3. use proxychains4-daemon process to serve remote DNS requests.
|
||||
# this is similar to the threaded `proxy_dns` method, however it requires
|
||||
# that proxychains4-daemon is already running on the specified address.
|
||||
# on the plus side it doesn't do malloc/threads so it should be quite
|
||||
# compatible with complex, async-unsafe software.
|
||||
# note that if you don't start proxychains4-daemon before using this,
|
||||
# the process will simply hang.
|
||||
#proxy_dns_daemon 127.0.0.1:1053
|
||||
|
||||
# set the class A subnet number to use for the internal remote DNS mapping
|
||||
# we use the reserved 224.x.x.x range by default,
|
||||
# if the proxified app does a DNS request, we will return an IP from that range.
|
||||
|
99
src/rdns.c
Normal file
99
src/rdns.c
Normal file
@ -0,0 +1,99 @@
|
||||
#include <sys/socket.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "rdns.h"
|
||||
#include "allocator_thread.h"
|
||||
#include "remotedns.h"
|
||||
|
||||
#ifndef HAVE_SOCK_CLOEXEC
|
||||
#define SOCK_CLOEXEC 0
|
||||
#endif
|
||||
|
||||
//static enum dns_lookup_flavor dns_flavor;
|
||||
#define dns_flavor rdns_get_flavor()
|
||||
|
||||
static struct sockaddr_in rdns_server;
|
||||
|
||||
size_t rdns_daemon_get_host_for_ip(ip_type4 ip, char* readbuf) {
|
||||
struct at_msg msg = {
|
||||
.h.msgtype = ATM_GETNAME,
|
||||
.h.datalen = htons(4),
|
||||
.m.ip = ip,
|
||||
};
|
||||
int fd = socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC, 0);
|
||||
sendto(fd, &msg, sizeof(msg.h)+4, 0, (void*)&rdns_server, sizeof(rdns_server));
|
||||
recvfrom(fd, &msg, sizeof msg, 0, (void*)0, (void*)0);
|
||||
close(fd);
|
||||
msg.h.datalen = ntohs(msg.h.datalen);
|
||||
if(!msg.h.datalen || msg.h.datalen > 256) return 0;
|
||||
memcpy(readbuf, msg.m.host, msg.h.datalen);
|
||||
return msg.h.datalen - 1;
|
||||
}
|
||||
|
||||
static ip_type4 rdns_daemon_get_ip_for_host(char* host, size_t len) {
|
||||
struct at_msg msg = {
|
||||
.h.msgtype = ATM_GETIP,
|
||||
};
|
||||
if(len >= 256) return IPT4_INT(-1);
|
||||
memcpy(msg.m.host, host, len+1);
|
||||
msg.h.datalen = htons(len+1);
|
||||
int fd = socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC, 0);
|
||||
sendto(fd, &msg, sizeof(msg.h)+len+1, 0, (void*)&rdns_server, sizeof(rdns_server));
|
||||
recvfrom(fd, &msg, sizeof msg, 0, (void*)0, (void*)0);
|
||||
close(fd);
|
||||
if(ntohs(msg.h.datalen) != 4) return IPT4_INT(-1);
|
||||
return msg.m.ip;
|
||||
}
|
||||
|
||||
const char *rdns_resolver_string(enum dns_lookup_flavor flavor) {
|
||||
static const char tab[][7] = {
|
||||
[DNSLF_LIBC] = "off",
|
||||
[DNSLF_FORKEXEC] = "old",
|
||||
[DNSLF_RDNS_THREAD] = "thread",
|
||||
[DNSLF_RDNS_DAEMON] = "daemon",
|
||||
};
|
||||
return tab[flavor];
|
||||
}
|
||||
|
||||
void rdns_init(enum dns_lookup_flavor flavor) {
|
||||
static int init_done = 0;
|
||||
if(!init_done) switch(flavor) {
|
||||
case DNSLF_RDNS_THREAD:
|
||||
at_init();
|
||||
break;
|
||||
case DNSLF_RDNS_DAEMON:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
init_done = 1;
|
||||
}
|
||||
|
||||
void rdns_set_daemon(struct sockaddr_in* addr) {
|
||||
rdns_server = *addr;
|
||||
}
|
||||
|
||||
#if 0
|
||||
enum dns_lookup_flavor rdns_get_flavor(void) {
|
||||
return dns_flavor;
|
||||
}
|
||||
#endif
|
||||
|
||||
size_t rdns_get_host_for_ip(ip_type4 ip, char* readbuf) {
|
||||
switch(dns_flavor) {
|
||||
case DNSLF_RDNS_THREAD: return at_get_host_for_ip(ip, readbuf);
|
||||
case DNSLF_RDNS_DAEMON: return rdns_daemon_get_host_for_ip(ip, readbuf);
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
ip_type4 rdns_get_ip_for_host(char* host, size_t len) {
|
||||
switch(dns_flavor) {
|
||||
case DNSLF_RDNS_THREAD: return at_get_ip_for_host(host, len);
|
||||
case DNSLF_RDNS_DAEMON: return rdns_daemon_get_ip_for_host(host, len);
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
28
src/rdns.h
Normal file
28
src/rdns.h
Normal file
@ -0,0 +1,28 @@
|
||||
#ifndef RDNS_H
|
||||
#define RDNS_H
|
||||
|
||||
#include <unistd.h>
|
||||
#include <netinet/in.h>
|
||||
#include "ip_type.h"
|
||||
#include "remotedns.h"
|
||||
|
||||
enum dns_lookup_flavor {
|
||||
DNSLF_LIBC = 0,
|
||||
DNSLF_FORKEXEC,
|
||||
|
||||
DNSLF_RDNS_START,
|
||||
DNSLF_RDNS_THREAD = DNSLF_RDNS_START,
|
||||
DNSLF_RDNS_DAEMON,
|
||||
};
|
||||
|
||||
void rdns_init(enum dns_lookup_flavor flavor);
|
||||
void rdns_set_daemon(struct sockaddr_in* addr);
|
||||
const char *rdns_resolver_string(enum dns_lookup_flavor flavor);
|
||||
size_t rdns_get_host_for_ip(ip_type4 ip, char* readbuf);
|
||||
ip_type4 rdns_get_ip_for_host(char* host, size_t len);
|
||||
|
||||
//enum dns_lookup_flavor rdns_get_flavor(void);
|
||||
#define rdns_get_flavor() proxychains_resolver
|
||||
extern enum dns_lookup_flavor proxychains_resolver;
|
||||
|
||||
#endif
|
@ -4,6 +4,8 @@
|
||||
#include <unistd.h>
|
||||
#include "ip_type.h"
|
||||
|
||||
#define MSG_LEN_MAX 256
|
||||
|
||||
enum at_msgtype {
|
||||
ATM_GETIP = 0,
|
||||
ATM_GETNAME,
|
||||
|
Loading…
Reference in New Issue
Block a user