#!/usr/local/bin/perl
# dnslog.pl v1.11
# 20080729 00:01 (GMT-04:00) Jeremy Kister - http://jeremy.kister.net/
# Function: make tinydns/dnscache logs a little more human friendly
# Released under Perl's Artistic License
#

use strict;

chdir('/'); # be nice

my %rrs = ('0001'=>'A','0002'=>'NS','0005'=>'CNAME','0006'=>'SOA','000c'=>'PTR',
           '000f'=>'MX','0010'=>'TXT','001c'=>'AAAA','0021'=>'SRV','0023'=>'NAPTR',
           '0026'=>'A6','00fb'=>'IXFR','00fc'=>'AXFR','00ff'=>'ANY',
           1=>'A',2=>'NS',5=>'CNAME',6=>'SOA',12=>'PTR',15=>'MX',16=>'TXT',28=>'AAAA', 
           33=>'SRV',35=>'NAPTR',38=>'A6',251=>'IXFR',252=>'AXFR',255=>'ANY'); 

$|=1;
my %nscache;
while(<STDIN>){
	if(substr($_,0,1) eq 'q'){
		my ($a,$b,$ipinfo,$rr,$e) = split; 
		my ($hip,$hport,$hid) = split /:/, $ipinfo;
		my $ip = join('.', unpack('C*', pack('H8', $hip)));
		my $port = hex($hport);
		my $id = hex($hid);
		
		my $name = get_a_rr($ip);
		print "$a $b $name $port $id $rrs{$rr} $e\n"; 
	}elsif(/^(tcp(?:open|close))\s+([^:]+):(.{4})(?:\s(.+))?/){
		my $ip = join('.', unpack('C*', pack('H8', $2)));
		my $port = hex($3);
	
		my $name = get_a_rr($ip);
		print "$1 $name:$port $4\n";
	}elsif(/^(.{8}):(.{4}):(.{4})\s(.)\s(.{4})\s(.+)/){
		my $ip = join('.', unpack('C*', pack('H8', $1)));
		my $port = hex($2);
		my $id = hex($3);
		my $lame = $4;
		my $rr = $rrs{$5};
		my $query = $6;
		$query =~ s#\\(\d{3})#chr(oct($1))#ge;

		my $name = get_a_rr($ip);
		printf("%15s:%5s:%5s: %s %5s %s\n", $name, $port, $id, $lame, $rr, $query);
	}else{
		print;
	}
}

sub get_a_rr {
	my $ipaddr = shift;
	
	return($ipaddr) unless($ARGV[0] eq '-l');
	return($nscache{$ipaddr}) if(defined($nscache{$ipaddr}));

	my $hostname = $ipaddr;

	eval {
		local $SIG{ALRM} = sub { die "timed out on $ipaddr.\n"; };
		alarm(2);
		$hostname = gethostbyaddr(pack('C4', split(/\./, $ipaddr)),2);
		alarm(0);
	};
	alarm(0);

	$nscache{$ipaddr} = $hostname;

	return($hostname);
}
