release
[hcoop/zz_old/debian/djbdns.git] / dnscache.c
CommitLineData
dc0d77d7
CE
1#include <unistd.h>
2#include "env.h"
3#include "exit.h"
4#include "scan.h"
5#include "strerr.h"
6#include "error.h"
7#include "ip4.h"
8#include "uint16.h"
9#include "uint64.h"
10#include "socket.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 "cache.h"
21#include "ndelay.h"
22#include "log.h"
23#include "okclient.h"
24#include "droproot.h"
25
26static int packetquery(char *buf,unsigned int len,char **q,char qtype[2],char qclass[2],char id[2])
27{
28 unsigned int pos;
29 char header[12];
30
31 errno = error_proto;
32 pos = dns_packet_copy(buf,len,0,header,12); if (!pos) return 0;
33 if (header[2] & 128) return 0; /* must not respond to responses */
34 if (!(header[2] & 1)) return 0; /* do not respond to non-recursive queries */
35 if (header[2] & 120) return 0;
36 if (header[2] & 2) return 0;
37 if (byte_diff(header + 4,2,"\0\1")) return 0;
38
39 pos = dns_packet_getname(buf,len,pos,q); if (!pos) return 0;
40 pos = dns_packet_copy(buf,len,pos,qtype,2); if (!pos) return 0;
41 pos = dns_packet_copy(buf,len,pos,qclass,2); if (!pos) return 0;
42 if (byte_diff(qclass,2,DNS_C_IN) && byte_diff(qclass,2,DNS_C_ANY)) return 0;
43
44 byte_copy(id,2,header);
45 return 1;
46}
47
48
49static char myipoutgoing[4];
50static char myipincoming[4];
51static char buf[1024];
52uint64 numqueries = 0;
53
54
55static int udp53;
56
57#define MAXUDP 200
58static struct udpclient {
59 struct query q;
60 struct taia start;
61 uint64 active; /* query number, if active; otherwise 0 */
62 iopause_fd *io;
63 char ip[4];
64 uint16 port;
65 char id[2];
66} u[MAXUDP];
67int uactive = 0;
68
69void u_drop(int j)
70{
71 if (!u[j].active) return;
72 log_querydrop(&u[j].active);
73 u[j].active = 0; --uactive;
74}
75
76void u_respond(int j)
77{
78 if (!u[j].active) return;
79 response_id(u[j].id);
80 if (response_len > 512) response_tc();
81 socket_send4(udp53,response,response_len,u[j].ip,u[j].port);
82 log_querydone(&u[j].active,response_len);
83 u[j].active = 0; --uactive;
84}
85
86void u_new(void)
87{
88 int j;
89 int i;
90 struct udpclient *x;
91 int len;
92 static char *q = 0;
93 char qtype[2];
94 char qclass[2];
95
96 for (j = 0;j < MAXUDP;++j)
97 if (!u[j].active)
98 break;
99
100 if (j >= MAXUDP) {
101 j = 0;
102 for (i = 1;i < MAXUDP;++i)
103 if (taia_less(&u[i].start,&u[j].start))
104 j = i;
105 errno = error_timeout;
106 u_drop(j);
107 }
108
109 x = u + j;
110 taia_now(&x->start);
111
112 len = socket_recv4(udp53,buf,sizeof buf,x->ip,&x->port);
113 if (len == -1) return;
114 if (len >= sizeof buf) return;
115 if (x->port < 1024) if (x->port != 53) return;
116 if (!okclient(x->ip)) return;
117
118 if (!packetquery(buf,len,&q,qtype,qclass,x->id)) return;
119
120 x->active = ++numqueries; ++uactive;
121 log_query(&x->active,x->ip,x->port,x->id,q,qtype);
122 switch(query_start(&x->q,q,qtype,qclass,myipoutgoing)) {
123 case -1:
124 u_drop(j);
125 return;
126 case 1:
127 u_respond(j);
128 }
129}
130
131
132static int tcp53;
133
134#define MAXTCP 20
135struct tcpclient {
136 struct query q;
137 struct taia start;
138 struct taia timeout;
139 uint64 active; /* query number or 1, if active; otherwise 0 */
140 iopause_fd *io;
141 char ip[4]; /* send response to this address */
142 uint16 port; /* send response to this port */
143 char id[2];
144 int tcp; /* open TCP socket, if active */
145 int state;
146 char *buf; /* 0, or dynamically allocated of length len */
147 unsigned int len;
148 unsigned int pos;
149} t[MAXTCP];
150int tactive = 0;
151
152/*
153state 1: buf 0; normal state at beginning of TCP connection
154state 2: buf 0; have read 1 byte of query packet length into len
155state 3: buf allocated; have read pos bytes of buf
156state 0: buf 0; handling query in q
157state -1: buf allocated; have written pos bytes
158*/
159
160void t_free(int j)
161{
162 if (!t[j].buf) return;
163 alloc_free(t[j].buf);
164 t[j].buf = 0;
165}
166
167void t_timeout(int j)
168{
169 struct taia now;
170 if (!t[j].active) return;
171 taia_now(&now);
172 taia_uint(&t[j].timeout,10);
173 taia_add(&t[j].timeout,&t[j].timeout,&now);
174}
175
176void t_close(int j)
177{
178 if (!t[j].active) return;
179 t_free(j);
180 log_tcpclose(t[j].ip,t[j].port);
181 close(t[j].tcp);
182 t[j].active = 0; --tactive;
183}
184
185void t_drop(int j)
186{
187 log_querydrop(&t[j].active);
188 errno = error_pipe;
189 t_close(j);
190}
191
192void t_respond(int j)
193{
194 if (!t[j].active) return;
195 log_querydone(&t[j].active,response_len);
196 response_id(t[j].id);
197 t[j].len = response_len + 2;
198 t_free(j);
199 t[j].buf = alloc(response_len + 2);
200 if (!t[j].buf) { t_close(j); return; }
201 uint16_pack_big(t[j].buf,response_len);
202 byte_copy(t[j].buf + 2,response_len,response);
203 t[j].pos = 0;
204 t[j].state = -1;
205}
206
207void t_rw(int j)
208{
209 struct tcpclient *x;
210 char ch;
211 static char *q = 0;
212 char qtype[2];
213 char qclass[2];
214 int r;
215
216 x = t + j;
217 if (x->state == -1) {
218 r = write(x->tcp,x->buf + x->pos,x->len - x->pos);
219 if (r <= 0) { t_close(j); return; }
220 x->pos += r;
221 if (x->pos == x->len) {
222 t_free(j);
223 x->state = 1; /* could drop connection immediately */
224 }
225 return;
226 }
227
228 r = read(x->tcp,&ch,1);
229 if (r == 0) { errno = error_pipe; t_close(j); return; }
230 if (r < 0) { t_close(j); return; }
231
232 if (x->state == 1) {
233 x->len = (unsigned char) ch;
234 x->len <<= 8;
235 x->state = 2;
236 return;
237 }
238 if (x->state == 2) {
239 x->len += (unsigned char) ch;
240 if (!x->len) { errno = error_proto; t_close(j); return; }
241 x->buf = alloc(x->len);
242 if (!x->buf) { t_close(j); return; }
243 x->pos = 0;
244 x->state = 3;
245 return;
246 }
247
248 if (x->state != 3) return; /* impossible */
249
250 x->buf[x->pos++] = ch;
251 if (x->pos < x->len) return;
252
253 if (!packetquery(x->buf,x->len,&q,qtype,qclass,x->id)) { t_close(j); return; }
254
255 x->active = ++numqueries;
256 log_query(&x->active,x->ip,x->port,x->id,q,qtype);
257 switch(query_start(&x->q,q,qtype,qclass,myipoutgoing)) {
258 case -1:
259 t_drop(j);
260 return;
261 case 1:
262 t_respond(j);
263 return;
264 }
265 t_free(j);
266 x->state = 0;
267}
268
269void t_new(void)
270{
271 int i;
272 int j;
273 struct tcpclient *x;
274
275 for (j = 0;j < MAXTCP;++j)
276 if (!t[j].active)
277 break;
278
279 if (j >= MAXTCP) {
280 j = 0;
281 for (i = 1;i < MAXTCP;++i)
282 if (taia_less(&t[i].start,&t[j].start))
283 j = i;
284 errno = error_timeout;
285 if (t[j].state == 0)
286 t_drop(j);
287 else
288 t_close(j);
289 }
290
291 x = t + j;
292 taia_now(&x->start);
293
294 x->tcp = socket_accept4(tcp53,x->ip,&x->port);
295 if (x->tcp == -1) return;
296 if (x->port < 1024) if (x->port != 53) { close(x->tcp); return; }
297 if (!okclient(x->ip)) { close(x->tcp); return; }
298 if (ndelay_on(x->tcp) == -1) { close(x->tcp); return; } /* Linux bug */
299
300 x->active = 1; ++tactive;
301 x->state = 1;
302 t_timeout(j);
303
304 log_tcpopen(x->ip,x->port);
305}
306
307
308iopause_fd io[3 + MAXUDP + MAXTCP];
309iopause_fd *udp53io;
310iopause_fd *tcp53io;
311
312static void doit(void)
313{
314 int j;
315 struct taia deadline;
316 struct taia stamp;
317 int iolen;
318 int r;
319
320 for (;;) {
321 taia_now(&stamp);
322 taia_uint(&deadline,120);
323 taia_add(&deadline,&deadline,&stamp);
324
325 iolen = 0;
326
327 udp53io = io + iolen++;
328 udp53io->fd = udp53;
329 udp53io->events = IOPAUSE_READ;
330
331 tcp53io = io + iolen++;
332 tcp53io->fd = tcp53;
333 tcp53io->events = IOPAUSE_READ;
334
335 for (j = 0;j < MAXUDP;++j)
336 if (u[j].active) {
337 u[j].io = io + iolen++;
338 query_io(&u[j].q,u[j].io,&deadline);
339 }
340 for (j = 0;j < MAXTCP;++j)
341 if (t[j].active) {
342 t[j].io = io + iolen++;
343 if (t[j].state == 0)
344 query_io(&t[j].q,t[j].io,&deadline);
345 else {
346 if (taia_less(&t[j].timeout,&deadline)) deadline = t[j].timeout;
347 t[j].io->fd = t[j].tcp;
348 t[j].io->events = (t[j].state > 0) ? IOPAUSE_READ : IOPAUSE_WRITE;
349 }
350 }
351
352 iopause(io,iolen,&deadline,&stamp);
353
354 for (j = 0;j < MAXUDP;++j)
355 if (u[j].active) {
356 r = query_get(&u[j].q,u[j].io,&stamp);
357 if (r == -1) u_drop(j);
358 if (r == 1) u_respond(j);
359 }
360
361 for (j = 0;j < MAXTCP;++j)
362 if (t[j].active) {
363 if (t[j].io->revents)
364 t_timeout(j);
365 if (t[j].state == 0) {
366 r = query_get(&t[j].q,t[j].io,&stamp);
367 if (r == -1) t_drop(j);
368 if (r == 1) t_respond(j);
369 }
370 else
371 if (t[j].io->revents || taia_less(&t[j].timeout,&stamp))
372 t_rw(j);
373 }
374
375 if (udp53io)
376 if (udp53io->revents)
377 u_new();
378
379 if (tcp53io)
380 if (tcp53io->revents)
381 t_new();
382 }
383}
384
385#define FATAL "dnscache: fatal: "
386
387char seed[128];
388
389int main()
390{
391 char *x;
392 unsigned long cachesize;
393
394 x = env_get("IP");
395 if (!x)
396 strerr_die2x(111,FATAL,"$IP not set");
397 if (!ip4_scan(x,myipincoming))
398 strerr_die3x(111,FATAL,"unable to parse IP address ",x);
399
400 udp53 = socket_udp();
401 if (udp53 == -1)
402 strerr_die2sys(111,FATAL,"unable to create UDP socket: ");
403 if (socket_bind4_reuse(udp53,myipincoming,53) == -1)
404 strerr_die2sys(111,FATAL,"unable to bind UDP socket: ");
405
406 tcp53 = socket_tcp();
407 if (tcp53 == -1)
408 strerr_die2sys(111,FATAL,"unable to create TCP socket: ");
409 if (socket_bind4_reuse(tcp53,myipincoming,53) == -1)
410 strerr_die2sys(111,FATAL,"unable to bind TCP socket: ");
411
412 droproot(FATAL);
413
414 socket_tryreservein(udp53,131072);
415
416 byte_zero(seed,sizeof seed);
417 read(0,seed,sizeof seed);
418 dns_random_init(seed);
419 close(0);
420
421 x = env_get("IPSEND");
422 if (!x)
423 strerr_die2x(111,FATAL,"$IPSEND not set");
424 if (!ip4_scan(x,myipoutgoing))
425 strerr_die3x(111,FATAL,"unable to parse IP address ",x);
426
427 x = env_get("CACHESIZE");
428 if (!x)
429 strerr_die2x(111,FATAL,"$CACHESIZE not set");
430 scan_ulong(x,&cachesize);
431 if (!cache_init(cachesize))
432 strerr_die3x(111,FATAL,"not enough memory for cache of size ",x);
433
434 if (env_get("HIDETTL"))
435 response_hidettl();
436 if (env_get("FORWARDONLY"))
437 query_forwardonly();
438
439 if (!roots_init())
440 strerr_die2sys(111,FATAL,"unable to read servers: ");
441
442 if (socket_listen(tcp53,20) == -1)
443 strerr_die2sys(111,FATAL,"unable to listen on TCP socket: ");
444
445 log_startup();
446 doit();
447}