djbdnscurve6  38
djbdnscurve6
dnstrace.c
Go to the documentation of this file.
1 #include "uint_t.h"
2 #include "fmt.h"
3 #include "str.h"
4 #include "byte.h"
5 #include "ip.h"
6 #include "exit.h"
7 #include "buffer.h"
8 #include "genalloc.h"
9 #include "stralloc.h"
10 #include "scan.h"
11 #include "logmsg.h"
12 #include "iopause.h"
13 #include "printrecord.h"
14 #include "alloc.h"
15 #include "parsetype.h"
16 #include "dd.h"
17 #include "dns.h"
18 
19 #define WHO "dnstrace"
20 
21 void nomem(void)
22 {
23  logmsg(WHO,111,FATAL,"out of memory");
24 }
25 void usage(void)
26 {
27  logmsg(WHO,100,USAGE,"dnstrace type name rootip ...");
28 }
29 
30 static stralloc querystr;
31 char ipstr[IP6_FMT];
32 static stralloc tmp;
33 
34 void printdomain(const char *d)
35 {
36  if (!stralloc_copys(&tmp,"")) nomem();
37  if (dns_domain_todot_cat(&tmp,d) <= 0) nomem();
38  buffer_put(buffer_1,tmp.s,tmp.len);
39 }
40 
41 static struct dns_transmit tx;
42 
43 int resolve(char *q,char qtype[2],char ip[16])
44 {
45  struct taia start;
46  struct taia stamp;
47  struct taia deadline;
48  char servers[QUERY_MAXIPLEN];
49  iopause_fd x[1];
50  int r;
51 
52  taia_now(&start);
53 
54  byte_zero(servers,QUERY_MAXIPLEN);
55  byte_copy(servers,16,ip);
56 
57  if (dns_transmit_start(&tx,servers,0,q,qtype,V6localnet) < 0) return DNS_COM;
58 
59  for (;;) {
60  taia_now(&stamp);
61  taia_uint(&deadline,120);
62  taia_add(&deadline,&deadline,&stamp);
63  dns_transmit_io(&tx,x,&deadline);
64  r = iopause(x,1,&deadline,&stamp);
65  r = dns_transmit_get(&tx,x,&stamp);
66  if (r < 0) return DNS_ERR;
67  if (r == 1) break;
68  }
69 
70  taia_now(&stamp);
71  taia_sub(&stamp,&stamp,&start);
72  taia_uint(&deadline,1);
73  if (taia_less(&deadline,&stamp)) {
74  buffer_put(buffer_1,querystr.s,querystr.len);
75  buffer_puts(buffer_1,"ALERT|took more than 1 second\n");
76  }
77 
78  return 0;
79 }
80 
81 struct address {
82  char *owner;
83  char ip[16];
84 } ;
85 
86 GEN_ALLOC_typedef(address_alloc,struct address,s,len,a)
87 GEN_ALLOC_readyplus(address_alloc,struct address,s,len,a,i,n,x,30,address_alloc_readyplus)
88 GEN_ALLOC_append(address_alloc,struct address,s,len,a,i,n,x,30,address_alloc_readyplus,address_alloc_append)
89 
90 static address_alloc address;
91 
92 struct ns {
93  char *owner;
94  char *ns;
95 } ;
96 
97 GEN_ALLOC_typedef(ns_alloc,struct ns,s,len,a)
98 GEN_ALLOC_readyplus(ns_alloc,struct ns,s,len,a,i,n,x,30,ns_alloc_readyplus)
99 GEN_ALLOC_append(ns_alloc,struct ns,s,len,a,i,n,x,30,ns_alloc_readyplus,ns_alloc_append)
100 
101 static ns_alloc ns;
102 
103 struct query {
104  char *owner;
105  char type[2];
106 } ;
107 
108 GEN_ALLOC_typedef(query_alloc,struct query,s,len,a)
109 GEN_ALLOC_readyplus(query_alloc,struct query,s,len,a,i,n,x,30,query_alloc_readyplus)
110 GEN_ALLOC_append(query_alloc,struct query,s,len,a,i,n,x,30,query_alloc_readyplus,query_alloc_append)
111 
112 static query_alloc query;
113 
114 struct qt {
115  char *owner;
116  char type[2];
117  char *control;
118  char ip[16];
119 } ;
120 
121 GEN_ALLOC_typedef(qt_alloc,struct qt,s,len,a)
122 GEN_ALLOC_readyplus(qt_alloc,struct qt,s,len,a,i,n,x,30,qt_alloc_readyplus)
123 GEN_ALLOC_append(qt_alloc,struct qt,s,len,a,i,n,x,30,qt_alloc_readyplus,qt_alloc_append)
124 
125 static qt_alloc qt;
126 
127 void qt_add(const char *q,const char type[2],const char *control,const char ip[16])
128 {
129  struct qt x;
130  int i;
131 
132  if (!*q) return; /* don't ask the roots about our artificial . host */
133 
134  for (i = 0; i < qt.len; ++i)
135  if (dns_domain_equal(qt.s[i].owner,q))
136  if (dns_domain_equal(qt.s[i].control,control))
137  if (byte_equal(qt.s[i].type,2,type))
138  if (byte_equal(qt.s[i].ip,16,ip))
139  return;
140 
141  byte_zero(&x,sizeof(x));
142  if (!dns_domain_copy(&x.owner,q)) nomem();
143  if (!dns_domain_copy(&x.control,control)) nomem();
144  byte_copy(x.type,2,type);
145  byte_copy(x.ip,16,ip);
146  if (!qt_alloc_append(&qt,&x)) nomem();
147 }
148 
149 void query_add(const char *owner,const char type[2])
150 {
151  struct query x;
152  int i;
153  int j;
154 
155  for (i = 0; i < query.len; ++i)
156  if (dns_domain_equal(query.s[i].owner,owner))
157  if (byte_equal(query.s[i].type,2,type))
158  return;
159 
160  byte_zero(&x,sizeof(x));
161  if (!dns_domain_copy(&x.owner,owner)) nomem();
162  byte_copy(x.type,2,type);
163  if (!query_alloc_append(&query,&x)) nomem();
164 
165  for (i = 0; i < ns.len; ++i)
166  if (dns_domain_suffix(owner,ns.s[i].owner))
167  for (j = 0; j < address.len; ++j)
168  if (dns_domain_equal(ns.s[i].ns,address.s[j].owner))
169  qt_add(owner,type,ns.s[i].owner,address.s[j].ip);
170 }
171 
172 void ns_add(const char *owner,const char *server)
173 {
174  struct ns x;
175  int i;
176  int j;
177 
178  buffer_put(buffer_1,querystr.s,querystr.len);
179  buffer_puts(buffer_1,"NS|");
181  buffer_puts(buffer_1,"|");
182  printdomain(server);
183  buffer_puts(buffer_1,"\n");
184 
185  for (i = 0; i < ns.len; ++i)
186  if (dns_domain_equal(ns.s[i].owner,owner))
187  if (dns_domain_equal(ns.s[i].ns,server))
188  return;
189 
190  query_add(server,DNS_T_A);
191  query_add(server,DNS_T_AAAA);
192 
193  byte_zero(&x,sizeof(x));
194  if (!dns_domain_copy(&x.owner,owner)) nomem();
195  if (!dns_domain_copy(&x.ns,server)) nomem();
196  if (!ns_alloc_append(&ns,&x)) nomem();
197 
198  for (i = 0; i < query.len; ++i)
199  if (dns_domain_suffix(query.s[i].owner,owner))
200  for (j = 0; j < address.len; ++j)
201  if (dns_domain_equal(server,address.s[j].owner))
202  qt_add(query.s[i].owner,query.s[i].type,owner,address.s[j].ip);
203 }
204 
205 void address_add(const char *owner,const char ip[16])
206 {
207  struct address x;
208  int i;
209  int j;
210  unsigned int type;
211 
212  scan_uint(querystr.s,&type);
213  buffer_put(buffer_1,querystr.s,querystr.len);
214  buffer_puts(buffer_1,"A/AAAA|");
216  buffer_puts(buffer_1,"|");
217  if (ip6_isv4mapped(ip)) {
218  buffer_put(buffer_1,ipstr,ip4_fmt(ipstr,ip + 12));
219  } else {
220  buffer_put(buffer_1,ipstr,ip6_fmt(ipstr,ip));
221  }
222  buffer_puts(buffer_1,"\n");
223 
224  for (i = 0; i < address.len; ++i)
226  if (byte_equal(address.s[i].ip,16,ip))
227  return;
228 
229  byte_zero(&x,sizeof(x));
230  if (!dns_domain_copy(&x.owner,owner)) nomem();
231  byte_copy(x.ip,16,ip);
232  if (!address_alloc_append(&address,&x)) nomem();
233 
234  for (i = 0; i < ns.len; ++i)
235  if (dns_domain_equal(ns.s[i].ns,owner))
236  for (j = 0; j < query.len; ++j)
237  if (dns_domain_suffix(query.s[j].owner,ns.s[i].owner))
238  qt_add(query.s[j].owner,query.s[j].type,ns.s[i].owner,ip);
239 }
240 
241 char seed[128];
242 
243 static char *t1;
244 static char *t2;
245 static char *referral;
246 static char *cname;
247 
248 static int typematch(const char rtype[2],const char qtype[2])
249 {
250  return byte_equal(qtype,2,rtype) || byte_equal(qtype,2,DNS_T_ANY);
251 }
252 
253 void parsepacket(const char *buf,unsigned int len,const char *d,const char dtype[2],const char *control)
254 {
255  char misc[20];
256  char header[12];
257  unsigned int pos;
258  uint16 numanswers;
259  unsigned int posanswers;
260  uint16 numauthority;
261  uint16 numglue;
262  uint16 datalen;
263  unsigned int rcode;
264  int flagout;
265  int flagcname;
266  int flagreferral;
267  int flagsoa;
268  int j;
269  const char *x;
270 
271  pos = dns_packet_copy(buf,len,0,header,12); if (!pos) goto DIE;
272  pos = dns_packet_skipname(buf,len,pos); if (!pos) goto DIE;
273  pos += 4;
274 
275  uint16_unpack_big(header + 6,&numanswers);
276  uint16_unpack_big(header + 8,&numauthority);
277  uint16_unpack_big(header + 10,&numglue);
278 
279  rcode = header[3] & 15;
280  if (rcode && (rcode != 3)) { errno = EPROTO; goto DIE; } /* impossible */
281 
282  flagout = 0;
283  flagcname = 0;
284  flagreferral = 0;
285  flagsoa = 0;
286  posanswers = pos;
287  for (j = 0; j < numanswers; ++j) {
288  pos = dns_packet_getname(buf,len,pos,&t1); if (!pos) goto DIE;
289  pos = dns_packet_copy(buf,len,pos,header,10); if (!pos) goto DIE;
290  if (dns_domain_equal(t1,d))
291  if (byte_equal(header + 2,2,DNS_C_IN))
292  if (typematch(header,dtype))
293  flagout = 1;
294  else {
295  if (typematch(header,DNS_T_CNAME)) {
296  if (!dns_packet_getname(buf,len,pos,&cname)) goto DIE;
297  flagcname = 1;
298  }
299  }
300  uint16_unpack_big(header + 8,&datalen);
301  pos += datalen;
302  }
303  for (j = 0; j < numauthority; ++j) {
304  pos = dns_packet_getname(buf,len,pos,&t1); if (!pos) goto DIE;
305  pos = dns_packet_copy(buf,len,pos,header,10); if (!pos) goto DIE;
306  if (typematch(header,DNS_T_SOA))
307  flagsoa = 1;
308  else if (typematch(header,DNS_T_NS)) {
309  flagreferral = 1;
310  if (!dns_domain_copy(&referral,t1)) goto DIE;
311  }
312  uint16_unpack_big(header + 8,&datalen);
313  pos += datalen;
314  }
315 
316  if (!flagcname && !rcode && !flagout && flagreferral && !flagsoa)
317  if (dns_domain_equal(referral,control) || !dns_domain_suffix(referral,control)) {
318  buffer_put(buffer_1,querystr.s,querystr.len);
319  buffer_puts(buffer_1,"ALERT|lame server; refers to ");
320  printdomain(referral);
321  buffer_puts(buffer_1,"\n");
322  return;
323  }
324 
325  pos = posanswers;
326  for (j = 0;j < numanswers + numauthority + numglue;++j) {
327  pos = dns_packet_getname(buf,len,pos,&t1); if (!pos) goto DIE;
328  pos = dns_packet_copy(buf,len,pos,header,10); if (!pos) goto DIE;
329  uint16_unpack_big(header + 8,&datalen);
330  if (dns_domain_suffix(t1,control))
331  if (byte_equal(header + 2,2,DNS_C_IN)) {
332  if (typematch(header,DNS_T_NS)) {
333  if (!dns_packet_getname(buf,len,pos,&t2)) goto DIE;
334  ns_add(t1,t2);
335  }
336  else if (typematch(header,DNS_T_A) && datalen == 4) {
337  if (!dns_packet_copy(buf,len,pos,misc + 12,4)) goto DIE;
338  byte_copy(misc,12,V4mappedprefix);
339  address_add(t1,misc);
340  }
341  else if (typematch(header,DNS_T_AAAA) && datalen == 16) {
342  if (!dns_packet_copy(buf,len,pos,misc,16)) goto DIE;
343  address_add(t1,misc);
344  }
345  }
346  pos += datalen;
347  }
348 
349 
350  if (flagcname) {
351  query_add(cname,dtype);
352  buffer_put(buffer_1,querystr.s,querystr.len);
353  buffer_puts(buffer_1,"CNAME|");
354  printdomain(cname);
355  buffer_puts(buffer_1,"\n");
356  return;
357  }
358  if (rcode == 3) {
359  buffer_put(buffer_1,querystr.s,querystr.len);
360  buffer_puts(buffer_1,"NXDOMAIN\n");
361  return;
362  }
363  if (flagout || flagsoa || !flagreferral) {
364  if (!flagout) {
365  buffer_put(buffer_1,querystr.s,querystr.len);
366  buffer_puts(buffer_1,"NODATA\n");
367  return;
368  }
369  pos = posanswers;
370  for (j = 0; j < numanswers + numauthority + numglue; ++j) {
371  pos = printrecord(&tmp,buf,len,pos,d,dtype);
372  if (!pos) goto DIE;
373  if (tmp.len) {
374  buffer_put(buffer_1,querystr.s,querystr.len);
375  buffer_puts(buffer_1,"answer|");
376  buffer_put(buffer_1,tmp.s,tmp.len); /* includes \n */
377  }
378  }
379  return;
380  }
381 
382  if (!dns_domain_suffix(d,referral)) goto DIE;
383  buffer_put(buffer_1,querystr.s,querystr.len);
384  buffer_puts(buffer_1,"see|");
385  printdomain(referral);
386  buffer_puts(buffer_1,"\n");
387  return;
388 
389  DIE:
390  x = errstr(errno);
391  buffer_put(buffer_1,querystr.s,querystr.len);
392  buffer_puts(buffer_1,"ALERT|unable to parse response packet; ");
393  buffer_puts(buffer_1,x);
394  buffer_puts(buffer_1,"\n");
395 }
396 
397 int main(int argc,char **argv)
398 {
399  static stralloc ipout;
400  static stralloc fqdn;
401  static stralloc udn;
402  static char *q;
403  char *control;
404  char type[2];
405  char ip[64];
406  int i;
407  uint16 u16;
408 
410 
411  if (!stralloc_copys(&querystr,"0|.|.|start|")) nomem();
412 
413  if (!address_alloc_readyplus(&address,1)) nomem();
414  if (!query_alloc_readyplus(&query,1)) nomem();
415  if (!ns_alloc_readyplus(&ns,1)) nomem();
416  if (!qt_alloc_readyplus(&qt,1)) nomem();
417 
418  if (!*argv) usage();
419  if (!*++argv) usage();
420  if (!parsetype(*argv,type)) usage();
421 
422  if (!*++argv) usage();
423  if (dns_domain_fromdot(&q,*argv,str_len(*argv)) <= 0) nomem();
424 
425  query_add(q,type);
426  ns_add("","");
427 
428  while (*++argv) {
429  if (!stralloc_copys(&udn,*argv)) nomem();
430  if (dns_ip_qualify(&ipout,&fqdn,&udn) < 0) nomem(); /* XXX unified */
431  for (i = 0; i + 16 <= ipout.len; i += 16)
432  address_add("",ipout.s + i);
433  }
434 
435  for (i = 0; i < qt.len; ++i) {
436  if (!dns_domain_copy(&q,qt.s[i].owner)) nomem();
437  control = qt.s[i].control;
438  if (!dns_domain_suffix(q,control)) continue;
439  byte_copy(type,2,qt.s[i].type);
440  byte_copy(ip,16,qt.s[i].ip);
441 
442  if (!stralloc_copys(&querystr,"")) nomem();
443  uint16_unpack_big(type,&u16);
444  if (!stralloc_catulong0(&querystr,u16,0)) nomem();
445  if (!stralloc_cats(&querystr,"|")) nomem();
446  if (dns_domain_todot_cat(&querystr,q) <= 0) nomem();
447  if (!stralloc_cats(&querystr,"|")) nomem();
448  if (dns_domain_todot_cat(&querystr,control) <= 0) nomem();
449  if (!stralloc_cats(&querystr,"|")) nomem();
450  if (ip6_isv4mapped(ip)) {
451  if (!stralloc_catb(&querystr,ipstr,ip4_fmt(ipstr,ip + 12))) nomem();
452  } else
453  if (!stralloc_catb(&querystr,ipstr,ip6_fmt(ipstr,ip))) nomem();
454  if (!stralloc_cats(&querystr,"|")) nomem();
455 
456  buffer_put(buffer_1,querystr.s,querystr.len);
457  buffer_puts(buffer_1,"tx\n");
458  buffer_flush(buffer_1);
459 
460  if (resolve(q,type,ip) < 0) { /* internal resolve */
461  const char *x = errstr(errno);
462  buffer_put(buffer_1,querystr.s,querystr.len);
463  buffer_puts(buffer_1,"ALERT|query failed; ");
464  buffer_puts(buffer_1,x);
465  buffer_puts(buffer_1,"\n");
466  }
467  else
468  parsepacket(tx.packet,tx.packetlen,q,type,control);
469 
470  if (dns_domain_equal(q,"\011localhost\0")) {
471  buffer_put(buffer_1,querystr.s,querystr.len);
472  buffer_puts(buffer_1,"ALERT|some caches do not handle localhost internally\n");
473  address_add(q,"\177\0\0\1");
474  }
475  if (dns_domain_equal(q,"\015ip4-loopback\0")) {
476  buffer_put(buffer_1,querystr.s,querystr.len);
477  buffer_puts(buffer_1,"ALERT|some caches do not handle localhost internally\n");
478  address_add(q,"\177\0\0\1");
479  }
480  if (dns_domain_equal(q,"\015ip6-loopback\0")) {
481  buffer_put(buffer_1,querystr.s,querystr.len);
482  buffer_puts(buffer_1,"ALERT|some caches do not handle loopback internally\n");
483  address_add(q,"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001");
484  }
485  if (dd4(q,"",ip) == 4 || dd6(q,"",ip) == 16) {
486  buffer_put(buffer_1,querystr.s,querystr.len);
487  buffer_puts(buffer_1,"ALERT|some caches do not handle IP addresses internally\n");
488  address_add(q,ip);
489  }
490 
491  buffer_flush(buffer_1);
492  }
493 
494  _exit(0);
495 }
char ip[16]
Definition: axfrdns.c:126
uint16 len
Definition: axfrdns.c:302
char buf[MSGSIZE]
Definition: axfrdns.c:301
int dd6(const char *q, const char *base, char ip[16])
Definition: dd.c:40
int dd4(const char *q, const char *base, char ip[4])
Definition: dd.c:7
void dns_transmit_io(struct dns_transmit *, iopause_fd *, struct taia *)
Definition: dns_transmit.c:284
unsigned int dns_packet_copy(const char *, unsigned int, unsigned int, char *, unsigned int)
Definition: dns_packet.c:8
#define DNS_ERR
Definition: dns.h:22
#define DNS_T_A
Definition: dns.h:37
#define QUERY_MAXIPLEN
Definition: dns.h:30
int dns_domain_equal(const char *, const char *)
Definition: dns_domain.c:39
int dns_domain_fromdot(char **, const char *, unsigned int)
Definition: dns_dfd.c:6
int dns_domain_todot_cat(stralloc *, const char *)
Definition: dns_dtda.c:11
int dns_ip_qualify(stralloc *, stralloc *, const stralloc *)
Definition: dns_ipq.c:228
#define DNS_C_IN
Definition: dns.h:34
#define DNS_T_ANY
Definition: dns.h:66
int dns_domain_copy(char **, const char *)
Definition: dns_domain.c:25
int dns_domain_suffix(const char *, const char *)
Definition: dns_domain.c:50
unsigned int dns_packet_skipname(const char *, unsigned int, unsigned int)
Definition: dns_packet.c:18
int dns_transmit_start(struct dns_transmit *, const char *, int, const char *, const char *, const char *)
#define DNS_T_SOA
Definition: dns.h:40
#define DNS_T_NS
Definition: dns.h:38
#define DNS_T_CNAME
Definition: dns.h:39
#define DNS_T_AAAA
Definition: dns.h:48
unsigned int dns_packet_getname(const char *, unsigned int, unsigned int, char **)
Definition: dns_packet.c:35
void dns_random_init(const char *)
#define DNS_COM
Definition: dns.h:23
int dns_transmit_get(struct dns_transmit *, const iopause_fd *, const struct taia *)
Definition: dns_transmit.c:301
char servers[QUERY_MAXIPLEN]
Definition: dnsfilter.c:48
struct line * x
struct line tmp
Definition: dnsfilter.c:32
char type[2]
Definition: dnsq.c:56
int resolve(char *q, char qtype[2], char ip[16])
Definition: dnstrace.c:43
void query_add(const char *owner, const char type[2])
Definition: dnstrace.c:149
void address_add(const char *owner, const char ip[16])
Definition: dnstrace.c:205
int main(int argc, char **argv)
Definition: dnstrace.c:397
void ns_add(const char *owner, const char *server)
Definition: dnstrace.c:172
void printdomain(const char *d)
Definition: dnstrace.c:34
void nomem(void)
Definition: dnstrace.c:21
void parsepacket(const char *buf, unsigned int len, const char *d, const char dtype[2], const char *control)
Definition: dnstrace.c:253
GEN_ALLOC_typedef(GEN_ALLOC_readyplus(address_alloc, GEN_ALLOC_readyplus(struct address, GEN_ALLOC_readyplus(s, GEN_ALLOC_readyplus(len, GEN_ALLOC_readyplus(a)
Definition: dnstrace.c:86
#define WHO
Definition: dnstrace.c:19
char ipstr[IP6_FMT]
Definition: dnstrace.c:31
char seed[128]
Definition: dnstrace.c:241
void usage(void)
Definition: dnstrace.c:25
#define GEN_ALLOC_append(ta, type, field, len, a, i, n, x, base, ta_rplus, ta_append)
Definition: gen_allocdefs.h:30
#define GEN_ALLOC_readyplus(ta, type, field, len, a, i, n, x, base, ta_rplus)
Definition: gen_allocdefs.h:17
void owner(int uid, int gid)
Definition: generic-conf.c:76
void start(const char *s)
Definition: generic-conf.c:41
void d(const char *home, const char *subdir, int uid, int gid, int mode)
int parsetype(char *s, char type[2])
Definition: parsetype.c:8
unsigned int printrecord(stralloc *out, const char *buf, unsigned int len, unsigned int pos, const char *q, const char qtype[2])
Definition: printrecord.c:119
char qtype[2]
Definition: dns.h:93
unsigned int packetlen
Definition: dns.h:77
char * packet
Definition: dns.h:76
char ip[16]
Definition: dnstrace.c:83
char * owner
Definition: dnstrace.c:82
Definition: query.h:56
char type[2]
Definition: query.h:70
char * ns[QUERY_MAXLEVEL][QUERY_MAXNS]
Definition: query.h:61