Imported Upstream version 1.05
[hcoop/zz_old/debian/djbdns.git] / query.c
CommitLineData
dc0d77d7
CE
1#include "error.h"
2#include "roots.h"
3#include "log.h"
4#include "case.h"
5#include "cache.h"
6#include "byte.h"
7#include "dns.h"
8#include "uint64.h"
9#include "uint32.h"
10#include "uint16.h"
11#include "dd.h"
12#include "alloc.h"
13#include "response.h"
14#include "query.h"
15
16static int flagforwardonly = 0;
17
18void query_forwardonly(void)
19{
20 flagforwardonly = 1;
21}
22
23static void cachegeneric(const char type[2],const char *d,const char *data,unsigned int datalen,uint32 ttl)
24{
25 unsigned int len;
26 char key[257];
27
28 len = dns_domain_length(d);
29 if (len > 255) return;
30
31 byte_copy(key,2,type);
32 byte_copy(key + 2,len,d);
33 case_lowerb(key + 2,len);
34
35 cache_set(key,len + 2,data,datalen,ttl);
36}
37
38static char save_buf[8192];
39static unsigned int save_len;
40static unsigned int save_ok;
41
42static void save_start(void)
43{
44 save_len = 0;
45 save_ok = 1;
46}
47
48static void save_data(const char *buf,unsigned int len)
49{
50 if (!save_ok) return;
51 if (len > (sizeof save_buf) - save_len) { save_ok = 0; return; }
52 byte_copy(save_buf + save_len,len,buf);
53 save_len += len;
54}
55
56static void save_finish(const char type[2],const char *d,uint32 ttl)
57{
58 if (!save_ok) return;
59 cachegeneric(type,d,save_buf,save_len,ttl);
60}
61
62
63static int typematch(const char rtype[2],const char qtype[2])
64{
65 return byte_equal(qtype,2,rtype) || byte_equal(qtype,2,DNS_T_ANY);
66}
67
68static uint32 ttlget(char buf[4])
69{
70 uint32 ttl;
71
72 uint32_unpack_big(buf,&ttl);
73 if (ttl > 1000000000) return 0;
74 if (ttl > 604800) return 604800;
75 return ttl;
76}
77
78
79static void cleanup(struct query *z)
80{
81 int j;
82 int k;
83
84 dns_transmit_free(&z->dt);
85 for (j = 0;j < QUERY_MAXALIAS;++j)
86 dns_domain_free(&z->alias[j]);
87 for (j = 0;j < QUERY_MAXLEVEL;++j) {
88 dns_domain_free(&z->name[j]);
89 for (k = 0;k < QUERY_MAXNS;++k)
90 dns_domain_free(&z->ns[j][k]);
91 }
92}
93
94static int rqa(struct query *z)
95{
96 int i;
97
98 for (i = QUERY_MAXALIAS - 1;i >= 0;--i)
99 if (z->alias[i]) {
100 if (!response_query(z->alias[i],z->type,z->class)) return 0;
101 while (i > 0) {
102 if (!response_cname(z->alias[i],z->alias[i - 1],z->aliasttl[i])) return 0;
103 --i;
104 }
105 if (!response_cname(z->alias[0],z->name[0],z->aliasttl[0])) return 0;
106 return 1;
107 }
108
109 if (!response_query(z->name[0],z->type,z->class)) return 0;
110 return 1;
111}
112
113static int globalip(char *d,char ip[4])
114{
115 if (dns_domain_equal(d,"\011localhost\0")) {
116 byte_copy(ip,4,"\177\0\0\1");
117 return 1;
118 }
119 if (dd(d,"",ip) == 4) return 1;
120 return 0;
121}
122
123static char *t1 = 0;
124static char *t2 = 0;
125static char *t3 = 0;
126static char *cname = 0;
127static char *referral = 0;
128static unsigned int *records = 0;
129
130static int smaller(char *buf,unsigned int len,unsigned int pos1,unsigned int pos2)
131{
132 char header1[12];
133 char header2[12];
134 int r;
135 unsigned int len1;
136 unsigned int len2;
137
138 pos1 = dns_packet_getname(buf,len,pos1,&t1);
139 dns_packet_copy(buf,len,pos1,header1,10);
140 pos2 = dns_packet_getname(buf,len,pos2,&t2);
141 dns_packet_copy(buf,len,pos2,header2,10);
142
143 r = byte_diff(header1,4,header2);
144 if (r < 0) return 1;
145 if (r > 0) return 0;
146
147 len1 = dns_domain_length(t1);
148 len2 = dns_domain_length(t2);
149 if (len1 < len2) return 1;
150 if (len1 > len2) return 0;
151
152 r = case_diffb(t1,len1,t2);
153 if (r < 0) return 1;
154 if (r > 0) return 0;
155
156 if (pos1 < pos2) return 1;
157 return 0;
158}
159
160static int doit(struct query *z,int state)
161{
162 char key[257];
163 char *cached;
164 unsigned int cachedlen;
165 char *buf;
166 unsigned int len;
167 const char *whichserver;
168 char header[12];
169 char misc[20];
170 unsigned int rcode;
171 unsigned int posanswers;
172 uint16 numanswers;
173 unsigned int posauthority;
174 uint16 numauthority;
175 unsigned int posglue;
176 uint16 numglue;
177 unsigned int pos;
178 unsigned int pos2;
179 uint16 datalen;
180 char *control;
181 char *d;
182 const char *dtype;
183 unsigned int dlen;
184 int flagout;
185 int flagcname;
186 int flagreferral;
187 int flagsoa;
188 uint32 ttl;
189 uint32 soattl;
190 uint32 cnamettl;
191 int i;
192 int j;
193 int k;
194 int p;
195 int q;
196
197 errno = error_io;
198 if (state == 1) goto HAVEPACKET;
199 if (state == -1) {
200 log_servfail(z->name[z->level]);
201 goto SERVFAIL;
202 }
203
204
205 NEWNAME:
206 if (++z->loop == 100) goto DIE;
207 d = z->name[z->level];
208 dtype = z->level ? DNS_T_A : z->type;
209 dlen = dns_domain_length(d);
210
211 if (globalip(d,misc)) {
212 if (z->level) {
213 for (k = 0;k < 64;k += 4)
214 if (byte_equal(z->servers[z->level - 1] + k,4,"\0\0\0\0")) {
215 byte_copy(z->servers[z->level - 1] + k,4,misc);
216 break;
217 }
218 goto LOWERLEVEL;
219 }
220 if (!rqa(z)) goto DIE;
221 if (typematch(DNS_T_A,dtype)) {
222 if (!response_rstart(d,DNS_T_A,655360)) goto DIE;
223 if (!response_addbytes(misc,4)) goto DIE;
224 response_rfinish(RESPONSE_ANSWER);
225 }
226 cleanup(z);
227 return 1;
228 }
229
230 if (dns_domain_equal(d,"\0011\0010\0010\003127\7in-addr\4arpa\0")) {
231 if (z->level) goto LOWERLEVEL;
232 if (!rqa(z)) goto DIE;
233 if (typematch(DNS_T_PTR,dtype)) {
234 if (!response_rstart(d,DNS_T_PTR,655360)) goto DIE;
235 if (!response_addname("\011localhost\0")) goto DIE;
236 response_rfinish(RESPONSE_ANSWER);
237 }
238 cleanup(z);
239 log_stats();
240 return 1;
241 }
242
243 if (dlen <= 255) {
244 byte_copy(key,2,DNS_T_ANY);
245 byte_copy(key + 2,dlen,d);
246 case_lowerb(key + 2,dlen);
247 cached = cache_get(key,dlen + 2,&cachedlen,&ttl);
248 if (cached) {
249 log_cachednxdomain(d);
250 goto NXDOMAIN;
251 }
252
253 byte_copy(key,2,DNS_T_CNAME);
254 cached = cache_get(key,dlen + 2,&cachedlen,&ttl);
255 if (cached) {
256 if (typematch(DNS_T_CNAME,dtype)) {
257 log_cachedanswer(d,DNS_T_CNAME);
258 if (!rqa(z)) goto DIE;
259 if (!response_cname(z->name[0],cached,ttl)) goto DIE;
260 cleanup(z);
261 return 1;
262 }
263 log_cachedcname(d,cached);
264 if (!dns_domain_copy(&cname,cached)) goto DIE;
265 goto CNAME;
266 }
267
268 if (typematch(DNS_T_NS,dtype)) {
269 byte_copy(key,2,DNS_T_NS);
270 cached = cache_get(key,dlen + 2,&cachedlen,&ttl);
271 if (cached && (cachedlen || byte_diff(dtype,2,DNS_T_ANY))) {
272 log_cachedanswer(d,DNS_T_NS);
273 if (!rqa(z)) goto DIE;
274 pos = 0;
275 while (pos = dns_packet_getname(cached,cachedlen,pos,&t2)) {
276 if (!response_rstart(d,DNS_T_NS,ttl)) goto DIE;
277 if (!response_addname(t2)) goto DIE;
278 response_rfinish(RESPONSE_ANSWER);
279 }
280 cleanup(z);
281 return 1;
282 }
283 }
284
285 if (typematch(DNS_T_PTR,dtype)) {
286 byte_copy(key,2,DNS_T_PTR);
287 cached = cache_get(key,dlen + 2,&cachedlen,&ttl);
288 if (cached && (cachedlen || byte_diff(dtype,2,DNS_T_ANY))) {
289 log_cachedanswer(d,DNS_T_PTR);
290 if (!rqa(z)) goto DIE;
291 pos = 0;
292 while (pos = dns_packet_getname(cached,cachedlen,pos,&t2)) {
293 if (!response_rstart(d,DNS_T_PTR,ttl)) goto DIE;
294 if (!response_addname(t2)) goto DIE;
295 response_rfinish(RESPONSE_ANSWER);
296 }
297 cleanup(z);
298 return 1;
299 }
300 }
301
302 if (typematch(DNS_T_MX,dtype)) {
303 byte_copy(key,2,DNS_T_MX);
304 cached = cache_get(key,dlen + 2,&cachedlen,&ttl);
305 if (cached && (cachedlen || byte_diff(dtype,2,DNS_T_ANY))) {
306 log_cachedanswer(d,DNS_T_MX);
307 if (!rqa(z)) goto DIE;
308 pos = 0;
309 while (pos = dns_packet_copy(cached,cachedlen,pos,misc,2)) {
310 pos = dns_packet_getname(cached,cachedlen,pos,&t2);
311 if (!pos) break;
312 if (!response_rstart(d,DNS_T_MX,ttl)) goto DIE;
313 if (!response_addbytes(misc,2)) goto DIE;
314 if (!response_addname(t2)) goto DIE;
315 response_rfinish(RESPONSE_ANSWER);
316 }
317 cleanup(z);
318 return 1;
319 }
320 }
321
322 if (typematch(DNS_T_A,dtype)) {
323 byte_copy(key,2,DNS_T_A);
324 cached = cache_get(key,dlen + 2,&cachedlen,&ttl);
325 if (cached && (cachedlen || byte_diff(dtype,2,DNS_T_ANY))) {
326 if (z->level) {
327 log_cachedanswer(d,DNS_T_A);
328 while (cachedlen >= 4) {
329 for (k = 0;k < 64;k += 4)
330 if (byte_equal(z->servers[z->level - 1] + k,4,"\0\0\0\0")) {
331 byte_copy(z->servers[z->level - 1] + k,4,cached);
332 break;
333 }
334 cached += 4;
335 cachedlen -= 4;
336 }
337 goto LOWERLEVEL;
338 }
339
340 log_cachedanswer(d,DNS_T_A);
341 if (!rqa(z)) goto DIE;
342 while (cachedlen >= 4) {
343 if (!response_rstart(d,DNS_T_A,ttl)) goto DIE;
344 if (!response_addbytes(cached,4)) goto DIE;
345 response_rfinish(RESPONSE_ANSWER);
346 cached += 4;
347 cachedlen -= 4;
348 }
349 cleanup(z);
350 return 1;
351 }
352 }
353
354 if (!typematch(DNS_T_ANY,dtype) && !typematch(DNS_T_AXFR,dtype) && !typematch(DNS_T_CNAME,dtype) && !typematch(DNS_T_NS,dtype) && !typematch(DNS_T_PTR,dtype) && !typematch(DNS_T_A,dtype) && !typematch(DNS_T_MX,dtype)) {
355 byte_copy(key,2,dtype);
356 cached = cache_get(key,dlen + 2,&cachedlen,&ttl);
357 if (cached && (cachedlen || byte_diff(dtype,2,DNS_T_ANY))) {
358 log_cachedanswer(d,dtype);
359 if (!rqa(z)) goto DIE;
360 while (cachedlen >= 2) {
361 uint16_unpack_big(cached,&datalen);
362 cached += 2;
363 cachedlen -= 2;
364 if (datalen > cachedlen) goto DIE;
365 if (!response_rstart(d,dtype,ttl)) goto DIE;
366 if (!response_addbytes(cached,datalen)) goto DIE;
367 response_rfinish(RESPONSE_ANSWER);
368 cached += datalen;
369 cachedlen -= datalen;
370 }
371 cleanup(z);
372 return 1;
373 }
374 }
375 }
376
377 for (;;) {
378 if (roots(z->servers[z->level],d)) {
379 for (j = 0;j < QUERY_MAXNS;++j)
380 dns_domain_free(&z->ns[z->level][j]);
381 z->control[z->level] = d;
382 break;
383 }
384
385 if (!flagforwardonly && (z->level < 2))
386 if (dlen < 255) {
387 byte_copy(key,2,DNS_T_NS);
388 byte_copy(key + 2,dlen,d);
389 case_lowerb(key + 2,dlen);
390 cached = cache_get(key,dlen + 2,&cachedlen,&ttl);
391 if (cached && cachedlen) {
392 z->control[z->level] = d;
393 byte_zero(z->servers[z->level],64);
394 for (j = 0;j < QUERY_MAXNS;++j)
395 dns_domain_free(&z->ns[z->level][j]);
396 pos = 0;
397 j = 0;
398 while (pos = dns_packet_getname(cached,cachedlen,pos,&t1)) {
399 log_cachedns(d,t1);
400 if (j < QUERY_MAXNS)
401 if (!dns_domain_copy(&z->ns[z->level][j++],t1)) goto DIE;
402 }
403 break;
404 }
405 }
406
407 if (!*d) goto DIE;
408 j = 1 + (unsigned int) (unsigned char) *d;
409 dlen -= j;
410 d += j;
411 }
412
413
414 HAVENS:
415 for (j = 0;j < QUERY_MAXNS;++j)
416 if (z->ns[z->level][j]) {
417 if (z->level + 1 < QUERY_MAXLEVEL) {
418 if (!dns_domain_copy(&z->name[z->level + 1],z->ns[z->level][j])) goto DIE;
419 dns_domain_free(&z->ns[z->level][j]);
420 ++z->level;
421 goto NEWNAME;
422 }
423 dns_domain_free(&z->ns[z->level][j]);
424 }
425
426 for (j = 0;j < 64;j += 4)
427 if (byte_diff(z->servers[z->level] + j,4,"\0\0\0\0"))
428 break;
429 if (j == 64) goto SERVFAIL;
430
431 dns_sortip(z->servers[z->level],64);
432 if (z->level) {
433 log_tx(z->name[z->level],DNS_T_A,z->control[z->level],z->servers[z->level],z->level);
434 if (dns_transmit_start(&z->dt,z->servers[z->level],flagforwardonly,z->name[z->level],DNS_T_A,z->localip) == -1) goto DIE;
435 }
436 else {
437 log_tx(z->name[0],z->type,z->control[0],z->servers[0],0);
438 if (dns_transmit_start(&z->dt,z->servers[0],flagforwardonly,z->name[0],z->type,z->localip) == -1) goto DIE;
439 }
440 return 0;
441
442
443 LOWERLEVEL:
444 dns_domain_free(&z->name[z->level]);
445 for (j = 0;j < QUERY_MAXNS;++j)
446 dns_domain_free(&z->ns[z->level][j]);
447 --z->level;
448 goto HAVENS;
449
450
451 HAVEPACKET:
452 if (++z->loop == 100) goto DIE;
453 buf = z->dt.packet;
454 len = z->dt.packetlen;
455
456 whichserver = z->dt.servers + 4 * z->dt.curserver;
457 control = z->control[z->level];
458 d = z->name[z->level];
459 dtype = z->level ? DNS_T_A : z->type;
460
461 pos = dns_packet_copy(buf,len,0,header,12); if (!pos) goto DIE;
462 pos = dns_packet_skipname(buf,len,pos); if (!pos) goto DIE;
463 pos += 4;
464 posanswers = pos;
465
466 uint16_unpack_big(header + 6,&numanswers);
467 uint16_unpack_big(header + 8,&numauthority);
468 uint16_unpack_big(header + 10,&numglue);
469
470 rcode = header[3] & 15;
471 if (rcode && (rcode != 3)) goto DIE; /* impossible; see irrelevant() */
472
473 flagout = 0;
474 flagcname = 0;
475 flagreferral = 0;
476 flagsoa = 0;
477 soattl = 0;
478 cnamettl = 0;
479 for (j = 0;j < numanswers;++j) {
480 pos = dns_packet_getname(buf,len,pos,&t1); if (!pos) goto DIE;
481 pos = dns_packet_copy(buf,len,pos,header,10); if (!pos) goto DIE;
482
483 if (dns_domain_equal(t1,d))
484 if (byte_equal(header + 2,2,DNS_C_IN)) { /* should always be true */
485 if (typematch(header,dtype))
486 flagout = 1;
487 else if (typematch(header,DNS_T_CNAME)) {
488 if (!dns_packet_getname(buf,len,pos,&cname)) goto DIE;
489 flagcname = 1;
490 cnamettl = ttlget(header + 4);
491 }
492 }
493
494 uint16_unpack_big(header + 8,&datalen);
495 pos += datalen;
496 }
497 posauthority = pos;
498
499 for (j = 0;j < numauthority;++j) {
500 pos = dns_packet_getname(buf,len,pos,&t1); if (!pos) goto DIE;
501 pos = dns_packet_copy(buf,len,pos,header,10); if (!pos) goto DIE;
502
503 if (typematch(header,DNS_T_SOA)) {
504 flagsoa = 1;
505 soattl = ttlget(header + 4);
506 if (soattl > 3600) soattl = 3600;
507 }
508 else if (typematch(header,DNS_T_NS)) {
509 flagreferral = 1;
510 if (!dns_domain_copy(&referral,t1)) goto DIE;
511 }
512
513 uint16_unpack_big(header + 8,&datalen);
514 pos += datalen;
515 }
516 posglue = pos;
517
518
519 if (!flagcname && !rcode && !flagout && flagreferral && !flagsoa)
520 if (dns_domain_equal(referral,control) || !dns_domain_suffix(referral,control)) {
521 log_lame(whichserver,control,referral);
522 byte_zero(whichserver,4);
523 goto HAVENS;
524 }
525
526
527 if (records) { alloc_free(records); records = 0; }
528
529 k = numanswers + numauthority + numglue;
530 records = (unsigned int *) alloc(k * sizeof(unsigned int));
531 if (!records) goto DIE;
532
533 pos = posanswers;
534 for (j = 0;j < k;++j) {
535 records[j] = pos;
536 pos = dns_packet_getname(buf,len,pos,&t1); if (!pos) goto DIE;
537 pos = dns_packet_copy(buf,len,pos,header,10); if (!pos) goto DIE;
538 uint16_unpack_big(header + 8,&datalen);
539 pos += datalen;
540 }
541
542 i = j = k;
543 while (j > 1) {
544 if (i > 1) { --i; pos = records[i - 1]; }
545 else { pos = records[j - 1]; records[j - 1] = records[i - 1]; --j; }
546
547 q = i;
548 while ((p = q * 2) < j) {
549 if (!smaller(buf,len,records[p],records[p - 1])) ++p;
550 records[q - 1] = records[p - 1]; q = p;
551 }
552 if (p == j) {
553 records[q - 1] = records[p - 1]; q = p;
554 }
555 while ((q > i) && smaller(buf,len,records[(p = q/2) - 1],pos)) {
556 records[q - 1] = records[p - 1]; q = p;
557 }
558 records[q - 1] = pos;
559 }
560
561 i = 0;
562 while (i < k) {
563 char type[2];
564
565 pos = dns_packet_getname(buf,len,records[i],&t1); if (!pos) goto DIE;
566 pos = dns_packet_copy(buf,len,pos,header,10); if (!pos) goto DIE;
567 ttl = ttlget(header + 4);
568
569 byte_copy(type,2,header);
570 if (byte_diff(header + 2,2,DNS_C_IN)) { ++i; continue; }
571
572 for (j = i + 1;j < k;++j) {
573 pos = dns_packet_getname(buf,len,records[j],&t2); if (!pos) goto DIE;
574 pos = dns_packet_copy(buf,len,pos,header,10); if (!pos) goto DIE;
575 if (!dns_domain_equal(t1,t2)) break;
576 if (byte_diff(header,2,type)) break;
577 if (byte_diff(header + 2,2,DNS_C_IN)) break;
578 }
579
580 if (!dns_domain_suffix(t1,control)) { i = j; continue; }
581 if (!roots_same(t1,control)) { i = j; continue; }
582
583 if (byte_equal(type,2,DNS_T_ANY))
584 ;
585 else if (byte_equal(type,2,DNS_T_AXFR))
586 ;
587 else if (byte_equal(type,2,DNS_T_SOA)) {
588 while (i < j) {
589 pos = dns_packet_skipname(buf,len,records[i]); if (!pos) goto DIE;
590 pos = dns_packet_getname(buf,len,pos + 10,&t2); if (!pos) goto DIE;
591 pos = dns_packet_getname(buf,len,pos,&t3); if (!pos) goto DIE;
592 pos = dns_packet_copy(buf,len,pos,misc,20); if (!pos) goto DIE;
593 if (records[i] < posauthority)
594 log_rrsoa(whichserver,t1,t2,t3,misc,ttl);
595 ++i;
596 }
597 }
598 else if (byte_equal(type,2,DNS_T_CNAME)) {
599 pos = dns_packet_skipname(buf,len,records[j - 1]); if (!pos) goto DIE;
600 pos = dns_packet_getname(buf,len,pos + 10,&t2); if (!pos) goto DIE;
601 log_rrcname(whichserver,t1,t2,ttl);
602 cachegeneric(DNS_T_CNAME,t1,t2,dns_domain_length(t2),ttl);
603 }
604 else if (byte_equal(type,2,DNS_T_PTR)) {
605 save_start();
606 while (i < j) {
607 pos = dns_packet_skipname(buf,len,records[i]); if (!pos) goto DIE;
608 pos = dns_packet_getname(buf,len,pos + 10,&t2); if (!pos) goto DIE;
609 log_rrptr(whichserver,t1,t2,ttl);
610 save_data(t2,dns_domain_length(t2));
611 ++i;
612 }
613 save_finish(DNS_T_PTR,t1,ttl);
614 }
615 else if (byte_equal(type,2,DNS_T_NS)) {
616 save_start();
617 while (i < j) {
618 pos = dns_packet_skipname(buf,len,records[i]); if (!pos) goto DIE;
619 pos = dns_packet_getname(buf,len,pos + 10,&t2); if (!pos) goto DIE;
620 log_rrns(whichserver,t1,t2,ttl);
621 save_data(t2,dns_domain_length(t2));
622 ++i;
623 }
624 save_finish(DNS_T_NS,t1,ttl);
625 }
626 else if (byte_equal(type,2,DNS_T_MX)) {
627 save_start();
628 while (i < j) {
629 pos = dns_packet_skipname(buf,len,records[i]); if (!pos) goto DIE;
630 pos = dns_packet_copy(buf,len,pos + 10,misc,2); if (!pos) goto DIE;
631 pos = dns_packet_getname(buf,len,pos,&t2); if (!pos) goto DIE;
632 log_rrmx(whichserver,t1,t2,misc,ttl);
633 save_data(misc,2);
634 save_data(t2,dns_domain_length(t2));
635 ++i;
636 }
637 save_finish(DNS_T_MX,t1,ttl);
638 }
639 else if (byte_equal(type,2,DNS_T_A)) {
640 save_start();
641 while (i < j) {
642 pos = dns_packet_skipname(buf,len,records[i]); if (!pos) goto DIE;
643 pos = dns_packet_copy(buf,len,pos,header,10); if (!pos) goto DIE;
644 if (byte_equal(header + 8,2,"\0\4")) {
645 pos = dns_packet_copy(buf,len,pos,header,4); if (!pos) goto DIE;
646 save_data(header,4);
647 log_rr(whichserver,t1,DNS_T_A,header,4,ttl);
648 }
649 ++i;
650 }
651 save_finish(DNS_T_A,t1,ttl);
652 }
653 else {
654 save_start();
655 while (i < j) {
656 pos = dns_packet_skipname(buf,len,records[i]); if (!pos) goto DIE;
657 pos = dns_packet_copy(buf,len,pos,header,10); if (!pos) goto DIE;
658 uint16_unpack_big(header + 8,&datalen);
659 if (datalen > len - pos) goto DIE;
660 save_data(header + 8,2);
661 save_data(buf + pos,datalen);
662 log_rr(whichserver,t1,type,buf + pos,datalen,ttl);
663 ++i;
664 }
665 save_finish(type,t1,ttl);
666 }
667
668 i = j;
669 }
670
671 alloc_free(records); records = 0;
672
673
674 if (flagcname) {
675 ttl = cnamettl;
676 CNAME:
677 if (!z->level) {
678 if (z->alias[QUERY_MAXALIAS - 1]) goto DIE;
679 for (j = QUERY_MAXALIAS - 1;j > 0;--j)
680 z->alias[j] = z->alias[j - 1];
681 for (j = QUERY_MAXALIAS - 1;j > 0;--j)
682 z->aliasttl[j] = z->aliasttl[j - 1];
683 z->alias[0] = z->name[0];
684 z->aliasttl[0] = ttl;
685 z->name[0] = 0;
686 }
687 if (!dns_domain_copy(&z->name[z->level],cname)) goto DIE;
688 goto NEWNAME;
689 }
690
691 if (rcode == 3) {
692 log_nxdomain(whichserver,d,soattl);
693 cachegeneric(DNS_T_ANY,d,"",0,soattl);
694
695 NXDOMAIN:
696 if (z->level) goto LOWERLEVEL;
697 if (!rqa(z)) goto DIE;
698 response_nxdomain();
699 cleanup(z);
700 return 1;
701 }
702
703 if (!flagout && flagsoa)
704 if (byte_diff(DNS_T_ANY,2,dtype))
705 if (byte_diff(DNS_T_AXFR,2,dtype))
706 if (byte_diff(DNS_T_CNAME,2,dtype)) {
707 save_start();
708 save_finish(dtype,d,soattl);
709 log_nodata(whichserver,d,dtype,soattl);
710 }
711
712 log_stats();
713
714
715 if (flagout || flagsoa || !flagreferral) {
716 if (z->level) {
717 pos = posanswers;
718 for (j = 0;j < numanswers;++j) {
719 pos = dns_packet_getname(buf,len,pos,&t1); if (!pos) goto DIE;
720 pos = dns_packet_copy(buf,len,pos,header,10); if (!pos) goto DIE;
721 uint16_unpack_big(header + 8,&datalen);
722 if (dns_domain_equal(t1,d))
723 if (typematch(header,DNS_T_A))
724 if (byte_equal(header + 2,2,DNS_C_IN)) /* should always be true */
725 if (datalen == 4)
726 for (k = 0;k < 64;k += 4)
727 if (byte_equal(z->servers[z->level - 1] + k,4,"\0\0\0\0")) {
728 if (!dns_packet_copy(buf,len,pos,z->servers[z->level - 1] + k,4)) goto DIE;
729 break;
730 }
731 pos += datalen;
732 }
733 goto LOWERLEVEL;
734 }
735
736 if (!rqa(z)) goto DIE;
737
738 pos = posanswers;
739 for (j = 0;j < numanswers;++j) {
740 pos = dns_packet_getname(buf,len,pos,&t1); if (!pos) goto DIE;
741 pos = dns_packet_copy(buf,len,pos,header,10); if (!pos) goto DIE;
742 ttl = ttlget(header + 4);
743 uint16_unpack_big(header + 8,&datalen);
744 if (dns_domain_equal(t1,d))
745 if (byte_equal(header + 2,2,DNS_C_IN)) /* should always be true */
746 if (typematch(header,dtype)) {
747 if (!response_rstart(t1,header,ttl)) goto DIE;
748
749 if (typematch(header,DNS_T_NS) || typematch(header,DNS_T_CNAME) || typematch(header,DNS_T_PTR)) {
750 if (!dns_packet_getname(buf,len,pos,&t2)) goto DIE;
751 if (!response_addname(t2)) goto DIE;
752 }
753 else if (typematch(header,DNS_T_MX)) {
754 pos2 = dns_packet_copy(buf,len,pos,misc,2); if (!pos2) goto DIE;
755 if (!response_addbytes(misc,2)) goto DIE;
756 if (!dns_packet_getname(buf,len,pos2,&t2)) goto DIE;
757 if (!response_addname(t2)) goto DIE;
758 }
759 else if (typematch(header,DNS_T_SOA)) {
760 pos2 = dns_packet_getname(buf,len,pos,&t2); if (!pos2) goto DIE;
761 if (!response_addname(t2)) goto DIE;
762 pos2 = dns_packet_getname(buf,len,pos2,&t3); if (!pos2) goto DIE;
763 if (!response_addname(t3)) goto DIE;
764 pos2 = dns_packet_copy(buf,len,pos2,misc,20); if (!pos2) goto DIE;
765 if (!response_addbytes(misc,20)) goto DIE;
766 }
767 else {
768 if (pos + datalen > len) goto DIE;
769 if (!response_addbytes(buf + pos,datalen)) goto DIE;
770 }
771
772 response_rfinish(RESPONSE_ANSWER);
773 }
774
775 pos += datalen;
776 }
777
778 cleanup(z);
779 return 1;
780 }
781
782
783 if (!dns_domain_suffix(d,referral)) goto DIE;
784 control = d + dns_domain_suffixpos(d,referral);
785 z->control[z->level] = control;
786 byte_zero(z->servers[z->level],64);
787 for (j = 0;j < QUERY_MAXNS;++j)
788 dns_domain_free(&z->ns[z->level][j]);
789 k = 0;
790
791 pos = posauthority;
792 for (j = 0;j < numauthority;++j) {
793 pos = dns_packet_getname(buf,len,pos,&t1); if (!pos) goto DIE;
794 pos = dns_packet_copy(buf,len,pos,header,10); if (!pos) goto DIE;
795 uint16_unpack_big(header + 8,&datalen);
796 if (dns_domain_equal(referral,t1)) /* should always be true */
797 if (typematch(header,DNS_T_NS)) /* should always be true */
798 if (byte_equal(header + 2,2,DNS_C_IN)) /* should always be true */
799 if (k < QUERY_MAXNS)
800 if (!dns_packet_getname(buf,len,pos,&z->ns[z->level][k++])) goto DIE;
801 pos += datalen;
802 }
803
804 goto HAVENS;
805
806
807 SERVFAIL:
808 if (z->level) goto LOWERLEVEL;
809 if (!rqa(z)) goto DIE;
810 response_servfail();
811 cleanup(z);
812 return 1;
813
814
815 DIE:
816 cleanup(z);
817 if (records) { alloc_free(records); records = 0; }
818 return -1;
819}
820
821int query_start(struct query *z,char *dn,char type[2],char class[2],char localip[4])
822{
823 if (byte_equal(type,2,DNS_T_AXFR)) { errno = error_perm; return -1; }
824
825 cleanup(z);
826 z->level = 0;
827 z->loop = 0;
828
829 if (!dns_domain_copy(&z->name[0],dn)) return -1;
830 byte_copy(z->type,2,type);
831 byte_copy(z->class,2,class);
832 byte_copy(z->localip,4,localip);
833
834 return doit(z,0);
835}
836
837int query_get(struct query *z,iopause_fd *x,struct taia *stamp)
838{
839 switch(dns_transmit_get(&z->dt,x,stamp)) {
840 case 1:
841 return doit(z,1);
842 case -1:
843 return doit(z,-1);
844 }
845 return 0;
846}
847
848void query_io(struct query *z,iopause_fd *x,struct taia *deadline)
849{
850 dns_transmit_io(&z->dt,x,deadline);
851}