shithub: purgatorio

ref: 3efb5bbb4061056e523858b134c555949591efe2
dir: /appl/cmd/ndb/dnsquery.b/

View raw version
implement Dnsquery;

#
# Copyright © 2003 Vita Nuova Holdings LImited.  All rights reserved.
#

include "sys.m";
	sys: Sys;

include "draw.m";

include "bufio.m";
	bufio: Bufio;
	Iobuf: import bufio;

include "arg.m";

Dnsquery: module
{
	init:	fn(nil: ref Draw->Context, nil: list of string);
};

usage()
{
	sys->fprint(sys->fildes(2), "usage: dnsquery [-x /net] [-s server] [address ...]\n");
	raise "fail:usage";
}

init(nil: ref Draw->Context, args: list of string)
{
	sys = load Sys Sys->PATH;
	bufio = load Bufio Bufio->PATH;
	if(bufio == nil)
		cantload(Bufio->PATH);

	net := "/net";
	server: string;
	arg := load Arg Arg->PATH;
	if(arg == nil)
		cantload(Arg->PATH);
	arg->init(args);
	while((c := arg->opt()) != 0)
		case c {
		'x' =>
			net = arg->arg();
			if(net == nil)
				usage();
		's' =>
			server = arg->arg();
			if(server == nil)
				usage();
		* =>
			usage();
		}
	args = arg->argv();
	arg = nil;

	if(server == nil)
		server = net+"/dns";
	if(args != nil){
		for(; args != nil; args = tl args)
			dnsquery(server, hd args);
	}else{
		f := bufio->fopen(sys->fildes(0), Sys->OREAD);
		if(f == nil)
			exit;
		for(;;){
			sys->print("> ");
			s := f.gets('\n');
			if(s == nil)
				break;
			dnsquery(server, s[0:len s-1]);
		}
	}
}

cantload(s: string)
{
	sys->fprint(sys->fildes(2), "dnsquery: can't load %s: %r\n", s);
	raise "fail:load";
}

dnsquery(server: string, query: string)
{
	dns := sys->open(server, Sys->ORDWR);
	if(dns == nil){
		sys->fprint(sys->fildes(2), "dnsquery: can't open %s: %r\n", server);
		raise "fail:open";
	}
	stdout := sys->fildes(1);
	for(i := len query; --i >= 0 && query[i] != ' ';)
		{}
	if(i < 0){
		i = len query;
		case dbattr(query) {
		"ip" =>
			query += " ptr";
		* =>
			query += " ip";
		}
	}
	if(query[i+1:] == "ptr"){
		while(i > 0 && query[i-1] == ' ')
			i--;
		if(!hastail(query[0:i], ".in-addr.arpa") && !hastail(query[0:i], ".IN-ADDR.ARPA"))
			query = addr2arpa(query[0:i])+" ptr";
	}
	b := array of byte query;
	if(sys->write(dns, b, len b) > 0){
		sys->seek(dns, big 0, Sys->SEEKSTART);
		buf := array[256] of byte;
		while((n := sys->read(dns, buf, len buf)) > 0)
			sys->print("%s\n", string buf[0:n]);
		if(n == 0)
			return;
	}
	sys->print("!%r\n");
}

hastail(s: string, t: string): int
{
	if(len s >= len t && s[len s - len t:] == t)
		return 1;
	return 0;
}

addr2arpa(a: string): string
{
	(nf, flds) := sys->tokenize(a, ".");
	rl: list of string;
	for(; flds != nil; flds = tl flds)
		rl = hd flds :: rl;
	addr: string;
	for(; rl != nil; rl = tl rl){
		if(addr != nil)
			addr[len addr] = '.';
		addr += hd rl;
	}
	return addr+".in-addr.arpa";
}

dbattr(s: string): string
{
	digit := 0;
	dot := 0;
	alpha := 0;
	hex := 0;
	colon := 0;
	for(i := 0; i < len s; i++){
		case c := s[i] {
		'0' to '9' =>
			digit = 1;
		'a' to 'f' or 'A' to 'F' =>
			hex = 1;
		'.' =>
			dot = 1;
		':' =>
			colon = 1;
		* =>
			if(c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c == '-' || c == '&')
				alpha = 1;
		}
	}
	if(alpha){
		if(dot)
			return "dom";
		return "sys";
	}
	if(colon)
		return "ip";
	if(dot){
		if(!hex)
			return "ip";
		return "dom";
	}
	return "sys";
}