xref: /plan9-contrib/sys/src/cmd/ndb/dnsdebug.c (revision 80ee5cbfe36716af62da8896207e9763b8e3d760)
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 *p;
48 	char *f[4];
49 	Ipifc *ifcs;
50 
51 	strcpy(mntpt, "/net");
52 
53 	ARGBEGIN{
54 	case 'r':
55 		resolver = 1;
56 		break;
57 	case 'x':
58 		dbfile = "/lib/ndb/external";
59 		strcpy(mntpt, "/net.alt");
60 		break;
61 	}ARGEND
62 
63 	now = time(0);
64 	dninit();
65 	fmtinstall('R', prettyrrconv);
66 	ifcs = readipifc(mntpt, nil);
67 	if(ifcs == nil)
68 		sysfatal("can't read my ip address");
69 	ipmove(ipaddr, ifcs->ip);
70 	opendatabase();
71 
72 	if(resolver)
73 		squirrelserveraddrs();
74 
75 	debug = 1;
76 
77 	if(argc > 0){
78 		docmd(argc, argv);
79 		exits(0);
80 	}
81 
82 	Binit(&in, 0, OREAD);
83 	for(print("> "); p = Brdline(&in, '\n'); print("> ")){
84 		p[Blinelen(&in)-1] = 0;
85 		n = tokenize(p, f, 3);
86 		if(n<1)
87 			continue;
88 
89 		/* flush the cache */
90 		dnpurge();
91 
92 		docmd(n, f);
93 
94 	}
95 	exits(0);
96 }
97 
98 static char*
99 longtime(long t)
100 {
101 	int d, h, m, n;
102 	static char x[128];
103 
104 	for(d = 0; t >= 24*60*60; t -= 24*60*60)
105 		d++;
106 	for(h = 0; t >= 60*60; t -= 60*60)
107 		h++;
108 	for(m = 0; t >= 60; t -= 60)
109 		m++;
110 	n = 0;
111 	if(d)
112 		n += sprint(x, "%d day ", d);
113 	if(h)
114 		n += sprint(x+n, "%d hr ", h);
115 	if(m)
116 		n += sprint(x+n, "%d min ", m);
117 	if(t || n == 0)
118 		sprint(x+n, "%ld sec", t);
119 	return x;
120 }
121 
122 int
123 prettyrrconv(va_list *arg, Fconv *f)
124 {
125 	RR *rp;
126 	char buf[3*Domlen];
127 	char *p, *e;
128 
129 	rp = va_arg(*arg, RR*);
130 	if(rp == 0){
131 		strcpy(buf, "<null>");
132 		goto out;
133 	}
134 
135 	p = buf;
136 	e = buf + sizeof(buf);
137 	p = seprint(p, e, "%-32.32s %-15.15s %-5.5s", rp->owner->name,
138 		longtime(rp->db ? rp->ttl : (rp->ttl-now)),
139 		rrname(rp->type, buf));
140 
141 	if(rp->negative){
142 		seprint(p, e, "negative rcode %d\n", rp->negrcode);
143 		goto out;
144 	}
145 
146 	switch(rp->type){
147 	case Thinfo:
148 		seprint(p, e, "\t%s %s", rp->cpu->name, rp->os->name);
149 		break;
150 	case Tcname:
151 	case Tmb:
152 	case Tmd:
153 	case Tmf:
154 	case Tns:
155 		seprint(p, e, "\t%s", rp->host->name);
156 		break;
157 	case Tmg:
158 	case Tmr:
159 		seprint(p, e, "\t%s", rp->mb->name);
160 		break;
161 	case Tminfo:
162 		seprint(p, e, "\t%s %s", rp->mb->name, rp->rmb->name);
163 		break;
164 	case Tmx:
165 		seprint(p, e, "\t%lud %s", rp->pref, rp->host->name);
166 		break;
167 	case Ta:
168 		seprint(p, e, "\t%s", rp->ip->name);
169 		break;
170 	case Tptr:
171 		seprint(p, e, "\t%s", rp->ptr->name);
172 		break;
173 	case Tsoa:
174 		seprint(p, e, "\t%s %s %lud %lud %lud %lud %lud", rp->host->name,
175 			rp->rmb->name, rp->soa->serial, rp->soa->refresh, rp->soa->retry,
176 			rp->soa->expire, rp->soa->minttl);
177 		break;
178 	case Ttxt:
179 		seprint(p, e, "\t%s", rp->txt->name);
180 		break;
181 	case Trp:
182 		seprint(p, e, "\t%s %s", rp->rmb->name, rp->txt->name);
183 		break;
184 	case Tkey:
185 		seprint(p, e, "\t%d %d %d", rp->key->flags, rp->key->proto,
186 			rp->key->alg);
187 		break;
188 	case Tsig:
189 		seprint(p, e, "\t%d %d %d %lud %lud %lud %d %s",
190 			rp->sig->type, rp->sig->alg, rp->sig->labels, rp->sig->ttl,
191 			rp->sig->exp, rp->sig->incep, rp->sig->tag, rp->sig->signer->name);
192 		break;
193 	case Tcert:
194 		seprint(p, e, "\t%d %d %d",
195 			rp->sig->type, rp->sig->tag, rp->sig->alg);
196 		break;
197 	default:
198 		break;
199 	}
200 out:
201 	strconv(buf, f);
202 	return sizeof(RR*);
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));
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));
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 	if(strcmp("ptr", tstr) == 0
376 	&& strstr(name, "IN-ADDR") == 0
377 	&& strstr(name, "in-addr") == 0){
378 		for(p = name; *p; p++)
379 			;
380 		*p = '.';
381 		np = buf;
382 		len = 0;
383 		while(p >= name){
384 			len++;
385 			p--;
386 			if(*p == '.'){
387 				memmove(np, p+1, len);
388 				np += len;
389 				len = 0;
390 			}
391 		}
392 		memmove(np, p+1, len);
393 		np += len;
394 		strcpy(np, "in-addr.arpa");
395 		strcpy(name, buf);
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(name, 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