Jacob Moodyndb/dns: DoT support7514eab2 years agoHistory
313 lines · 5.5 KB · C
RawDownload
#include <u.h>#include <libc.h>#include <bio.h>#include <ctype.h>#include <ip.h>#include <ndb.h>#include "dns.h" Cfg cfg; char	*dbfile;char	*logfile = "dnsdebug";int	debug;char	mntpt[Maxpath]; static char *servername; void	docmd(int, char**);void	doquery(char*, char*);int	setserver(char*); #pragma	varargck	type	"P"	RR*int	prettyrrfmt(Fmt*); voidusage(void){	fprint(2, "%s: [-crdx] [-f db-file] [[@server] domain [type]]\n", argv0);	exits("usage");} voidmain(int argc, char *argv[]){	int n;	Biobuf in;	char *p;	char *f[4]; 	strcpy(mntpt, "/net"); 	ARGBEGIN{	case 'f':		dbfile = EARGF(usage());		break;	case 'c':		cfg.cachedb = 1;		break;	case 'r':		cfg.resolver = 1;		break;	case 'd':		debug = 1;		break;	case 'x':		dbfile = "/lib/ndb/external";		strcpy(mntpt, "/net.alt");		break;	default:		usage();	}ARGEND 	dninit();	fmtinstall('P', prettyrrfmt);	opendatabase();	srand(truerand());	db2cache(1); 	if(argc > 0){		docmd(argc, argv);		exits(0);	} 	Binit(&in, 0, OREAD);	for(print("> "); p = Brdline(&in, '\n'); print("> ")){		p[Blinelen(&in)-1] = 0;		n = tokenize(p, f, 3);		if(n>=1) {			docmd(n, f);		}	}	exits(0);} static char*longtime(long t){	int d, h, m, n;	static char x[128]; 	for(d = 0; t >= 24*60*60; t -= 24*60*60)		d++;	for(h = 0; t >= 60*60; t -= 60*60)		h++;	for(m = 0; t >= 60; t -= 60)		m++;	n = 0;	if(d)		n += sprint(x, "%d day ", d);	if(h)		n += sprint(x+n, "%d hr ", h);	if(m)		n += sprint(x+n, "%d min ", m);	if(t || n == 0)		sprint(x+n, "%ld sec", t);	return x;} intprettyrrfmt(Fmt *f){	char tname[32], *strp, *t;	Fmt fstr;	RR *rp;	int rv; 	fmtstrinit(&fstr);	rp = va_arg(f->args, RR*);	fmtprint(&fstr, "%R", rp);	strp = fmtstrflush(&fstr);	if((t = strchr(strp, '\t')) == nil || rp == nil)		rv = fmtstrcpy(f, strp);	else		rv = fmtprint(f, "%-32.32s %-15.15s %-5.5s%s",			rp->owner->name, longtime(rp->ttl),			rrname(rp->type, tname, sizeof tname), t);	free(strp);	return rv;} voidlogsection(char *flag, RR *rp){	if(rp == nil)		return;	print("\t%s%P\n", flag, rp);	for(rp = rp->next; rp != nil; rp = rp->next)		print("\t      %P\n", rp);} voidlogreply(int id, char *rcvd, uchar *addr, DNSmsg *mp){	char tname[32];	RR *rp; 	print("%d: %s %I %s (%s%s%s%s%s)\n", id, rcvd, addr, rcname(getercode(mp)),		mp->flags & Fauth? "authoritative": "",		mp->flags & Ftrunc? " truncated": "",		mp->flags & Frecurse? " recurse": "",		mp->flags & Fcanrec? " can_recurse": "",		(mp->flags & (Fauth|Rmask)) == (Fauth|Rname)? " nx": "");	for(rp = mp->qd; rp != nil; rp = rp->next)		print("\tQ:    %s %s\n", rp->owner->name,			rrname(rp->type, tname, sizeof tname));	logsection("Ans:  ", mp->an);	logsection("Auth: ", mp->ns);	logsection("Hint: ", mp->ar);} voidlogrequest(int id, int depth, char *send, uchar *addr, char *sname, char *rname, int type){	char tname[32]; 	print("%d.%d: %s %I/%s %s %s\n", id, depth, send,		addr, sname, rname, rrname(type, tname, sizeof tname));} RR*getdnsservers(int class){	uchar ip[IPaddrlen];	DN *nsdp;	RR *rp, *ns;	char name[64]; 	if(servername == nil)		return dnsservers(class); 	snprint(name, sizeof name, "override#%s#server", servername[0] == '!' ? "dot" : "dns");	ns = rralloc(Tns);	if(parseip(ip, servername+1) == -1){		nsdp = idnlookup(servername+1, class, 1);	} else {		nsdp = dnlookup(name, class, 1);		rp = rralloc(isv4(ip) ? Ta : Taaaa);		rp->owner = nsdp;		rp->ip = ipalookup(ip, class, 1);		rp->db = 1;		rp->ttl = 10*Min;		rrattach(rp, Authoritative);	}	ns->owner = dnlookup(name, class, 1);	ns->host = nsdp;	return ns;} intsetserver(char *server){	if(servername != nil){		free(servername);		servername = nil;		cfg.resolver = 0;	}	if(server == nil || server[0] == 0 || server[1] == 0)		return 0;	servername = estrdup(server);	cfg.resolver = 1;	return 0;} voiddoquery(char *name, char *tstr){	int len, type, rooted;	char buf[1024];	RR *rr, *rp;	Request req; 	/* default to an "ip" request if alpha, "ptr" if numeric */	if(tstr == nil || *tstr == 0)		if(strcmp(ipattr(name), "ip") == 0)			tstr = "ptr";		else			tstr = "ip"; 	/* look it up */	type = rrtype(tstr);	if(type < 0){		print("!unknown type %s\n", tstr);		return;	} 	/* if name end in '.', remove it */	len = strlen(name);	if(len > 0 && name[len-1] == '.'){		rooted = 1;		name[len-1] = 0;	} else		rooted = 0; 	/* inverse queries may need to be permuted */	if(type == Tptr)		mkptrname(name, buf, sizeof buf);	else		strncpy(buf, name, sizeof buf); 	memset(&req, 0, sizeof req);	getactivity(&req);	req.isslave = 1;	req.aborttime = timems() + Maxreqtm;	req.from = argv0; 	rr = dnresolve(buf, Cin, type, &req, nil, 0, Recurse, rooted, nil);	if(rr){		print("----------------------------\n");		for(rp = rr; rp; rp = rp->next)			print("answer %P\n", rp);		print("----------------------------\n");	}	rrfreelist(rr);	putactivity(&req);} voiddocmd(int n, char **f){	int tmpsrv;	char *name, *type; 	if(n == 1 && strcmp(f[0], "refresh") == 0){		db2cache(1);		dnageall(1);		return;	} 	name = type = nil;	tmpsrv = 0; 	if(*f[0] == '@' || *f[0] == '!') {		if(setserver(f[0]) < 0)			return; 		switch(n){		case 3:			type = f[2];			/* fall through */		case 2:			name = f[1];			tmpsrv = 1;			break;		}	} else		switch(n){		case 2:			type = f[1];			/* fall through */		case 1:			name = f[0];			break;		} 	if(name == nil)		return; 	if(!cfg.cachedb) dnpurge();		/* flush the cache */	doquery(name, type); 	if(tmpsrv)		setserver("@");}