2 proxychains-ng DNS daemon
4 Copyright (C) 2020 rofl0r.
10 #define _POSIX_C_SOURCE 200809L
16 #include <sys/select.h>
17 #include <arpa/inet.h>
20 #include "udpserver.h"
23 #include "../remotedns.h"
24 #include "../ip_type.h"
27 #define MAX(x, y) ((x) > (y) ? (x) : (y))
30 static struct htab
*ip_lookup_table
;
31 static sblist
*hostnames
;
32 static unsigned remote_subnet
;
33 static const struct server
* server
;
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__)
44 static void dolog(const char* fmt
, ...) { }
47 static char* my_inet_ntoa(unsigned char *ip_buf_4_bytes
, char *outbuf_16_bytes
) {
49 char *o
= outbuf_16_bytes
;
51 for(p
= ip_buf_4_bytes
; p
< ip_buf_4_bytes
+ 4; p
++) {
61 *(o
++) = (n
/ 10) + '0';
68 return outbuf_16_bytes
;
72 /* buf needs to be long enough for an ipv6 addr, i.e. INET6_ADDRSTRLEN + 1 */
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);
78 snprintf(portbuf
, sizeof portbuf
, ":%u", (unsigned) ntohs(SOCKADDR_UNION_PORT(su
)));
83 static int usage(char *a0
) {
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
94 unsigned index_from_ip(ip_type4 internalip
) {
95 ip_type4 tmp
= internalip
;
97 ret
= tmp
.octet
[3] + (tmp
.octet
[2] << 8) + (tmp
.octet
[1] << 16);
102 char *host_from_ip(ip_type4 internalip
) {
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
;
112 ip_type4
get_ip_from_index(unsigned index
) {
114 index
++; // so we can start at .0.0.1
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;
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
)) {
134 if(!htab_insert(ip_lookup_table
, n
, HTV_N(sblist_getsize(hostnames
)-1))) {
135 sblist_delete(hostnames
, sblist_getsize(hostnames
)-1);
138 return get_ip_from_index(sblist_getsize(hostnames
)-1);
141 int main(int argc
, char** argv
) {
143 const char *listenip
= "127.0.0.1";
144 unsigned port
= 1053;
146 while((ch
= getopt(argc
, argv
, ":r:i:p:")) != -1) {
149 remote_subnet
= atoi(optarg
);
158 dprintf(2, "error: option -%c requires an operand\n", optopt
);
161 return usage(argv
[0]);
164 signal(SIGPIPE
, SIG_IGN
);
166 if(server_setup(&s
, listenip
, port
)) {
167 perror("server_setup");
172 ip_lookup_table
= htab_create(64);
173 hostnames
= sblist_new(sizeof(char*), 64);
177 char ipstr_buf
[INET6_ADDRSTRLEN
+6+1];
179 struct at_msg msg
, out
;
180 size_t msgl
= sizeof(msg
);
183 #define FAIL() do { failed=1; goto sendresp; } while(0)
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
));
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
));
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
));
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
));
209 char *hn
= host_from_ip(msg
.m
.ip
);
211 size_t l
= strlen(hn
);
212 memcpy(out
.m
.host
, hn
, l
+1);
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");
219 dolog("%s: unknown request %u\n", ipstr(&c
.addr
, ipstr_buf
),
220 (unsigned) msg
.h
.msgtype
);
224 out
.h
.msgtype
= ATM_FAIL
;
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
));