djbdnscurve6 45
djbdnscurve6
Loading...
Searching...
No Matches
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
21void nomem(void)
22{
23 logmsg(WHO,111,FATAL,"out of memory");
24}
25void usage(void)
26{
27 logmsg(WHO,100,USAGE,"dnstrace type name rootip ...");
28}
29
30static stralloc querystr;
31char ipstr[IP6_FMT];
32static stralloc tmp;
33
34void 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
41static struct dns_transmit tx;
42
43int resolve(char *q,char qtype[2],char ip[16])
44{
45 struct taia start;
46 struct taia stamp;
47 struct taia deadline;
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
81struct address {
82 char *owner;
83 char ip[16];
84} ;
85
86GEN_ALLOC_typedef(address_alloc,struct address,s,len,a)
87GEN_ALLOC_readyplus(address_alloc,struct address,s,len,a,i,n,x,30,address_alloc_readyplus)
88GEN_ALLOC_append(address_alloc,struct address,s,len,a,i,n,x,30,address_alloc_readyplus,address_alloc_append)
89
90static address_alloc address;
91
92struct ns {
93 char *owner;
94 char *ns;
95} ;
96
97GEN_ALLOC_typedef(ns_alloc,struct ns,s,len,a)
98GEN_ALLOC_readyplus(ns_alloc,struct ns,s,len,a,i,n,x,30,ns_alloc_readyplus)
99GEN_ALLOC_append(ns_alloc,struct ns,s,len,a,i,n,x,30,ns_alloc_readyplus,ns_alloc_append)
100
101static ns_alloc ns;
102
103struct query {
104 char *owner;
105 char type[2];
106} ;
107
108GEN_ALLOC_typedef(query_alloc,struct query,s,len,a)
109GEN_ALLOC_readyplus(query_alloc,struct query,s,len,a,i,n,x,30,query_alloc_readyplus)
110GEN_ALLOC_append(query_alloc,struct query,s,len,a,i,n,x,30,query_alloc_readyplus,query_alloc_append)
111
112static query_alloc query;
113
114struct qt {
115 char *owner;
116 char type[2];
117 char *control;
118 char ip[16];
119} ;
120
121GEN_ALLOC_typedef(qt_alloc,struct qt,s,len,a)
122GEN_ALLOC_readyplus(qt_alloc,struct qt,s,len,a,i,n,x,30,qt_alloc_readyplus)
123GEN_ALLOC_append(qt_alloc,struct qt,s,len,a,i,n,x,30,qt_alloc_readyplus,qt_alloc_append)
124
125static qt_alloc qt;
126
127void 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
149void 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
172void 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
205void 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
241char seed[128];
242
243static char *t1;
244static char *t2;
245static char *referral;
246static char *cname;
247
248static 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
253void 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
397int 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:125
uint16 len
Definition: axfrdns.c:319
char buf[MSGSIZE]
Definition: axfrdns.c:318
int main()
Definition: axfrdns.c:323
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
#define DNS_ERR
Definition: dns.h:32
#define DNS_T_A
Definition: dns.h:56
#define QUERY_MAXIPLEN
Definition: dns.h:45
#define DNS_C_IN
Definition: dns.h:53
#define DNS_T_ANY
Definition: dns.h:85
#define DNS_T_SOA
Definition: dns.h:59
#define DNS_T_NS
Definition: dns.h:57
#define DNS_T_CNAME
Definition: dns.h:58
#define DNS_T_AAAA
Definition: dns.h:67
#define DNS_COM
Definition: dns.h:33
int dns_domain_fromdot(char **out, const char *buf, unsigned int n)
Definition: dns_dfd.c:6
int dns_domain_equal(const char *dn1, const char *dn2)
Definition: dns_domain.c:39
int dns_domain_copy(char **out, const char *in)
Definition: dns_domain.c:25
int dns_domain_suffix(const char *big, const char *little)
Definition: dns_domain.c:50
int dns_domain_todot_cat(stralloc *out, const char *d)
Definition: dns_dtda.c:11
int dns_ip_qualify(stralloc *ipout, stralloc *fqdn, const stralloc *in)
Definition: dns_ipq.c:228
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
unsigned int dns_packet_skipname(const char *buf, unsigned int len, unsigned int pos)
Definition: dns_packet.c:18
void dns_random_init(const char data[128])
Definition: dns_random.c:37
void dns_transmit_io(struct dns_transmit *d, iopause_fd *x, struct taia *deadline)
Definition: dns_transmit.c:279
int dns_transmit_start(struct dns_transmit *d, const char servers[QUERY_MAXIPLEN], int flagrecursive, const char *q, const char qtype[2], const char localip[16])
Definition: dns_transmit.c:264
int dns_transmit_get(struct dns_transmit *d, const iopause_fd *x, const struct taia *when)
Definition: dns_transmit.c:296
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
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
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 *, char *)
unsigned int printrecord(stralloc *, const char *, unsigned int, unsigned int, const char *, const char *)
char ip[16]
Definition: dnstrace.c:83
char * owner
Definition: dnstrace.c:82
char qtype[2]
Definition: dns.h:112
unsigned int packetlen
Definition: dns.h:96
char * packet
Definition: dns.h:95
Definition: query.h:56
char type[2]
Definition: query.h:70
char * ns[QUERY_MAXLEVEL][QUERY_MAXNS]
Definition: query.h:61