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