Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/rofl0r/proxychains-ng.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile25
-rwxr-xr-xconfigure3
-rw-r--r--src/allocator_thread.h2
-rw-r--r--src/core.c15
-rw-r--r--src/daemon/daemon.c231
-rw-r--r--src/daemon/hsearch.c188
-rw-r--r--src/daemon/hsearch.h21
-rw-r--r--src/daemon/sblist.c73
-rw-r--r--src/daemon/sblist.h92
-rw-r--r--src/daemon/sblist_delete.c9
-rw-r--r--src/daemon/udpclient.c41
-rw-r--r--src/daemon/udpserver.c65
-rw-r--r--src/daemon/udpserver.h48
-rw-r--r--src/libproxychains.c58
-rw-r--r--src/proxychains.conf24
-rw-r--r--src/rdns.c99
-rw-r--r--src/rdns.h28
-rw-r--r--src/remotedns.h2
18 files changed, 979 insertions, 45 deletions
diff --git a/Makefile b/Makefile
index 31ba8db..d124ac9 100644
--- a/Makefile
+++ b/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/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)
+
+$(PXCHAINS): $(OBJS)
+ $(CC) $^ $(USER_LDFLAGS) $(LIBDL) -o $@
-$(ALL_TOOLS): $(OBJS)
- $(CC) src/main.o src/common.o $(USER_LDFLAGS) $(LIBDL) -o $(PXCHAINS)
+$(PXCHAINS_D): $(DOBJS)
+ $(CC) $^ $(USER_LDFLAGS) -o $@
.PHONY: all clean install install-config install-libs install-tools
diff --git a/configure b/configure
index 993b20c..2b1e42a 100755
--- a/configure
+++ b/configure
@@ -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
diff --git a/src/allocator_thread.h b/src/allocator_thread.h
index 734ed89..1e8fae3 100644
--- a/src/allocator_thread.h
+++ b/src/allocator_thread.h
@@ -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];
diff --git a/src/core.c b/src/core.c
index 53e52d9..c307cbe 100644
--- a/src/core.c
+++ b/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:
@@ -865,7 +864,7 @@ struct hostent *proxy_gethostbyname(const char *name, struct gethostbyname_data*
goto retname;
}
- data->resolved_addr = at_get_ip_for_host((char*) name, strlen(name)).as_int;
+ 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);
diff --git a/src/daemon/daemon.c b/src/daemon/daemon.c
new file mode 100644
index 000000000..a0e8f2a
--- /dev/null
+++ b/src/daemon/daemon.c
@@ -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));
+ }
+}
diff --git a/src/daemon/hsearch.c b/src/daemon/hsearch.c
new file mode 100644
index 000000000..a00e87b
--- /dev/null
+++ b/src/daemon/hsearch.c
@@ -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;
+}
diff --git a/src/daemon/hsearch.h b/src/daemon/hsearch.h
new file mode 100644
index 000000000..98da86d
--- /dev/null
+++ b/src/daemon/hsearch.h
@@ -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
diff --git a/src/daemon/sblist.c b/src/daemon/sblist.c
new file mode 100644
index 000000000..96bbebc
--- /dev/null
+++ b/src/daemon/sblist.c
@@ -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);
+}
diff --git a/src/daemon/sblist.h b/src/daemon/sblist.h
new file mode 100644
index 000000000..f0d1846
--- /dev/null
+++ b/src/daemon/sblist.h
@@ -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
diff --git a/src/daemon/sblist_delete.c b/src/daemon/sblist_delete.c
new file mode 100644
index 000000000..a18209a
--- /dev/null
+++ b/src/daemon/sblist_delete.c
@@ -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--;
+ }
+}
diff --git a/src/daemon/udpclient.c b/src/daemon/udpclient.c
new file mode 100644
index 000000000..1cb5825
--- /dev/null
+++ b/src/daemon/udpclient.c
@@ -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);
+ }
+}
diff --git a/src/daemon/udpserver.c b/src/daemon/udpserver.c
new file mode 100644
index 000000000..62b85d0
--- /dev/null
+++ b/src/daemon/udpserver.c
@@ -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;
+}
diff --git a/src/daemon/udpserver.h b/src/daemon/udpserver.h
new file mode 100644
index 000000000..88e16d2
--- /dev/null
+++ b/src/daemon/udpserver.h
@@ -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
+
diff --git a/src/libproxychains.c b/src/libproxychains.c
index ca10cda..fc6880f 100644
--- a/src/libproxychains.c
+++ b/src/libproxychains.c
@@ -38,6 +38,7 @@
#include "core.h"
#include "common.h"
+#include "rdns.h"
#undef satosin
#define satosin(x) ((struct sockaddr_in *) &(x))
@@ -71,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];
@@ -126,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();
@@ -147,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) {
@@ -281,6 +276,7 @@ static void get_chain_data(proxy_data * pd, unsigned int *proxy_count, chain_typ
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)
@@ -339,9 +335,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 == 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;
@@ -351,7 +347,7 @@ static void get_chain_data(proxy_data * pd, unsigned int *proxy_count, chain_typ
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);
}
}
@@ -443,9 +439,25 @@ inv_host:
} else if(!strcmp(buff, "quiet_mode")) {
proxychains_quiet_mode = 1;
} else if(!strcmp(buff, "proxy_dns_old")) {
- proxychains_resolver = 2;
+ proxychains_resolver = DNSLF_FORKEXEC;
} else if(!strcmp(buff, "proxy_dns")) {
- proxychains_resolver = 1;
+ 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");
@@ -508,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 *******/
@@ -520,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] &&
@@ -635,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;
}
@@ -649,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);
@@ -659,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);
@@ -672,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))
@@ -719,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 {
diff --git a/src/proxychains.conf b/src/proxychains.conf
index fb08ae1..ecb9164 100644
--- a/src/proxychains.conf
+++ b/src/proxychains.conf
@@ -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.
diff --git a/src/rdns.c b/src/rdns.c
new file mode 100644
index 000000000..d9496b1
--- /dev/null
+++ b/src/rdns.c
@@ -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();
+ }
+}
+
diff --git a/src/rdns.h b/src/rdns.h
new file mode 100644
index 000000000..8f63ab8
--- /dev/null
+++ b/src/rdns.h
@@ -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
diff --git a/src/remotedns.h b/src/remotedns.h
index f4be974..588e09a 100644
--- a/src/remotedns.h
+++ b/src/remotedns.h
@@ -4,6 +4,8 @@
#include <unistd.h>
#include "ip_type.h"
+#define MSG_LEN_MAX 256
+
enum at_msgtype {
ATM_GETIP = 0,
ATM_GETNAME,