tdnsdebug.c - plan9port - [fork] Plan 9 from user space | |
git clone git://src.adamsgaard.dk/plan9port | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
tdnsdebug.c (8549B) | |
--- | |
1 #include <u.h> | |
2 #include <libc.h> | |
3 #include <bio.h> | |
4 #include <ctype.h> | |
5 #include <ip.h> | |
6 #include <ndb.h> | |
7 #include <thread.h> | |
8 #include "dns.h" | |
9 | |
10 enum | |
11 { | |
12 Maxrequest= 128, | |
13 Ncache= 8, | |
14 Maxpath= 128, | |
15 Maxreply= 512, | |
16 Maxrrr= 16 | |
17 }; | |
18 | |
19 static char *servername; | |
20 static RR *serveraddrs; | |
21 | |
22 int debug; | |
23 int cachedb; | |
24 ulong now; | |
25 int testing; | |
26 int traceactivity; | |
27 char *trace; | |
28 int needrefresh; | |
29 int resolver; | |
30 uchar ipaddr[IPaddrlen]; /* my ip address */ | |
31 int maxage; | |
32 char *logfile = "dns"; | |
33 char *dbfile; | |
34 char mntpt[Maxpath]; | |
35 char *zonerefreshprogram; | |
36 char *tcpaddr; | |
37 char *udpaddr; | |
38 | |
39 int prettyrrfmt(Fmt*); | |
40 void preloadserveraddrs(void); | |
41 void squirrelserveraddrs(void); | |
42 int setserver(char*); | |
43 void doquery(char*, char*); | |
44 void docmd(int, char**); | |
45 | |
46 void | |
47 usage(void) | |
48 { | |
49 fprint(2, "usage: dnsdebug [-fr] [query ...]\n"); | |
50 threadexitsall("usage"); | |
51 } | |
52 | |
53 void | |
54 threadmain(int argc, char *argv[]) | |
55 { | |
56 int n; | |
57 Biobuf in; | |
58 char *p; | |
59 char *f[4]; | |
60 | |
61 strcpy(mntpt, "/net"); | |
62 | |
63 ARGBEGIN{ | |
64 case 'r': | |
65 resolver = 1; | |
66 break; | |
67 case 'f': | |
68 dbfile = EARGF(usage()); | |
69 break; | |
70 default: | |
71 usage(); | |
72 }ARGEND | |
73 | |
74 now = time(0); | |
75 dninit(); | |
76 fmtinstall('R', prettyrrfmt); | |
77 if(myipaddr(ipaddr, mntpt) < 0) | |
78 sysfatal("can't read my ip address"); | |
79 opendatabase(); | |
80 | |
81 if(resolver) | |
82 squirrelserveraddrs(); | |
83 | |
84 debug = 1; | |
85 | |
86 if(argc > 0){ | |
87 docmd(argc, argv); | |
88 threadexitsall(0); | |
89 } | |
90 | |
91 Binit(&in, 0, OREAD); | |
92 for(print("> "); p = Brdline(&in, '\n'); print("> ")){ | |
93 p[Blinelen(&in)-1] = 0; | |
94 n = tokenize(p, f, 3); | |
95 if(n<1) | |
96 continue; | |
97 | |
98 /* flush the cache */ | |
99 dnpurge(); | |
100 | |
101 docmd(n, f); | |
102 | |
103 } | |
104 threadexitsall(0); | |
105 } | |
106 | |
107 static char* | |
108 longtime(long t) | |
109 { | |
110 int d, h, m, n; | |
111 static char x[128]; | |
112 | |
113 for(d = 0; t >= 24*60*60; t -= 24*60*60) | |
114 d++; | |
115 for(h = 0; t >= 60*60; t -= 60*60) | |
116 h++; | |
117 for(m = 0; t >= 60; t -= 60) | |
118 m++; | |
119 n = 0; | |
120 if(d) | |
121 n += sprint(x, "%d day ", d); | |
122 if(h) | |
123 n += sprint(x+n, "%d hr ", h); | |
124 if(m) | |
125 n += sprint(x+n, "%d min ", m); | |
126 if(t || n == 0) | |
127 sprint(x+n, "%ld sec", t); | |
128 return x; | |
129 } | |
130 | |
131 int | |
132 prettyrrfmt(Fmt *f) | |
133 { | |
134 RR *rp; | |
135 char buf[3*Domlen]; | |
136 char *p, *e; | |
137 Txt *t; | |
138 | |
139 rp = va_arg(f->args, RR*); | |
140 if(rp == 0){ | |
141 strcpy(buf, "<null>"); | |
142 goto out; | |
143 } | |
144 | |
145 p = buf; | |
146 e = buf + sizeof(buf); | |
147 p = seprint(p, e, "%-32.32s %-15.15s %-5.5s", rp->owner->name, | |
148 longtime(rp->db ? rp->ttl : (rp->ttl-now)), | |
149 rrname(rp->type, buf, sizeof buf)); | |
150 | |
151 if(rp->negative){ | |
152 seprint(p, e, "negative rcode %d\n", rp->negrcode); | |
153 goto out; | |
154 } | |
155 | |
156 switch(rp->type){ | |
157 case Thinfo: | |
158 seprint(p, e, "\t%s %s", rp->cpu->name, rp->os->name); | |
159 break; | |
160 case Tcname: | |
161 case Tmb: | |
162 case Tmd: | |
163 case Tmf: | |
164 case Tns: | |
165 seprint(p, e, "\t%s", rp->host->name); | |
166 break; | |
167 case Tmg: | |
168 case Tmr: | |
169 seprint(p, e, "\t%s", rp->mb->name); | |
170 break; | |
171 case Tminfo: | |
172 seprint(p, e, "\t%s %s", rp->mb->name, rp->rmb->name); | |
173 break; | |
174 case Tmx: | |
175 seprint(p, e, "\t%lud %s", rp->pref, rp->host->name); | |
176 break; | |
177 case Ta: | |
178 case Taaaa: | |
179 seprint(p, e, "\t%s", rp->ip->name); | |
180 break; | |
181 case Tptr: | |
182 seprint(p, e, "\t%s", rp->ptr->name); | |
183 break; | |
184 case Tsoa: | |
185 seprint(p, e, "\t%s %s %lud %lud %lud %lud %lud", rp->ho… | |
186 rp->rmb->name, rp->soa->serial, rp->soa->refresh… | |
187 rp->soa->expire, rp->soa->minttl); | |
188 break; | |
189 case Tnull: | |
190 seprint(p, e, "\t%.*H", rp->null->dlen, rp->null->data); | |
191 break; | |
192 case Ttxt: | |
193 p = seprint(p, e, "\t"); | |
194 for(t = rp->txt; t != nil; t = t->next) | |
195 p = seprint(p, e, "%s", t->p); | |
196 break; | |
197 case Trp: | |
198 seprint(p, e, "\t%s %s", rp->rmb->name, rp->rp->name); | |
199 break; | |
200 case Tkey: | |
201 seprint(p, e, "\t%d %d %d", rp->key->flags, rp->key->pro… | |
202 rp->key->alg); | |
203 break; | |
204 case Tsig: | |
205 seprint(p, e, "\t%d %d %d %lud %lud %lud %d %s", | |
206 rp->sig->type, rp->sig->alg, rp->sig->labels, rp… | |
207 rp->sig->exp, rp->sig->incep, rp->sig->tag, rp->… | |
208 break; | |
209 case Tcert: | |
210 seprint(p, e, "\t%d %d %d", | |
211 rp->sig->type, rp->sig->tag, rp->sig->alg); | |
212 break; | |
213 default: | |
214 break; | |
215 } | |
216 out: | |
217 return fmtstrcpy(f, buf); | |
218 } | |
219 | |
220 void | |
221 logsection(char *flag, RR *rp) | |
222 { | |
223 if(rp == nil) | |
224 return; | |
225 print("\t%s%R\n", flag, rp); | |
226 for(rp = rp->next; rp != nil; rp = rp->next) | |
227 print("\t %R\n", rp); | |
228 } | |
229 | |
230 void | |
231 logreply(int id, uchar *addr, DNSmsg *mp) | |
232 { | |
233 RR *rp; | |
234 char buf[12]; | |
235 char resp[32]; | |
236 | |
237 switch(mp->flags & Rmask){ | |
238 case Rok: | |
239 strcpy(resp, "OK"); | |
240 break; | |
241 case Rformat: | |
242 strcpy(resp, "Format error"); | |
243 break; | |
244 case Rserver: | |
245 strcpy(resp, "Server failed"); | |
246 break; | |
247 case Rname: | |
248 strcpy(resp, "Nonexistent"); | |
249 break; | |
250 case Runimplimented: | |
251 strcpy(resp, "Unimplemented"); | |
252 break; | |
253 case Rrefused: | |
254 strcpy(resp, "Refused"); | |
255 break; | |
256 default: | |
257 sprint(resp, "%d", mp->flags & Rmask); | |
258 break; | |
259 } | |
260 | |
261 print("%d: rcvd %s from %I (%s%s%s%s%s)\n", id, resp, addr, | |
262 mp->flags & Fauth ? "authoritative" : "", | |
263 mp->flags & Ftrunc ? " truncated" : "", | |
264 mp->flags & Frecurse ? " recurse" : "", | |
265 mp->flags & Fcanrec ? " can_recurse" : "", | |
266 mp->flags & (Fauth|Rname) == (Fauth|Rname) ? | |
267 " nx" : ""); | |
268 for(rp = mp->qd; rp != nil; rp = rp->next) | |
269 print("\tQ: %s %s\n", rp->owner->name, rrname(rp->typ… | |
270 logsection("Ans: ", mp->an); | |
271 logsection("Auth: ", mp->ns); | |
272 logsection("Hint: ", mp->ar); | |
273 } | |
274 | |
275 void | |
276 logsend(int id, int subid, uchar *addr, char *sname, char *rname, int ty… | |
277 { | |
278 char buf[12]; | |
279 | |
280 print("%d.%d: sending to %I/%s %s %s\n", id, subid, | |
281 addr, sname, rname, rrname(type, buf, sizeof buf)); | |
282 } | |
283 | |
284 RR* | |
285 getdnsservers(int class) | |
286 { | |
287 RR *rr; | |
288 | |
289 if(servername == nil) | |
290 return dnsservers(class); | |
291 | |
292 rr = rralloc(Tns); | |
293 rr->owner = dnlookup("local#dns#servers", class, 1); | |
294 rr->host = dnlookup(servername, class, 1); | |
295 | |
296 return rr; | |
297 } | |
298 | |
299 void | |
300 squirrelserveraddrs(void) | |
301 { | |
302 RR *rr, *rp, **l; | |
303 Request req; | |
304 | |
305 /* look up the resolver address first */ | |
306 resolver = 0; | |
307 debug = 0; | |
308 if(serveraddrs) | |
309 rrfreelist(serveraddrs); | |
310 serveraddrs = nil; | |
311 rr = getdnsservers(Cin); | |
312 l = &serveraddrs; | |
313 for(rp = rr; rp != nil; rp = rp->next){ | |
314 if(strcmp(ipattr(rp->host->name), "ip") == 0){ | |
315 *l = rralloc(Ta); | |
316 (*l)->owner = rp->host; | |
317 (*l)->ip = rp->host; | |
318 l = &(*l)->next; | |
319 continue; | |
320 } | |
321 req.aborttime = now + 60; /* don't spend more tha… | |
322 *l = dnresolve(rp->host->name, Cin, Ta, &req, 0, 0, Recu… | |
323 while(*l != nil) | |
324 l = &(*l)->next; | |
325 } | |
326 resolver = 1; | |
327 debug = 1; | |
328 } | |
329 | |
330 void | |
331 preloadserveraddrs(void) | |
332 { | |
333 RR *rp, **l, *first; | |
334 | |
335 l = &first; | |
336 for(rp = serveraddrs; rp != nil; rp = rp->next){ | |
337 rrcopy(rp, l); | |
338 rrattach(first, 1); | |
339 } | |
340 } | |
341 | |
342 int | |
343 setserver(char *server) | |
344 { | |
345 if(servername != nil){ | |
346 free(servername); | |
347 servername = nil; | |
348 resolver = 0; | |
349 } | |
350 if(server == nil || *server == 0) | |
351 return 0; | |
352 servername = strdup(server); | |
353 squirrelserveraddrs(); | |
354 if(serveraddrs == nil){ | |
355 print("can't resolve %s\n", servername); | |
356 resolver = 0; | |
357 } else { | |
358 resolver = 1; | |
359 } | |
360 return resolver ? 0 : -1; | |
361 } | |
362 | |
363 void | |
364 doquery(char *name, char *tstr) | |
365 { | |
366 Request req; | |
367 RR *rr, *rp; | |
368 int len, type; | |
369 char *p, *np; | |
370 int rooted; | |
371 char buf[1024]; | |
372 | |
373 if(resolver) | |
374 preloadserveraddrs(); | |
375 | |
376 /* default to an "ip" request if alpha, "ptr" if numeric */ | |
377 if(tstr == nil || *tstr == 0) { | |
378 if(strcmp(ipattr(name), "ip") == 0) | |
379 tstr = "ptr"; | |
380 else | |
381 tstr = "ip"; | |
382 } | |
383 | |
384 /* if name end in '.', remove it */ | |
385 len = strlen(name); | |
386 if(len > 0 && name[len-1] == '.'){ | |
387 rooted = 1; | |
388 name[len-1] = 0; | |
389 } else | |
390 rooted = 0; | |
391 | |
392 /* inverse queries may need to be permuted */ | |
393 strncpy(buf, name, sizeof buf); | |
394 if(strcmp("ptr", tstr) == 0 | |
395 && strstr(name, "IN-ADDR") == 0 | |
396 && strstr(name, "in-addr") == 0){ | |
397 for(p = name; *p; p++) | |
398 ; | |
399 *p = '.'; | |
400 np = buf; | |
401 len = 0; | |
402 while(p >= name){ | |
403 len++; | |
404 p--; | |
405 if(*p == '.'){ | |
406 memmove(np, p+1, len); | |
407 np += len; | |
408 len = 0; | |
409 } | |
410 } | |
411 memmove(np, p+1, len); | |
412 np += len; | |
413 strcpy(np, "in-addr.arpa"); | |
414 } | |
415 | |
416 /* look it up */ | |
417 type = rrtype(tstr); | |
418 if(type < 0){ | |
419 print("!unknown type %s\n", tstr); | |
420 return; | |
421 } | |
422 | |
423 getactivity(&req); | |
424 req.aborttime = now + 60; /* don't spend more than 60 sec… | |
425 rr = dnresolve(buf, Cin, type, &req, 0, 0, Recurse, rooted, 0); | |
426 if(rr){ | |
427 print("----------------------------\n"); | |
428 for(rp = rr; rp; rp = rp->next) | |
429 print("answer %R\n", rp); | |
430 print("----------------------------\n"); | |
431 } | |
432 rrfreelist(rr); | |
433 | |
434 putactivity(); | |
435 } | |
436 | |
437 void | |
438 docmd(int n, char **f) | |
439 { | |
440 int tmpsrv; | |
441 char *name, *type; | |
442 | |
443 name = nil; | |
444 type = nil; | |
445 tmpsrv = 0; | |
446 | |
447 if(*f[0] == '@') { | |
448 if(setserver(f[0]+1) < 0) | |
449 return; | |
450 | |
451 switch(n){ | |
452 case 3: | |
453 type = f[2]; | |
454 /* fall through */ | |
455 case 2: | |
456 name = f[1]; | |
457 tmpsrv = 1; | |
458 break; | |
459 } | |
460 } else { | |
461 switch(n){ | |
462 case 2: | |
463 type = f[1]; | |
464 /* fall through */ | |
465 case 1: | |
466 name = f[0]; | |
467 break; | |
468 } | |
469 } | |
470 | |
471 if(name == nil) | |
472 return; | |
473 | |
474 doquery(name, type); | |
475 | |
476 if(tmpsrv) | |
477 setserver(""); | |
478 } |