#!/usr/bin/perl

#  $Id: replayconv,v 1.1 2009/04/01 07:24:56 fujiwara Exp $
#
#  Copyright (C) 1998-2006 Kazunori Fujiwara <fujiwara@wide.ad.jp>.
#  All rights reserved.
#
#  replayconv is copyrighted free software
#  by Kazunori Fujiwara <fujiwara@wide.ad.jp>.
#  You can redistribute it and/or modify it
#  under either the terms of the GPL version 2.
#  GPL is shown in <http://www.gnu.org/licenses/gpl.html>.
#
# This program reads BIND 9 querylog and outputs dns_replay input file.

use strict;
use Getopt::Std;

my $start = -1;
my $precision;
my ($qname, $qclass, $qtype, $opt, $date0, $date1, $edns);
my $opts;
my $factor;

my @sametimedata;
my $prevtime = -1;
undef @sametimedata;

our ($opt_t);
getopts('t:');
$factor = defined($opt_t) ? $opt_t : 1;
#print "factor=$factor [$opt_t]\n";
#====================================================================
my %typemap = (
  'a' => '1',
  'ns' => '2',
  'md' => '3',
  'mf' => '4',
  'cname' => '5',
  'soa' => '6',
  'mb' => '7',
  'mg' => '8',
  'mr' => '9',
  'null' => '10',
  'wks' => '11',
  'ptr' => '12',
  'hinfo' => '13',
  'minfo' => '14',
  'mx' => '15',
  'txt' => '16',
  'x25' => '19',
  'isdn' => '20',
  'rt' => '21',
  'nsap' => '22',
  'nsap_ptr' => '23',
  'sig' => '24',
  'key' => '25',
  'px' => '26',
  'gpos' => '27',
  'aaaa' => '28',
  'loc' => '29',
  'nxt' => '30',
  'eid' => '31',
  'nimloc' => '32',
  'srv' => '33',
  'atma' => '34',
  'naptr' => '35',
  'kx' => '36',
  'cert' => '37',
  'a6' => '38',
  'dname' => '39',
  'sink' => '40',
  'opt' => '41',
  'apl' => '42',
  'ds' => '43',
  'sshfp' => '44',
  'ipseckey' => '45',
  'rrsig' => '46',
  'nsec' => '47',
  'dnskey' => '48',
  'dhcid' => '49',
  'spf' => '99',
  'uinfo' => 100,
  'uid' => 101,
  'gif' => 102,
  'unspec' => 103,
  'tkey' => 249,
  'tsig' => 250,
  'ixfr' => '251',
  'axfr' => '252',
  'mailb' => '253',
  'maila' => '254',
  'any' => '255',
  'ta' => 32768,
  'dlv' => 32769);

sub qtype_to_num
{
	my ($b) = @_;
	$b =~ y/A-Z/a-z/;
	if ($b =~ /^type(\d+)$/) {
		$b = $1;
	} elsif (defined($typemap{$b})) {
		$b = $typemap{$b};
	} else {
		$b = 0;
	}
	return $b;
}

while (<>) {
	chomp;
	if (/^.* (\d\d):(\d\d):(\d\d)(\.\d\d\d)? .* query: (\S+) (\S+) (\S+) (\S+)$/) {
		$qname = $5; $qclass = $6; $qtype = $7; $opt = $8;
		$date0 = $1 * 3600 + $2 * 60 + $3 + $4; $date1 = $4;
		$qtype =~ y/A-Z/a-z/;
		$qtype = &qtype_to_num($qtype);
		if ($qname =~ /^[a-zA-Z0-9-._]+$/) {
			print STDERR "wrong qname: $_\n";
			next;
		}
	} else {
		print STDERR "format error: $_\n";
		next;
	}
	if ($start < 0) {
		$start = $date0;
		if ($date1 eq "") {
			$precision = int(1000000 / $factor);
		} else {
			$precision = int(1000 / $factor);
		}
	}
	if ($prevtime != $date0 && $#sametimedata >= 0) {
		&flush;
	}
	$prevtime = $date0;
	$edns = ($opt =~ /E/) ? "E" : "e";
	push @sametimedata, "$qname $qtype $edns";
}
&flush if ($#sametimedata >= 0);

sub flush
{
	# flush
	my $count = $#sametimedata + 1;
	my $step = int($precision / $count);
	my $sum;
	my $step2 = int (($date0 - $prevtime) * 1000000 / $factor + 0.5) - $precision;
	for (my $i = 0; $i < $count-1; $i++) {
		$sum += $step;
		print $sametimedata[$i], " ", $step, "\n";
	}
	print $sametimedata[$count-1], " ", $precision - $sum + $step2, "\n";
	undef @sametimedata;
}
