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