1 /*
2    proxychains-ng DNS daemon
3 
4    Copyright (C) 2020 rofl0r.
5 
6 */
7 
8 #define _GNU_SOURCE
9 #include <unistd.h>
10 #define _POSIX_C_SOURCE 200809L
11 #include <stdlib.h>
12 #include <string.h>
13 #include <stdio.h>
14 #include <pthread.h>
15 #include <signal.h>
16 #include <sys/select.h>
17 #include <arpa/inet.h>
18 #include <errno.h>
19 #include <limits.h>
20 #include "udpserver.h"
21 #include "sblist.h"
22 #include "hsearch.h"
23 #include "../remotedns.h"
24 #include "../ip_type.h"
25 
26 #ifndef MAX
27 #define MAX(x, y) ((x) > (y) ? (x) : (y))
28 #endif
29 
30 static struct htab *ip_lookup_table;
31 static sblist *hostnames;
32 static unsigned remote_subnet;
33 static const struct server* server;
34 
35 #ifndef CONFIG_LOG
36 #define CONFIG_LOG 1
37 #endif
38 #if CONFIG_LOG
39 /* we log to stderr because it's not using line buffering, i.e. malloc which would need
40    locking when called from different threads. for the same reason we use dprintf,
41    which writes directly to an fd. */
42 #define dolog(...) dprintf(2, __VA_ARGS__)
43 #else
dolog(const char * fmt,...)44 static void dolog(const char* fmt, ...) { }
45 #endif
46 
my_inet_ntoa(unsigned char * ip_buf_4_bytes,char * outbuf_16_bytes)47 static char* my_inet_ntoa(unsigned char *ip_buf_4_bytes, char *outbuf_16_bytes) {
48 	unsigned char *p;
49 	char *o = outbuf_16_bytes;
50 	unsigned char n;
51 	for(p = ip_buf_4_bytes; p < ip_buf_4_bytes + 4; p++) {
52 		n = *p;
53 		if(*p >= 100) {
54 			if(*p >= 200)
55 				*(o++) = '2';
56 			else
57 				*(o++) = '1';
58 			n %= 100;
59 		}
60 		if(*p >= 10) {
61 			*(o++) = (n / 10) + '0';
62 			n %= 10;
63 		}
64 		*(o++) = n + '0';
65 		*(o++) = '.';
66 	}
67 	o[-1] = 0;
68 	return outbuf_16_bytes;
69 }
70 
71 
72 /* buf needs to be long enough for an ipv6 addr, i.e. INET6_ADDRSTRLEN + 1 */
ipstr(union sockaddr_union * su,char * buf)73 static char* ipstr(union sockaddr_union *su, char* buf) {
74 	int af = SOCKADDR_UNION_AF(su);
75 	void *ipdata = SOCKADDR_UNION_ADDRESS(su);
76 	inet_ntop(af, ipdata, buf, INET6_ADDRSTRLEN+1);
77 	char portbuf[7];
78 	snprintf(portbuf, sizeof portbuf, ":%u", (unsigned) ntohs(SOCKADDR_UNION_PORT(su)));
79 	strcat(buf, portbuf);
80 	return buf;
81 }
82 
usage(char * a0)83 static int usage(char *a0) {
84 	dprintf(2,
85 		"Proxychains-NG remote dns daemon\n"
86 		"--------------------------------\n"
87 		"usage: %s -i listenip -p port -r remotesubnet\n"
88 		"all arguments are optional.\n"
89 		"by default listenip is 127.0.0.1, port 1053 and remotesubnet 224.\n\n", a0
90 	);
91 	return 1;
92 }
93 
index_from_ip(ip_type4 internalip)94 unsigned index_from_ip(ip_type4 internalip) {
95 	ip_type4 tmp = internalip;
96 	uint32_t ret;
97 	ret = tmp.octet[3] + (tmp.octet[2] << 8) + (tmp.octet[1] << 16);
98 	ret -= 1;
99 	return ret;
100 }
101 
host_from_ip(ip_type4 internalip)102 char *host_from_ip(ip_type4 internalip) {
103 	char *res = NULL;
104 	unsigned index = index_from_ip(internalip);
105 	if(index < sblist_getsize(hostnames)) {
106 		char **tmp = sblist_get(hostnames, index);
107 		if(tmp && *tmp) res = *tmp;
108 	}
109 	return res;
110 }
111 
get_ip_from_index(unsigned index)112 ip_type4 get_ip_from_index(unsigned index) {
113 	ip_type4 ret;
114 	index++; // so we can start at .0.0.1
115 	if(index > 0xFFFFFF)
116 		return IPT4_INVALID;
117 	ret.octet[0] = remote_subnet & 0xFF;
118 	ret.octet[1] = (index & 0xFF0000) >> 16;
119 	ret.octet[2] = (index & 0xFF00) >> 8;
120 	ret.octet[3] = index & 0xFF;
121 	return ret;
122 }
123 
get_ip(char * hn)124 ip_type4 get_ip(char* hn) {
125 	htab_value *v = htab_find(ip_lookup_table, hn);
126 	if(v) return get_ip_from_index(v->n);
127 	char *n = strdup(hn);
128 	if(!n) return IPT4_INVALID;
129 	if(!sblist_add(hostnames, &n)) {
130 	o_out:;
131 		free(n);
132 		return IPT4_INVALID;
133 	}
134 	if(!htab_insert(ip_lookup_table, n, HTV_N(sblist_getsize(hostnames)-1))) {
135 		sblist_delete(hostnames, sblist_getsize(hostnames)-1);
136 		goto o_out;
137 	}
138 	return get_ip_from_index(sblist_getsize(hostnames)-1);
139 }
140 
main(int argc,char ** argv)141 int main(int argc, char** argv) {
142 	int ch;
143 	const char *listenip = "127.0.0.1";
144 	unsigned port = 1053;
145 	remote_subnet = 224;
146 	while((ch = getopt(argc, argv, ":r:i:p:")) != -1) {
147 		switch(ch) {
148 			case 'r':
149 				remote_subnet = atoi(optarg);
150 				break;
151 			case 'i':
152 				listenip = optarg;
153 				break;
154 			case 'p':
155 				port = atoi(optarg);
156 				break;
157 			case ':':
158 				dprintf(2, "error: option -%c requires an operand\n", optopt);
159 				/* fall through */
160 			case '?':
161 				return usage(argv[0]);
162 		}
163 	}
164 	signal(SIGPIPE, SIG_IGN);
165 	struct server s;
166 	if(server_setup(&s, listenip, port)) {
167 		perror("server_setup");
168 		return 1;
169 	}
170 	server = &s;
171 
172 	ip_lookup_table = htab_create(64);
173 	hostnames = sblist_new(sizeof(char*), 64);
174 
175 	while(1) {
176 		struct client c;
177 		char ipstr_buf[INET6_ADDRSTRLEN+6+1];
178 		char ip4str_buf[16];
179 		struct at_msg msg, out;
180 		size_t msgl = sizeof(msg);
181 		int failed = 0;
182 
183 #define FAIL() do { failed=1; goto sendresp; } while(0)
184 
185 		if(server_waitclient(&s, &c, &msg, &msgl)) continue;
186 		msg.h.datalen = ntohs(msg.h.datalen);
187 		if(msgl != sizeof(msg.h)+msg.h.datalen) {
188 			dolog("%s: invalid datalen\n", ipstr(&c.addr, ipstr_buf));
189 			FAIL();
190 		}
191 
192 		out.h.msgtype = msg.h.msgtype;
193 		if(msg.h.msgtype == ATM_GETIP) {
194 			if(!memchr(msg.m.host, 0, msg.h.datalen)) {
195 				dolog("%s: nul terminator missing\n", ipstr(&c.addr, ipstr_buf));
196 				FAIL();
197 			}
198 			out.h.datalen = sizeof(ip_type4);
199 			out.m.ip = get_ip(msg.m.host);
200 			failed = !memcmp(&out.m.ip, &IPT4_INVALID, 4);
201 			dolog("%s requested ip for %s (%s)\n", ipstr(&c.addr, ipstr_buf),
202 			      msg.m.host, failed?"FAIL":my_inet_ntoa((void*)&out.m.ip, ip4str_buf));
203 			if(failed) FAIL();
204 		} else if (msg.h.msgtype == ATM_GETNAME) {
205 			if(msg.h.datalen != 4) {
206 				dolog("%s: invalid len for getname request\n", ipstr(&c.addr, ipstr_buf));
207 				FAIL();
208 			}
209 			char *hn = host_from_ip(msg.m.ip);
210 			if(hn) {
211 				size_t l = strlen(hn);
212 				memcpy(out.m.host, hn, l+1);
213 				out.h.datalen = l+1;
214 			}
215 			dolog("%s requested name for %s (%s)\n", ipstr(&c.addr, ipstr_buf),
216 			      my_inet_ntoa((void*) &msg.m.ip, ip4str_buf), hn?hn:"FAIL");
217 			if(!hn) FAIL();
218 		} else {
219 			dolog("%s: unknown request %u\n", ipstr(&c.addr, ipstr_buf),
220 			      (unsigned) msg.h.msgtype);
221 		}
222 	sendresp:;
223 		if(failed) {
224 			out.h.msgtype = ATM_FAIL;
225 			out.h.datalen = 0;
226 		}
227 		unsigned short dlen = out.h.datalen;
228 		out.h.datalen = htons(dlen);
229 		sendto(server->fd, &out, sizeof(out.h)+dlen, 0, (void*) &c.addr, SOCKADDR_UNION_LENGTH(&c.addr));
230 	}
231 }
232