xref: /plan9/sys/src/cmd/ndb/dnsdebug.c (revision e34dbc32159cf6b992e3c875383330eae3abc0be)
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 char	*zonerefreshprogram;
35 
36 int prettyrrfmt(Fmt*);
37 void preloadserveraddrs(void);
38 void squirrelserveraddrs(void);
39 int setserver(char*);
40 void doquery(char*, char*);
41 void docmd(int, char**);
42 
43 void
44 main(int argc, char *argv[])
45 {
46 	int n;
47 	Biobuf in;
48 	char *p;
49 	char *f[4];
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', prettyrrfmt);
66 	if(myipaddr(ipaddr, mntpt) < 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 prettyrrfmt(Fmt *f)
122 {
123 	RR *rp;
124 	char buf[3*Domlen];
125 	char *p, *e;
126 
127 	rp = va_arg(f->args, 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, sizeof 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 	case Taaaa:
167 		seprint(p, e, "\t%s", rp->ip->name);
168 		break;
169 	case Tptr:
170 		seprint(p, e, "\t%s", rp->ptr->name);
171 		break;
172 	case Tsoa:
173 		seprint(p, e, "\t%s %s %lud %lud %lud %lud %lud", rp->host->name,
174 			rp->rmb->name, rp->soa->serial, rp->soa->refresh, rp->soa->retry,
175 			rp->soa->expire, rp->soa->minttl);
176 		break;
177 	case Tnull:
178 		seprint(p, e, "\t%.*H", rp->null->dlen, rp->null->data);
179 		break;
180 	case Ttxt:
181 		seprint(p, e, "\t%s", rp->txt->name);
182 		break;
183 	case Trp:
184 		seprint(p, e, "\t%s %s", rp->rmb->name, rp->txt->name);
185 		break;
186 	case Tkey:
187 		seprint(p, e, "\t%d %d %d", rp->key->flags, rp->key->proto,
188 			rp->key->alg);
189 		break;
190 	case Tsig:
191 		seprint(p, e, "\t%d %d %d %lud %lud %lud %d %s",
192 			rp->sig->type, rp->sig->alg, rp->sig->labels, rp->sig->ttl,
193 			rp->sig->exp, rp->sig->incep, rp->sig->tag, rp->sig->signer->name);
194 		break;
195 	case Tcert:
196 		seprint(p, e, "\t%d %d %d",
197 			rp->sig->type, rp->sig->tag, rp->sig->alg);
198 		break;
199 	default:
200 		break;
201 	}
202 out:
203 	return fmtstrcpy(f, buf);
204 }
205 
206 void
207 logsection(char *flag, RR *rp)
208 {
209 	if(rp == nil)
210 		return;
211 	print("\t%s%R\n", flag, rp);
212 	for(rp = rp->next; rp != nil; rp = rp->next)
213 		print("\t      %R\n", rp);
214 }
215 
216 void
217 logreply(int id, uchar *addr, DNSmsg *mp)
218 {
219 	RR *rp;
220 	char buf[12];
221 	char resp[32];
222 
223 	switch(mp->flags & Rmask){
224 	case Rok:
225 		strcpy(resp, "OK");
226 		break;
227 	case Rformat:
228 		strcpy(resp, "Format error");
229 		break;
230 	case Rserver:
231 		strcpy(resp, "Server failed");
232 		break;
233 	case Rname:
234 		strcpy(resp, "Nonexistent");
235 		break;
236 	case Runimplimented:
237 		strcpy(resp, "Unimplemented");
238 		break;
239 	case Rrefused:
240 		strcpy(resp, "Refused");
241 		break;
242 	default:
243 		sprint(resp, "%d", mp->flags & Rmask);
244 		break;
245 	}
246 
247 	print("%d: rcvd %s from %I (%s%s%s%s%s)\n", id, resp, addr,
248 		mp->flags & Fauth ? "authoritative" : "",
249 		mp->flags & Ftrunc ? " truncated" : "",
250 		mp->flags & Frecurse ? " recurse" : "",
251 		mp->flags & Fcanrec ? " can_recurse" : "",
252 		mp->flags & (Fauth|Rname) == (Fauth|Rname) ?
253 		" nx" : "");
254 	for(rp = mp->qd; rp != nil; rp = rp->next)
255 		print("\tQ:    %s %s\n", rp->owner->name, rrname(rp->type, buf, sizeof buf));
256 	logsection("Ans:  ", mp->an);
257 	logsection("Auth: ", mp->ns);
258 	logsection("Hint: ", mp->ar);
259 }
260 
261 void
262 logsend(int id, int subid, uchar *addr, char *sname, char *rname, int type)
263 {
264 	char buf[12];
265 
266 	print("%d.%d: sending to %I/%s %s %s\n", id, subid,
267 		addr, sname, rname, rrname(type, buf, sizeof buf));
268 }
269 
270 RR*
271 getdnsservers(int class)
272 {
273 	RR *rr;
274 
275 	if(servername == nil)
276 		return dnsservers(class);
277 
278 	rr = rralloc(Tns);
279 	rr->owner = dnlookup("local#dns#servers", class, 1);
280 	rr->host = dnlookup(servername, class, 1);
281 
282 	return rr;
283 }
284 
285 void
286 squirrelserveraddrs(void)
287 {
288 	RR *rr, *rp, **l;
289 	Request req;
290 
291 	/* look up the resolver address first */
292 	resolver = 0;
293 	debug = 0;
294 	if(serveraddrs)
295 		rrfreelist(serveraddrs);
296 	serveraddrs = nil;
297 	rr = getdnsservers(Cin);
298 	l = &serveraddrs;
299 	for(rp = rr; rp != nil; rp = rp->next){
300 		if(strcmp(ipattr(rp->host->name), "ip") == 0){
301 			*l = rralloc(Ta);
302 			(*l)->owner = rp->host;
303 			(*l)->ip = rp->host;
304 			l = &(*l)->next;
305 			continue;
306 		}
307 		req.isslave = 1;
308 		req.aborttime = now + 60;	/* don't spend more than 60 seconds */
309 		*l = dnresolve(rp->host->name, Cin, Ta, &req, 0, 0, Recurse, 0, 0);
310 		while(*l != nil)
311 			l = &(*l)->next;
312 	}
313 	resolver = 1;
314 	debug = 1;
315 }
316 
317 void
318 preloadserveraddrs(void)
319 {
320 	RR *rp, **l, *first;
321 
322 	l = &first;
323 	for(rp = serveraddrs; rp != nil; rp = rp->next){
324 		rrcopy(rp, l);
325 		rrattach(first, 1);
326 	}
327 }
328 
329 int
330 setserver(char *server)
331 {
332 	if(servername != nil){
333 		free(servername);
334 		servername = nil;
335 		resolver = 0;
336 	}
337 	if(server == nil || *server == 0)
338 		return 0;
339 	servername = strdup(server);
340 	squirrelserveraddrs();
341 	if(serveraddrs == nil){
342 		print("can't resolve %s\n", servername);
343 		resolver = 0;
344 	} else {
345 		resolver = 1;
346 	}
347 	return resolver ? 0 : -1;
348 }
349 
350 void
351 doquery(char *name, char *tstr)
352 {
353 	Request req;
354 	RR *rr, *rp;
355 	int len, type;
356 	char *p, *np;
357 	int rooted;
358 	char buf[1024];
359 
360 	if(resolver)
361 		preloadserveraddrs();
362 
363 	/* default to an "ip" request if alpha, "ptr" if numeric */
364 	if(tstr == nil || *tstr == 0) {
365 		if(strcmp(ipattr(name), "ip") == 0)
366 			tstr = "ptr";
367 		else
368 			tstr = "ip";
369 	}
370 
371 	/* if name end in '.', remove it */
372 	len = strlen(name);
373 	if(len > 0 && name[len-1] == '.'){
374 		rooted = 1;
375 		name[len-1] = 0;
376 	} else
377 		rooted = 0;
378 
379 	/* inverse queries may need to be permuted */
380 	strncpy(buf, name, sizeof buf);
381 	if(strcmp("ptr", tstr) == 0
382 	&& strstr(name, "IN-ADDR") == 0
383 	&& strstr(name, "in-addr") == 0){
384 		for(p = name; *p; p++)
385 			;
386 		*p = '.';
387 		np = buf;
388 		len = 0;
389 		while(p >= name){
390 			len++;
391 			p--;
392 			if(*p == '.'){
393 				memmove(np, p+1, len);
394 				np += len;
395 				len = 0;
396 			}
397 		}
398 		memmove(np, p+1, len);
399 		np += len;
400 		strcpy(np, "in-addr.arpa");
401 	}
402 
403 	/* look it up */
404 	type = rrtype(tstr);
405 	if(type < 0){
406 		print("!unknown type %s\n", tstr);
407 		return;
408 	}
409 
410 	getactivity(&req);
411 	req.isslave = 1;
412 	req.aborttime = now + 60;	/* don't spend more than 60 seconds */
413 	rr = dnresolve(buf, Cin, type, &req, 0, 0, Recurse, rooted, 0);
414 	if(rr){
415 		print("----------------------------\n");
416 		for(rp = rr; rp; rp = rp->next)
417 			print("answer %R\n", rp);
418 		print("----------------------------\n");
419 	}
420 	rrfreelist(rr);
421 
422 	putactivity();
423 }
424 
425 void
426 docmd(int n, char **f)
427 {
428 	int tmpsrv;
429 	char *name, *type;
430 
431 	name = nil;
432 	type = nil;
433 	tmpsrv = 0;
434 
435 	if(*f[0] == '@') {
436 		if(setserver(f[0]+1) < 0)
437 			return;
438 
439 		switch(n){
440 		case 3:
441 			type = f[2];
442 			/* fall through */
443 		case 2:
444 			name = f[1];
445 			tmpsrv = 1;
446 			break;
447 		}
448 	} else {
449 		switch(n){
450 		case 2:
451 			type = f[1];
452 			/* fall through */
453 		case 1:
454 			name = f[0];
455 			break;
456 		}
457 	}
458 
459 	if(name == nil)
460 		return;
461 
462 	doquery(name, type);
463 
464 	if(tmpsrv)
465 		setserver("");
466 }
467