djbdnscurve6 53
djbdnscurve6
Loading...
Searching...
No Matches
dnscache.c
Go to the documentation of this file.
1#include <unistd.h>
2#include "case.h"
3#include "env.h"
4#include "exit.h"
5#include "scan.h"
6#include "logmsg.h"
7#include "str.h"
8#include "ip.h"
9#include "uint_t.h"
10#include "socket_if.h"
11#include "dns.h"
12#include "taia.h"
13#include "byte.h"
14#include "roots.h"
15#include "fmt.h"
16#include "iopause.h"
17#include "query.h"
18#include "alloc.h"
19#include "response.h"
20#include "sipcache.h"
21#include "ndelay.h"
22#include "log.h"
23#include "clientok.h"
24#include "droproot.h"
25#include "readclose.h"
26#include "curvedns.h"
27
28#define WHO "dnscache"
29
31stralloc ifname = {0};
32uint32 ifidx = 0; /* aka scope_id */
33
34extern int flagedserver; /* per env */
35extern int flagusetxtformat; /* toggle */
36extern unsigned int fallback; /* per env */
37
38unsigned int flagedns0 = 0; /* toggle */
39unsigned int msgsize = MSGSIZE; /* per env */
40
43
44static int packetquery(char *buf,unsigned int len,char **q,char qtype[2],char qclass[2],char id[2])
45{
46 unsigned int pos;
47 unsigned int ad = 0; /* for future use */
48 char header[12];
49
50 errno = EPROTO;
51 pos = dns_packet_copy(buf,len,0,header,12); if (!pos) return 0;
52 if (header[2] & 128) return 0; /* must not respond to responses */
53 if (!(header[2] & 1)) return 0; /* do not respond to non-recursive queries */
54 if (header[2] & 120) return 0; /* standard query only */
55 if (header[2] & 2) return 0; /* Truncation not allowed */
56 if (header[3] & 32) ad = 1; /* Authenticated data */
57 if (byte_diff(header + 4,2,"\0\1")) return 0;
58
59 pos = dns_packet_getname(buf,len,pos,q); if (!pos) return 0;
60 pos = dns_packet_copy(buf,len,pos,qtype,2); if (!pos) return 0;
61 pos = dns_packet_copy(buf,len,pos,qclass,2); if (!pos) return 0;
62 if (byte_diff(qclass,2,DNS_C_IN) && byte_diff(qclass,2,DNS_C_ANY)) return 0;
63 if (!dns_packet_edns0(header,buf,len,pos)) return 0;
64
65 byte_copy(id,2,header);
66 return 1;
67}
68
69static char ipsending[16];
70static char iplistening[16];
71static char buf[MAXSEGMENT];
72uint64 numqueries = 0;
73
74static int udp53;
75
76static struct udpclient {
77 struct query q;
78 struct taia start;
79 uint64 active; /* query number, if active; otherwise 0 */
80 iopause_fd *io;
81 char ip[16];
82 uint16 port;
83 char id[2];
84 uint32 scope_id;
85} u[QUERY_MAXUDP];
86
87int uactive = 0;
88int eactive = 0;
89
90void u_drop(int j)
91{
92 if (!u[j].active) return;
93 log_querydrop(&u[j].active);
94 u[j].active = 0;
95 if (flagedns0) --eactive;
96 else --uactive;
97}
98
99void u_respond(int j)
100{
101 char d[32];
102
103 if (!u[j].active) return;
104
105 response_id(u[j].id);
107 if (socket_send(udp53,response,response_len,u[j].ip,u[j].port,u[j].scope_id) > 0) {
108 log_querydone(&u[j].active,response_len);
109 } else {
110 ip6_fmt(d,u[j].ip);
111 if (ip6_isv4mapped(u[j].ip))
112 ip4_fmt(d,u[j].ip + 12);
113 else
114 ip6_fmt(d,u[j].ip);
115 logmsg(WHO,errno,WARN,B("sending reply to ",d," failed."));
116 }
117 u[j].active = 0;
118 if (flagedns0) --eactive;
119 else --uactive;
120}
121
122void u_new(void)
123{
124 int j;
125 int i;
126 struct udpclient *x;
127 int len;
128 static char *q = 0;
129 char qtype[2];
130 char qclass[2];
131
132 for (j = 0; j < QUERY_MAXUDP; ++j)
133 if (!u[j].active)
134 break;
135
136 if (j >= QUERY_MAXUDP) {
137 j = 0;
138 for (i = 1; i < QUERY_MAXUDP; ++i)
139 if (taia_less(&u[i].start,&u[j].start)) {
140 j = i;
141 errno = ETIMEDOUT;
142 u_drop(j);
143 }
144 }
145
146 x = u + j;
147 taia_now(&x->start);
148
149 len = socket_recv(udp53,buf,sizeof(buf),x->ip,&x->port,&x->scope_id);
150 if (len == -1) return;
151 if (len >= sizeof(buf)) return;
152 if (x->port < 1024) if (x->port != DNSPORT) return;
153 if (!clientok(x->ip)) {
154 char ipstr[IP6_FMT];
155 if (ip6_isv4mapped(x->ip)) len = ip4_fmt(ipstr,x->ip + 12);
156 else len = ip6_fmt(ipstr,x->ip);
157 ipstr[len] = '\0';
158 logmsg(WHO,99,WARN,B("client blocked: ",ipstr));
159 return;
160 }
161
162 if (!packetquery(buf,len,&q,qtype,qclass,x->id)) return;
163
164 x->active = ++numqueries;
165 if (flagedns0) ++eactive;
166 else ++uactive;
167 log_query(&x->active,x->ip,x->port,x->id,q,qtype);
168
169 switch (query_start(&x->q,q,qtype,qclass,ipsending,x->scope_id)) {
170 case -1: case -2: u_drop(j); return;
171 case 1: u_respond(j);
172 }
173}
174
175static int tcp53;
176
177struct tcpclient {
178 struct query q;
179 struct taia start;
180 struct taia timeout;
181 uint64 active; /* query number or 1, if active; otherwise 0 */
182 iopause_fd *io;
183 char ip[16]; /* send response to this address */
184 uint16 port; /* send response to this port */
185 char id[2];
186 int tcp; /* open TCP socket, if active */
187 int state;
188 char *buf; /* 0, or dynamically allocated of length len */
189 unsigned int len;
190 unsigned int pos;
191 uint32 scope_id;
193int tactive = 0;
194
195/*
196state 1: buf 0; normal state at beginning of TCP connection
197state 2: buf 0; have read 1 byte of query packet length into len
198state 3: buf allocated; have read pos bytes of buf
199state 0: buf 0; handling query in q
200state -1: buf allocated; have written pos bytes
201*/
202
203void t_free(int j)
204{
205 if (!t[j].buf) return;
206 alloc_free(t[j].buf);
207 t[j].buf = 0;
208}
209
210void t_timeout(int j)
211{
212 struct taia now;
213 if (!t[j].active) return;
214 taia_now(&now);
215 taia_uint(&t[j].timeout,10);
216 taia_add(&t[j].timeout,&t[j].timeout,&now);
217}
218
219void t_close(int j)
220{
221 if (!t[j].active) return;
222 t_free(j);
223 log_tcpclose(t[j].ip,t[j].port);
224 close(t[j].tcp);
225 t[j].active = 0; --tactive;
226}
227
228void t_drop(int j)
229{
230 log_querydrop(&t[j].active);
231 errno = EPIPE;
232 t_close(j);
233}
234
235void t_respond(int j)
236{
237 if (!t[j].active) return;
238 log_querydone(&t[j].active,response_len);
239 response_id(t[j].id);
240 t[j].len = response_len + 2;
241 t_free(j);
242 t[j].buf = alloc(response_len + 2);
243 if (!t[j].buf) { t_close(j); return; }
244 uint16_pack_big(t[j].buf,response_len);
245 byte_copy(t[j].buf + 2,response_len,response);
246 t[j].pos = 0;
247 t[j].state = -1;
248}
249
250void t_rw(int j)
251{
252 struct tcpclient *x;
253 char *ch;
254 static char *q = 0;
255 unsigned int readsize;
256 char qtype[2];
257 char qclass[2];
258 int r;
259
260 x = t + j;
261 if (x->state == -1) {
262 r = write(x->tcp,x->buf + x->pos,x->len - x->pos);
263 if (r <= 0) { t_close(j); return; }
264 x->pos += r;
265 if (x->pos == x->len) {
266 t_free(j);
267 x->state = 1; /* could drop connection immediately */
268 }
269 return;
270 }
271
272 switch (x->state) {
273 case 1: readsize = 2U; break;
274 case 2: readsize = 1U; break;
275 case 3: readsize = x->len - x->pos; break;
276 default: return; /* impossible */
277 }
278
279 r = read(x->tcp,buf,readsize);
280 if (r == 0) { errno = EPIPE; t_close(j); return; }
281 if (r < 0) { t_close(j); return; }
282
283 ch = buf;
284 if (x->state == 1) {
285 x->len = (unsigned char) *ch++;
286 x->len <<= 8;
287 x->state = 2;
288 if (--r <= 0) return;
289 }
290 if (x->state == 2) {
291 x->len += (unsigned char) *ch;
292 if (!x->len) { errno = EPIPE; t_close(j); return; }
293 x->buf = alloc(x->len);
294 if (!x->buf) { t_close(j); return; }
295 x->pos = 0;
296 x->state = 3;
297 return;
298 }
299
300 if (x->state != 3) return; /* impossible */
301
302 byte_copy(&x->buf[x->pos],r,ch);
303 x->pos += r;
304 if (x->pos < x->len) return;
305
306 if (!packetquery(x->buf,x->len,&q,qtype,qclass,x->id)) { t_close(j); return; }
307
308 x->active = ++numqueries;
309 log_query(&x->active,x->ip,x->port,x->id,q,qtype);
310 switch (query_start(&x->q,q,qtype,qclass,ipsending,x->scope_id)) {
311 case -1: case -2: t_drop(j); return;
312 case 1: t_respond(j); return;
313 }
314 t_free(j);
315 x->state = 0;
316}
317
318void t_new(void)
319{
320 int i;
321 int j;
322 int len;
323 struct tcpclient *x;
324
325 for (j = 0; j < QUERY_MAXTCP; ++j)
326 if (!t[j].active)
327 break;
328
329 if (j >= QUERY_MAXTCP) {
330 j = 0;
331 for (i = 1; i < QUERY_MAXTCP; ++i)
332 if (taia_less(&t[i].start,&t[j].start)) j = i;
333 errno = ETIMEDOUT;
334 if (t[j].state == 0)
335 t_drop(j);
336 else
337 t_close(j);
338 }
339
340 x = t + j;
341 taia_now(&x->start);
342
343 x->tcp = socket_accept(tcp53,x->ip,&x->port,&x->scope_id);
344 if (x->tcp == -1) return;
345 if (x->port < 1024) if (x->port != DNSPORT) { close(x->tcp); return; }
346 if (!clientok(x->ip)) {
347 char ipstr[IP6_FMT];
348 if (ip6_isv4mapped(x->ip)) len = ip4_fmt(ipstr,x->ip + 12);
349 else len = ip6_fmt(ipstr,x->ip);
350 ipstr[len] = '\0'; // Bugfix Martin C; 10.11.2022
351 logmsg(WHO,99,WARN,B("client blocked: ",ipstr));
352 close(x->tcp);
353 return;
354 }
355 if (ndelay_on(x->tcp) == -1) { close(x->tcp); return; } /* Linux bug */
356
357 x->active = 1; ++tactive;
358 x->state = 1;
359 t_timeout(j);
360
361 log_tcpopen(x->ip,x->port);
362}
363
364
365iopause_fd io[3 + QUERY_MAXUDP + QUERY_MAXTCP];
366iopause_fd *udp53io;
367iopause_fd *tcp53io;
368
369static void doit(void)
370{
371 int j;
372 struct taia deadline;
373 struct taia stamp;
374 int iolen;
375 int r;
376
377 for (;;) {
378 taia_now(&stamp);
379 taia_uint(&deadline,120);
380 taia_add(&deadline,&deadline,&stamp);
381
382 iolen = 0;
383
384 udp53io = io + iolen++;
385 udp53io->fd = udp53;
386 udp53io->events = IOPAUSE_READ;
387
388 tcp53io = io + iolen++;
389 tcp53io->fd = tcp53;
390 tcp53io->events = IOPAUSE_READ;
391
392 for (j = 0; j < QUERY_MAXUDP; ++j)
393 if (u[j].active) {
394 u[j].io = io + iolen++;
395 query_io(&u[j].q,u[j].io,&deadline);
396 }
397
398 for (j = 0; j < QUERY_MAXTCP; ++j)
399 if (t[j].active) {
400 t[j].io = io + iolen++;
401 if (t[j].state == 0)
402 query_io(&t[j].q,t[j].io,&deadline);
403 else {
404 if (taia_less(&t[j].timeout,&deadline)) deadline = t[j].timeout;
405 t[j].io->fd = t[j].tcp;
406 t[j].io->events = (t[j].state > 0) ? IOPAUSE_READ : IOPAUSE_WRITE;
407 }
408 }
409
410 if (iopause(io,iolen,&deadline,&stamp) < 0) {
411 errno = ECONNRESET;
412 logmsg(WHO,errno,FATAL,"IO resources not available");
413 }
414
415 for (j = 0; j < QUERY_MAXUDP; ++j)
416 if (u[j].active) {
417 r = query_get(&u[j].q,u[j].io,&stamp);
418 if (r == -1 || r == -2 || r == -3) { errno = ECONNRESET; u_drop(j); }
419 if (r == 1) u_respond(j);
420 }
421
422 for (j = 0; j < QUERY_MAXTCP; ++j)
423 if (t[j].active) {
424 if (t[j].io->revents) t_timeout(j);
425 if (t[j].state == 0) {
426 r = query_get(&t[j].q,t[j].io,&stamp);
427 if (r == -1 || r == -2 || r == -3) { errno = ECONNRESET; t_drop(j); }
428 if (r == 1) t_respond(j);
429 }
430 else if (t[j].io->revents || taia_less(&t[j].timeout,&stamp))
431 t_rw(j);
432 }
433
434 if (udp53io)
435 if (udp53io->revents)
436 u_new();
437
438 if (tcp53io)
439 if (tcp53io->revents)
440 t_new();
441 }
442}
443
444char seed[128];
445
446int main()
447{
448 char *x;
449 unsigned long cachesize;
450 flagedserver = 0;
451 fallback = 0;
452
453 int opt[MAXOPT];
454 for (int i = 0; i < MAXOPT; ++i) opt[i] = 0;
455
456 x = env_get("IP");
457 if (!x)
458 logmsg(WHO,111,ERROR,"$IP not set");
459 if (case_equals(x,"::")) {
460 flagipv6anycast = 1;
461 opt[0] = 1;
462 } else if (case_equals(x,":0")) {
463 flagdualstack = 1;
464 opt[0] = opt[1] = 1;
465 byte_copy(x,2,"::");
466 ifidx = 0;
467 }
468 if (!ip6_ifscan(x,iplistening,&ifname))
469 logmsg(WHO,101,SYNTAX,B("unable to parse IP address: ",x));
470
471 if (ifname.len > 1) ifidx = socket_getifidx(ifname.s);
472
473 if (ip6_isv4mapped(iplistening))
474 udp53 = socket_udp4();
475 else
476 udp53 = socket_udp();
477 if (udp53 == -1)
478 logmsg(WHO,111,FATAL,"unable to create UDP socket");
479
480 if (flagdualstack) socket_dualstack(udp53);
481 if (flagipv6anycast) socket_ip6anycast(udp53);
482 if (socket_bind_reuse(udp53,iplistening,dnsport,ifidx) == -1)
483 logmsg(WHO,111,FATAL,"unable to bind to UDP socket");
484
485 if (ip6_isv4mapped(iplistening))
486 tcp53 = socket_tcp4();
487 else
488 tcp53 = socket_tcp6();
489 if (tcp53 == -1)
490 logmsg(WHO,111,FATAL,"unable to create TCP socket");
491
492 if (flagdualstack) socket_dualstack(tcp53);
493 if (flagipv6anycast) socket_ip6anycast(tcp53);
494 if (socket_bind_reuse(tcp53,iplistening,dnsport,ifidx) == -1)
495 logmsg(WHO,111,FATAL,"unable to bind to TCP socket");
496
497 droproot(WHO);
498
499 socket_tryreservein(udp53,131072);
500
501 byte_zero(seed,sizeof(seed));
502 read(0,seed,sizeof(seed));
504 close(0);
505 query_init();
506
507 x = env_get("IPSEND");
508 if (!x)
509 logmsg(WHO,111,ERROR,"$IPSEND not set");
510 if (!ip6_ifscan(x,ipsending,&ifname))
511 logmsg(WHO,100,SYNTAX,B("unable to parse IP address: ",x));
512
513 x = env_get("CACHESIZE");
514 if (!x)
515 logmsg(WHO,111,ERROR,"$CACHESIZE not set");
516 scan_dnum(x,&cachesize);
517 if (!cache_init(cachesize))
518 logmsg(WHO,111,FATAL,B("not enough memory for cache of size: ",x));
519
520 x = env_get("UDPSIZE");
521 if (x) { scan_uint(x,&msgsize); udp_msgsize(); }
522
523 if (env_get("HIDETTL"))
525 if (env_get("USETXTFORMAT"))
526 { flagusetxtformat = 1; opt[2] = 1; }
527
528 x = env_get("UZ5FALLBACK");
529 if (x) scan_dnum(x,&fallback);
530
531 if (env_get("FLAGEDSERVER"))
532 { flagedserver = 1; opt[3] = 1; }
533
534 x = env_get("DNSOPTRR");
535 if (x) { scan_dnum(x,&flagedns0); opt[4] = flagedns0; }
536
537 x = env_get("FORWARDONLY");
538 if (x) { query_forwardonly(); opt[5] = 1; }
539
540 if (!roots_init())
541 logmsg(WHO,111,ERROR,"unable to read servers");
542
543 if (socket_listen(tcp53,TCP_BACKLOG) == -1)
544 logmsg(WHO,111,FATAL,"unable to listen on TCP socket");
545
546 log_startup(iplistening,ifidx,ipsending,msgsize,opt);
547 doit();
548}
unsigned int doit(char *buf, unsigned int len, unsigned int pos)
Definition: axfr-get.c:131
unsigned long port
Definition: axfrdns.c:129
struct tai now
Definition: axfrdns.c:132
char ip[16]
Definition: axfrdns.c:128
uint16 len
Definition: axfrdns.c:322
char buf[MSGSIZE]
Definition: axfrdns.c:321
int clientok(char ip[16])
Definition: clientok.c:11
unsigned int udp_msgsize(void)
Definition: curvedns.c:38
#define DNSPORT
Definition: curvedns.h:10
#define DNS_C_IN
Definition: dns.h:62
#define MSGSIZE
Definition: dns.h:47
#define MAXSEGMENT
Definition: dns.h:50
#define TCP_BACKLOG
Definition: dns.h:56
#define DNS_C_ANY
Definition: dns.h:63
#define MAXOPT
Definition: dns.h:53
unsigned int dns_packet_getname(const char *buf, unsigned int len, unsigned int pos, char **d)
Definition: dns_packet.c:35
unsigned int dns_packet_copy(const char *buf, unsigned int len, unsigned int pos, char *out, unsigned int outlen)
Definition: dns_packet.c:8
void dns_random_init(const char data[128])
Definition: dns_random.c:36
uint64 numqueries
Definition: dnscache.c:72
int flagipv6anycast
Definition: dnscache.c:42
void t_close(int j)
Definition: dnscache.c:219
void u_new(void)
Definition: dnscache.c:122
uint32 ifidx
Definition: dnscache.c:32
void t_respond(int j)
Definition: dnscache.c:235
void u_respond(int j)
Definition: dnscache.c:99
iopause_fd * udp53io
Definition: dnscache.c:366
void t_new(void)
Definition: dnscache.c:318
void u_drop(int j)
Definition: dnscache.c:90
unsigned int flagedns0
Definition: dnscache.c:38
int flagedserver
Definition: curvedns.c:19
int flagusetxtformat
Definition: curvedns.c:20
iopause_fd * tcp53io
Definition: dnscache.c:367
void t_timeout(int j)
Definition: dnscache.c:210
int uactive
Definition: dnscache.c:87
void t_free(int j)
Definition: dnscache.c:203
stralloc ifname
Definition: dnscache.c:31
uint16 dnsport
Definition: dnscache.c:30
int eactive
Definition: dnscache.c:88
unsigned int fallback
Definition: curvedns.c:21
unsigned int msgsize
Definition: dnscache.c:39
void t_drop(int j)
Definition: dnscache.c:228
#define WHO
Definition: dnscache.c:28
char seed[128]
Definition: dnscache.c:444
int main()
Definition: dnscache.c:446
int flagdualstack
Definition: dnscache.c:41
struct tcpclient t[QUERY_MAXTCP]
iopause_fd io[3+QUERY_MAXUDP+QUERY_MAXTCP]
Definition: dnscache.c:365
void t_rw(int j)
Definition: dnscache.c:250
int tactive
Definition: dnscache.c:193
int iolen
Definition: dnsfilter.c:52
struct line * x
char ipstr[IP6_FMT]
Definition: dnstrace.c:34
void droproot(const char *server)
Definition: droproot.c:7
unsigned int dns_packet_edns0(const char header[12], const char *buf, const int len, unsigned int pos)
Definition: edns0.c:22
void start(const char *s)
Definition: generic-conf.c:41
void d(const char *home, const char *subdir, int uid, int gid, int mode)
void log_tcpopen(const char[16], unsigned int)
Definition: log.c:151
void log_query(uint64 *, const char[16], unsigned int, const char[2], const char *, const char[2])
Definition: log.c:120
void log_querydrop(uint64 *)
Definition: log.c:135
void log_querydone(uint64 *, unsigned int)
Definition: log.c:129
void log_tcpclose(const char[16], unsigned int)
Definition: log.c:158
void log_startup(const char[16], uint32, const char[16], int, int[MAXOPT])
Definition: log.c:95
#define QUERY_MAXTCP
Definition: query.h:14
void query_init(void)
Definition: query.c:22
void query_io(struct query *, iopause_fd *, struct taia *)
Definition: query.c:1222
#define QUERY_MAXUDP
Definition: query.h:13
int query_start(struct query *, char *, char[2], char[2], char[16], uint32)
Definition: query.c:1193
int query_get(struct query *, iopause_fd *, struct taia *)
Definition: query.c:1211
void query_forwardonly(void)
Definition: query.c:35
void response_id(const char[2])
Definition: response.c:114
void response_hidettl(void)
Definition: response.c:70
char response[]
Definition: response.c:6
void response_tc(void)
Definition: response.c:119
unsigned int response_len
Definition: response.c:7
int roots_init(void)
Definition: roots.c:130
int cache_init(unsigned int)
Definition: sipcache.c:177
Definition: query.h:60
struct query q
Definition: dnscache.c:178
uint32 scope_id
Definition: dnscache.c:191
struct taia timeout
Definition: dnscache.c:180
char * buf
Definition: dnscache.c:188
uint16 port
Definition: dnscache.c:184
unsigned int len
Definition: dnscache.c:189
iopause_fd * io
Definition: dnscache.c:182
int state
Definition: dnscache.c:187
char ip[16]
Definition: dnscache.c:183
uint64 active
Definition: dnscache.c:181
unsigned int pos
Definition: dnscache.c:190
struct taia start
Definition: dnscache.c:179
int tcp
Definition: dnscache.c:186