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 
16 static int flagforwardonly = 0;
17 
query_forwardonly(void)18 void query_forwardonly(void)
19 {
20   flagforwardonly = 1;
21 }
22 
cachegeneric(const char type[2],const char * d,const char * data,unsigned int datalen,uint32 ttl)23 static 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 
38 static char save_buf[8192];
39 static unsigned int save_len;
40 static unsigned int save_ok;
41 
save_start(void)42 static void save_start(void)
43 {
44   save_len = 0;
45   save_ok = 1;
46 }
47 
save_data(const char * buf,unsigned int len)48 static 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 
save_finish(const char type[2],const char * d,uint32 ttl)56 static 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 
typematch(const char rtype[2],const char qtype[2])63 static 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 
ttlget(char buf[4])68 static 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 
cleanup(struct query * z)79 static 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 
rqa(struct query * z)94 static 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 
globalip(char * d,char ip[4])113 static 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 
123 static char *t1 = 0;
124 static char *t2 = 0;
125 static char *t3 = 0;
126 static char *cname = 0;
127 static char *referral = 0;
128 static unsigned int *records = 0;
129 
smaller(char * buf,unsigned int len,unsigned int pos1,unsigned int pos2)130 static 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 
doit(struct query * z,int state)160 static 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 == 500) 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 == 500) 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 
query_start(struct query * z,char * dn,char type[2],char class[2],char localip[4])821 int 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 
query_get(struct query * z,iopause_fd * x,struct taia * stamp)837 int 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 
query_io(struct query * z,iopause_fd * x,struct taia * deadline)848 void query_io(struct query *z,iopause_fd *x,struct taia *deadline)
849 {
850   dns_transmit_io(&z->dt,x,deadline);
851 }
852