plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

dnsdebug.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->host->name,
    186 			rp->rmb->name, rp->soa->serial, rp->soa->refresh, rp->soa->retry,
    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->proto,
    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->sig->ttl,
    207 			rp->sig->exp, rp->sig->incep, rp->sig->tag, rp->sig->signer->name);
    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->type, buf, sizeof buf));
    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 type)
    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 than 60 seconds */
    322 		*l = dnresolve(rp->host->name, Cin, Ta, &req, 0, 0, Recurse, 0, 0);
    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 seconds */
    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 }