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