#!/usr/bin/perl -w

=head1 NAME

namedlogsumm.pl - Produce Named/Bind logfile summary

Copyright (C) 2016 by Paweł Sobota, Release 0.56 prebeta ;)

=head1 SYNOPSIS

    namedlogsumm.pl [-t <cnt>] [-n <cnt>] [-a <cnt>] [-s <cnt>] [-d <today|yesterday|date>]
    [file1 [filen]]

    namedlogsumm.pl -[help|version]

    If no file(s) specified, reads from stdin.  Output is to stdout.



=head1 DESCRIPTION

    namedlogsumm is a log analyzer/summarizer for the Named/Bind DNS.
    It is designed to provide an over-view of named/bind activity,
    with just enough detail to give the administrator a "heads up"
    for potential trouble spots.
    
    namedlogsumm generates summaries and, in some cases, detailed reports of
    dns server traffic volumes, queries type and names, and server
    warnings, errors and others.



=head1 OPTIONS

    -t <cnt>
    -n <cnt>
    -a <cnt>
    -s <cnt>
    -d <today|yesterday|date>



=head1 RETURN VALUE

    namedlogsumm doesn't return anything of interest to the shell.



=head1 ERRORS

    Error messages are emitted to stderr.



=head1 EXAMPLES

    Produce a report of previous day's activities:

        namedlogsumm.pl -t 25 -n 25 -a 25 -s 25 -d yesterday /var/log/named/named.log /var/log/named/queries.log

    What's happened so far today:

        namedlogsumm.pl -t 25 -n 25 -a 25 -s 25 -d today /var/log/named/named.log /var/log/named/queries.log

    Crontab entry to generate a report of the previous day's activity
    at 10 minutes after midnight.

    10 0 * * * /usr/local/sbin/namedlogsumm.pl -t 25 -n 25 -a 25 -s 25 -d yesterday /var/log/named/named.log /var/log/named/queries.log 2>&1 | /usr/bin/mailx -s "`uname -n` daily bind stats" postmaster
    05   6   *   *   *   root /usr/sbin/namedlogsumm.cron >/dev/null

    Crontab entry to generate a report for the prior week's activity.
    (This example assumes one rotates ones mail logs weekly, some time
    before 4:10 a.m. on Sunday.)

    10 4 * * 0   /usr/local/sbin/namedlogsumm.pl -t 25 -n 25 -a 25 -s 25 -d yesterday /var/log/named/named.log /var/log/named/queries.log 2>&1 | /usr/bin/mailx -s "`uname -n` weekly bind stats" postmaster
    05   6   *   *   *   root /usr/sbin/namedlogsumm.cron >/dev/null

    The two crontab examples, above, must actually be a single line each.

=head1 SEE ALSO

    The namedlogsumm FAQ: namedlogsumm-faq.txt.

=head1 NOTES

    namedlogsumm makes no attempt to catch/parse non-Named/Bind log entries.
    Result will be unpredictible.

    The namedlogsumm Home Page is at:

    http://devel.wbcd.pl/systools/namedlogsumm

=head1 REQUIREMENTS

    namedlogsumm requires the POSIX(strftime mktime), File::Basename module,
    which is in perl Core package

    namedlogsumm is currently written and tested under Perl 5.10.1
    As of version, pflogsumm worked with Perl 5.10.1, but
    future compatibility is not guaranteed.

=head1 LICENSE

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation; either version 2
    of the License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You may have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
    USA.

    An on-line copy of the GNU General Public License can be found
    http://www.fsf.org/copyleft/gpl.html.

=cut

# 2017/08/13 --cutclientport - cut port number from ipaddr#ipport

# 2017/11/11 --splitquerylanwan - split queries per LAN WAN summary

# 2017/11/26 --splitquerylanwan - split queries Summary + query types(A,AAAA,PTR.NS,MX,...) per LAN WAN summary



use strict;      # force definations for all vars an subroutines
use warnings;    # force check of unset variables in expressions
use diagnostics; # give var/code line number on faults

use File::Basename; # for basename(), dirname(),
use POSIX qw(strftime); # for strftime(),
use POSIX qw(mktime); # for mktime(),



my $self=basename(__FILE__);



####################
#####   ARGS   #####
####################
my (%MYARG, $argi);

$MYARG{'filename'}=undef;
$MYARG{'greptime'}=undef;
$MYARG{'grepdate'}=undef; # strftime('%b %e', localtime());#strftime("%b %e", localtime( $MYARG{'greptime'} ));
$MYARG{'maxtypes'}=25;
$MYARG{'maxnames'}=25;
$MYARG{'maxarpas'}=25;
$MYARG{'maxaddrs'}=25;
$MYARG{'sortquerytypes'}=0;
$MYARG{'showlongstat'}=0;
$MYARG{'cutclientport'}=0;
$MYARG{'splitquerylanwan'}=0;

$argi=0;
while ($argi<$#ARGV+1) {
	#print("\$ARGV[$argi]=|".$ARGV[$argi]."|\n");
	if ($ARGV[$argi] eq '--help') {
		&usage();
		exit(0);
	}
	if ($ARGV[$argi] eq '-l') {
		if ($argi+1<$#ARGV+1) { push(@{$MYARG{'logsfile'}}, $ARGV[$argi+1]); $argi++; $argi++; next; }
		else                  { print("$self: option -l require argument\n"); exit(1); }
	}
	if ($ARGV[$argi] eq '-d') {
		if ($argi+1<$#ARGV+1) { $MYARG{'grepdate'}=$ARGV[$argi+1]; $argi++; $argi++; next; } ### $MYARG{'greptime'}=str2time($ARGV[$argi+1]);
		else                  { print("$self: option -d require argument\n"); exit(1); }
	}
	
	if ($ARGV[$argi] eq '-t') {
		if ($argi+1<$#ARGV+1) { $MYARG{'maxtypes'}=$ARGV[$argi+1]; $argi++; $argi++; next; }
		else                  { print("$self: option -t require argument\n"); exit(1); }
	}
	if ($ARGV[$argi] eq '-n') {
		if ($argi+1<$#ARGV+1) { $MYARG{'maxnames'}=$ARGV[$argi+1]; $argi++; $argi++; next; }
		else                  { print("$self: option -n require argument\n"); exit(1); }
	}
	if ($ARGV[$argi] eq '-a') {
		if ($argi+1<$#ARGV+1) { $MYARG{'maxarpas'}=$ARGV[$argi+1]; $argi++; $argi++; next; }
		else                  { print("$self: option -a require argument\n"); exit(1); }
	}
	if ($ARGV[$argi] eq '-s') {
		if ($argi+1<$#ARGV+1) { $MYARG{'maxaddrs'}=$ARGV[$argi+1]; $argi++; $argi++; next; }
		else                  { print("$self: option -s require argument\n"); exit(1); }
	}
	
	if ($ARGV[$argi] eq '--sortquerytypes') {
		$MYARG{'sortquerytypes'}=1; $argi++; next;
	}
	if ($ARGV[$argi] eq '--showlongstat') {
		$MYARG{'showlongstat'}=1; $argi++; next;
	}
	if ($ARGV[$argi] eq '--cutclientport') {
		$MYARG{'cutclientport'}=1; $argi++; next;
	}
	if ($ARGV[$argi] eq '--splitquerylanwan') {
		$MYARG{'splitquerylanwan'}=1; $argi++; next;
	}
	
	if (substr($ARGV[$argi],0,1) eq '-') {
		print("$self: Unknown argument: '$ARGV[$argi]'\n");
		exit(1);
	}
	last;
	#print("$self: Unknown option $ARGV[$argi]\n"); exit(1);
}

while ($argi<$#ARGV+1) {
	push(@{$MYARG{'logsfile'}}, $ARGV[$argi]);
	$argi++;
}



#################
# validate args #
#################
if (!defined($MYARG{'grepdate'})) { &usage(1); exit(); }
if (!defined($MYARG{'logsfile'})) { &usage(2); exit(); }

my ($YYYY, $mm, $dd, $HH, $MM, $SS);
if ($MYARG{'grepdate'}=~m/^([0-9][0-9][0-9][0-9])[\/\.-]([0-1][0-9]|Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)[\/\.-]([0-3][0-9])$/) { ($YYYY, $mm, $dd, $HH, $MM, $SS)=($1,$2,$3, 0,0,0); }
if ($MYARG{'grepdate'}=~m/^([0-3][0-9])[\/\.-]([0-1][0-9]|Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)[\/\.-]([0-9][0-9][0-9][0-9])$/) { ($YYYY, $mm, $dd, $HH, $MM, $SS)=($3,$2,$1, 0,0,0); }
if (defined($YYYY) && defined($mm) && defined($dd)) {
	my %M2D=('Jan'=>1,'Feb'=>2,'Mar'=>3,'Apr'=>4,'May'=>5,'Jun'=>6,'Jul'=>7,'Aug'=>8,'Sep'=>9,'Oct'=>10,'Nov'=>11,'Dec'=>12);
	#print("|($YYYY, $mm, $dd, $HH, $MM, $SS)|\n");
	if (defined($M2D{$mm})) { $mm=$M2D{$mm}; }
	if ($YYYY>1900) { $YYYY=$YYYY-1900; }
	if ($mm>0) { $mm=$mm-1; }
	$MYARG{'greptime'}=mktime( $SS, $MM, $HH, $dd, $mm, $YYYY );
	if (!defined($MYARG{'greptime'})) { print("$self: 1 option -d has invalid argument: '$MYARG{'grepdate'}'\n"); exit(1); }
}

if ($MYARG{'grepdate'} eq 'yesterday') { $MYARG{'greptime'}=time() - 86400; }
if ($MYARG{'grepdate'} eq 'today')     { $MYARG{'greptime'}=time() -     0; }
if (!defined($MYARG{'greptime'})) { print("$self: 2 option -d has invalid argument: '$MYARG{'grepdate'}'\n"); exit(1); }
$MYARG{'grepdate'}=strftime("%d-%b-%Y", localtime( $MYARG{'greptime'} ));
#print("|$MYARG{'greptime'}| = |$MYARG{'grepdate'}|\n");
#exit();



sub usage {
#print("|@_|\n");
printf qq{Usage: $self [-d <today|yesterday|date>] [-h <cnt>] [-u <cnt>] [file1]

       $self --help
       ### $self --version
};
print("Usage: $0 -t 25 -n 25 -a 25 -s 25 -d yesterday /var/log/named/named.log /var/log/named/queries.log\n");
}










#########################
#####   INIT DATA   #####
#########################

# /* Type field of Query and Answer */
# #define QTYPE_A     0x01 /*   1 */ /* A, IPv4 address */
# #define QTYPE_IPv4  0x01 /*   1 */ /* A, IPv4 address */
# #define QTYPE_NS    0x02 /*   2 */ /* NS, Authoritative name server */
# #define QTYPE_CNAME 0x05 /*   5 */ /* CNAME, Canonical name for an alias */
# #define QTYPE_SOA   0x06 /*   6 */ /* SOA, Marks the start of a zone of authority */
# #define QTYPE_NULL  0x0A /*  10 */ /* NULL, Null resource record */
# #define QTYPE_PTR   0x0C /*  12 */ /* PTR, Domain name pointer */
# #define QTYPE_HINFO 0x0D /*  13 */
# #define QTYPE_MINFO 0x0E /*  14 */
# #define QTYPE_MX    0x0F /*  15 */ /* MX, Mail exchange */
# #define QTYPE_TXT   0x10 /*  16 */ /* TXT, Text strings */
# #define QTYPE_RP    0x11 /*  17 */ /* RP, Responsible Person */
# #define QTYPE_AAAA  0x1C /*  28 */ /* AAAA, IPv6 Address */
# #define QTYPE_IPv6  0x1C /*  28 */ /* AAAA, IPv6 Address */
# #define QTYPE_SRV   0x21 /*  33 */
# #define QTYPE_NAPTR 0x23 /*  35 */
# #define QTYPE_A6    0x26 /*  38 */
# #define QTYPE_AXFR  0xFC /* 252 */ /* AXFR, A request for a transfer of an entire zone */
# #define QTYPE_ANY   0xFF /* 255 */

my (%INFO,%HHLIST,%HHLLAN,%HHWWAN);
my (%QTYPE,%LTYPE,%WTYPE, %IPALAN,%IPAWAN,%IPAAAA);
my (%QNAME4,%QNAME6,%QNAMENS,%QNAMEMX,%QNAMETXT,%QNAMESOA,%QNAMEX, %QARPA4,%QARPA6);
my (%LNAME4,%LNAME6,%LNAMENS,%LNAMEMX,%LNAMETXT,%LNAMESOA,%LNAMEX, %LARPA4,%LARPA6);
my (%WNAME4,%WNAME6,%WNAMENS,%WNAMEMX,%WNAMETXT,%WNAMESOA,%WNAMEX, %WARPA4,%WARPA6);

%IPALAN=();
%IPAWAN=();
%IPAAAA=();

# QUERY ALL
%QTYPE=();
%QNAME4=();
%QNAME6=();
%QNAMENS=();
%QNAMEMX=();
%QNAMETXT=();
%QNAMESOA=();
%QNAMEX=();

%QARPA4=();
%QARPA6=();

# QUERY LAN
%LTYPE=();
%LNAME4=();
%LNAME6=();
%LNAMENS=();
%LNAMEMX=();
%LNAMETXT=();
%LNAMESOA=();
%LNAMEX=();

%LARPA4=();
%LARPA6=();

# QUERY WAN
%WTYPE=();
%WNAME4=();
%WNAME6=();
%WNAMENS=();
%WNAMEMX=();
%WNAMETXT=();
%WNAMESOA=();
%WNAMEX=();

%WARPA4=();
%WARPA6=();

for my $ii ( (0 .. 23) ) {
	my $hh=sprintf("%02d",$ii);
	$HHLIST{$hh}{'A'}     = $HHLLAN{$hh}{'A'}     = $HHWWAN{$hh}{'A'}     = 0;
	$HHLIST{$hh}{'IPv4'}  = $HHLLAN{$hh}{'IPv4'}  = $HHWWAN{$hh}{'IPv4'}  = 0;
	$HHLIST{$hh}{'NS'}    = $HHLLAN{$hh}{'NS'}    = $HHWWAN{$hh}{'NS'}    = 0;
	$HHLIST{$hh}{'CNAME'} = $HHLLAN{$hh}{'CNAME'} = $HHWWAN{$hh}{'CNAME'} = 0;
	$HHLIST{$hh}{'SOA'}   = $HHLLAN{$hh}{'SOA'}   = $HHWWAN{$hh}{'SOA'}   = 0;
	$HHLIST{$hh}{'NULL'}  = $HHLLAN{$hh}{'NULL'}  = $HHWWAN{$hh}{'NULL'}  = 0;
	$HHLIST{$hh}{'PTR'}   = $HHLLAN{$hh}{'PTR'}   = $HHWWAN{$hh}{'PTR'}   = 0;
	$HHLIST{$hh}{'HINFO'} = $HHLLAN{$hh}{'HINFO'} = $HHWWAN{$hh}{'HINFO'} = 0;
	$HHLIST{$hh}{'MINFO'} = $HHLLAN{$hh}{'MINFO'} = $HHWWAN{$hh}{'MINFO'} = 0;
	$HHLIST{$hh}{'MX'}    = $HHLLAN{$hh}{'MX'}    = $HHWWAN{$hh}{'MX'}    = 0;
	$HHLIST{$hh}{'TXT'}   = $HHLLAN{$hh}{'TXT'}   = $HHWWAN{$hh}{'TXT'}   = 0;
	$HHLIST{$hh}{'RP'}    = $HHLLAN{$hh}{'RP'}    = $HHWWAN{$hh}{'RP'}    = 0;
	$HHLIST{$hh}{'AAAA'}  = $HHLLAN{$hh}{'AAAA'}  = $HHWWAN{$hh}{'AAAA'}  = 0;
	$HHLIST{$hh}{'IPv6'}  = $HHLLAN{$hh}{'IPv6'}  = $HHWWAN{$hh}{'IPv6'}  = 0;
	$HHLIST{$hh}{'SRV'}   = $HHLLAN{$hh}{'SRV'}   = $HHWWAN{$hh}{'SRV'}   = 0;
	$HHLIST{$hh}{'NAPTR'} = $HHLLAN{$hh}{'NAPTR'} = $HHWWAN{$hh}{'NAPTR'} = 0;
	$HHLIST{$hh}{'A6'}    = $HHLLAN{$hh}{'A6'}    = $HHWWAN{$hh}{'A6'}    = 0;
	$HHLIST{$hh}{'AXFR'}  = $HHLLAN{$hh}{'AXFR'}  = $HHWWAN{$hh}{'AXFR'}  = 0;
	$HHLIST{$hh}{'ANY'}   = $HHLLAN{$hh}{'ANY'}   = $HHWWAN{$hh}{'ANY'}   = 0;
	# view external: query: net.wbcd.pl IN SPF -ED (10.5.5.5)
	# view external: query: wbcd.pl IN A6 -ED (10.5.5.5)
	$HHLIST{$hh}{'A6'}    = $HHLLAN{$hh}{'A6'}    = $HHWWAN{$hh}{'A6'}    = 0;
	$HHLIST{$hh}{'SPF'}   = $HHLLAN{$hh}{'SPF'}   = $HHWWAN{$hh}{'SPF'}   = 0;
	# if (!defined($HHLIST{10}{DS}))
	$HHLIST{$hh}{'DS'}    = $HHLLAN{$hh}{'DS'}    = $HHWWAN{$hh}{'DS'}    = 0;
	# if (!defined($HHLIST{10}{RRSIG}))
	$HHLIST{$hh}{'RRSIG'} = $HHLLAN{$hh}{'RRSIG'} = $HHWWAN{$hh}{'RRSIG'} = 0;
	# if (!defined($HHLIST{20}{TYPE})):
	# if (!defined($HHLIST{21}{TYPE})):
	$HHLIST{$hh}{'TYPE'}  = $HHLLAN{$hh}{'TYPE'}  = $HHWWAN{$hh}{'TYPE'}  = 0;
}










###############################
#####   PARSE NAMED LOG   #####
###############################

foreach my $logsfile (@{$MYARG{'logsfile'}}) {
	my ($NAMED,$line,$spa,$sph,$spc,$spn,$spt,$spe);
	my ($ipaddr,$qname,$qtype,$hh,$ii, @IP4OCT,$ipv4_uint32, @IP6OCT,$ipv6_uint32);
	
	if (!open($NAMED,"<".$logsfile)) {
		print(STDERR "Unable open(<'$logsfile'), Reason: $!\n");
		#exit(1);
		next;
	}
	
	while ($line=<$NAMED>) {
		$line=~s,[\r\n]+$,,g;
		#print("line:A=|$line|\n");
		if (substr($line,0,length($MYARG{'grepdate'})) ne $MYARG{'grepdate'}) { next; }
		#print("line:B=|$line|\n");
		
		$spt=$spa=$spe=-1;
		$spt=index($line," ");
		if ($spt>0) { $spe=index($line,":",$spt+1); }
		if ( ! (0<$spt && $spt<$spe)  ) { next; }
		$hh=substr($line, $spt+1, $spe-$spt-1); #print(basename(__FILE__).':'.__LINE__.": hh=|$hh| line=|$line|\n");
		
		$spa=$sph=$spn=$spc=$spt=-1;
		
		###############
		# queries.log #
		###############
		# 25-Jan-2017 06:45:02.471 client 10.0.0.3#46572: query: cen05.xen.wbcd.pl IN A +
		#              25          - Jan             - 2017                    06        : 45         : 02           .471                                    client   10.0.0.3    #46572 :                      query: cen05.xen.wbcd.pl IN A +
		# 27-Jan-2017 00:10:21.183 queries: info: client 10.5.5.5#46882: view internal: query: wbcd.pl IN AAAA + (10.5.5.5)
		#              27          - Jan             - 2017                    00        : 10         : 21           .183                queries: info:      client   10.5.5.5    #46882 : view internal:       query: wbcd.pl IN AAAA + (10.5.5.5)
		if ($line=~m/^([ 0-3][0-9])-([A-Z][a-z][a-z])-([0-9][0-9][0-9][0-9]) ([0-2][0-9]):([0-5][0-9]):([0-5][0-9])(\.[0-9][0-9][0-9])? (queries: info:)?[ ]*client ([0-9\.:a-f]+)#[0-9]+: (view [A-Za-z0-9_]+:)?[ ]*query: ([^ ]+) ([A-Z]+) ([A-Z]+)/) {
			$spa=index($line," client ");
			if ($spa>0) { $sph=index($line, "#", $spa+1); }
			$spn=index($line," query: ");
			if ($spn>0) { $spc=index($line, " ", $spn+length(" query: ")); }
			if ($spc>0) { $spt=index($line, " ", $spc+1); }
			# ipaddr - hash - query name - query class - query type
			$ipaddr=$9;
			$qname=$11;
			$qtype=$13;
			#print(basename(__FILE__).':'.__LINE__.": ipaddr=|$ipaddr| qname=|$qname| qtype=|$qtype|\n");
			if (0<$spa && $spa<$sph && $sph<$spn && $spn<$spc && $spc<$spt) {
				
				#$ipaddr=substr($line, $spa+length(" client "), $sph - length(" client ") - $spa);
				#$qname=substr($line, $spn+length(" query: "));
				#$qtype=substr($line, $spt+1);
				#if (($spe=index($qtype," "))>0) { $qtype=substr($qtype, 0, $spe); }
				#if (($spe=index($qname," "))>0) { $qname=substr($qname, 0, $spe); }
				#print(basename(__FILE__).':'.__LINE__.": hh=|$hh| ipaddr=|$ipaddr| qtype=|$qtype| qname=|$qname|\n");
				
				
						if (!defined($HHLIST{$hh}{$qtype})) { print("foreach (MYARG{'logsfile'}): while (line): if (!defined(\$HHLIST{$hh}{$qtype})): qtype=|$qtype|\n"); print("logsfile=$logsfile\n"); print("line=|$line|\n"); }
						if (!defined($HHLIST{$hh}{$qtype})) { $HHLIST{$hh}{$qtype}=0; }
						$HHLIST{$hh}{$qtype} = $HHLIST{$hh}{$qtype} + 1;
						
						if (defined( $QTYPE{$qtype} )) { $QTYPE{$qtype} =$QTYPE{$qtype} +1; } else { $QTYPE{$qtype} =1; }
						
						#if (substr($qname,-12,12) eq 'in-addr.arpa' || substr($qname,-8,8) eq 'ip6.arpa')
						#if (substr($qname,-5,5) eq '.arpa') {
						#} else {
						#} # if (substr($qname,-5,5) eq '.arpa')
						
						if ($qtype eq 'A'   ) {   if (defined( $QNAME4  {$qname} )) { $QNAME4  {$qname} =$QNAME4  {$qname} +1; } else { $QNAME4  {$qname} =1; }   }
						if ($qtype eq 'AAAA') {   if (defined( $QNAME6  {$qname} )) { $QNAME6  {$qname} =$QNAME6  {$qname} +1; } else { $QNAME6  {$qname} =1; }   }
						if ($qtype eq 'PTR' ) {
							if (substr($qname, -8, 8) eq 'ip6.arpa'    ) {   if (defined( $QARPA6{$qname} )) { $QARPA6{$qname} =$QARPA6{$qname} +1; } else { $QARPA6{$qname} =1; }   }
							if (substr($qname,-12,12) eq 'in-addr.arpa') {   if (defined( $QARPA4{$qname} )) { $QARPA4{$qname} =$QARPA4{$qname} +1; } else { $QARPA4{$qname} =1; }   }
						}
						if ($qtype eq 'NS'  ) {   if (defined( $QNAMENS {$qname} )) { $QNAMENS {$qname} =$QNAMENS {$qname} +1; } else { $QNAMENS {$qname} =1; }   }
						if ($qtype eq 'MX'  ) {   if (defined( $QNAMEMX {$qname} )) { $QNAMEMX {$qname} =$QNAMEMX {$qname} +1; } else { $QNAMEMX {$qname} =1; }   }
						if ($qtype eq 'TXT' ) {   if (defined( $QNAMETXT{$qname} )) { $QNAMETXT{$qname} =$QNAMETXT{$qname} +1; } else { $QNAMETXT{$qname} =1; }   }
						if ($qtype eq 'SOA' ) {   if (defined( $QNAMESOA{$qname} )) { $QNAMESOA{$qname} =$QNAMESOA{$qname} +1; } else { $QNAMESOA{$qname} =1; }   }
						
						if ($qtype ne 'A' && $qtype ne 'AAAA' && $qtype ne 'PTR' && $qtype ne 'NS' && $qtype ne 'MX' && $qtype ne 'TXT' && $qtype ne 'SOA' ) {   if (defined( $QNAMEX  {$qname} )) { $QNAMEX  {$qname} =$QNAMEX  {$qname} +1; } else { $QNAMEX  {$qname} =1; }   }
				
				
				
				@IP4OCT=split(/\./, $ipaddr);
				@IP6OCT=split(/:/,  $ipaddr);
				
				if ($#IP4OCT+1==4) {
					# IPv4 LAN vs WAN
					# 10.0.0.0/8     = 0A 00 00 00 / FF 00 00 00
					# 172.16.0.0/12  = AC 10 00 00 / FF F0 00 00
					# 192.168.0.0/16 = C0 A8 00 00 / FF FF 00 00
					$ipv4_uint32=unpack(N=>pack(CCCC=>split(/\./=>$ipaddr)));
					if ( ($ipv4_uint32&0xFF000000)==(0x0A000000&0xFF000000) || ($ipv4_uint32&0xFFF00000)==(0xAC100000&0xFFF00000) || ($ipv4_uint32&0xFFFF0000)==(0xC0A80000&0xFFFF0000) ) {
						##################
						# QUERY from LAN #
						##################
						if (defined($IPALAN{$ipaddr})) { $IPALAN{$ipaddr}=$IPALAN{$ipaddr}+1; } else { $IPALAN{$ipaddr}=1; }
						
						if (!defined($HHLLAN{$hh}{$qtype})) { print("foreach (MYARG{'logsfile'}): while (line): if (!defined(\$HHLLAN{$hh}{$qtype})): qtype=|$qtype|\n"); print("logsfile=$logsfile\n"); print("line=|$line|\n"); }
						if (!defined($HHLLAN{$hh}{$qtype})) { $HHLLAN{$hh}{$qtype}=0; }
						$HHLLAN{$hh}{$qtype} = $HHLLAN{$hh}{$qtype} + 1;
						
						if (defined( $LTYPE{$qtype} )) { $LTYPE{$qtype} =$LTYPE{$qtype} +1; } else { $LTYPE{$qtype} =1; }
						
						if ($qtype eq 'A'   ) {   if (defined( $LNAME4  {$qname} )) { $LNAME4  {$qname} =$LNAME4  {$qname} +1; } else { $LNAME4  {$qname} =1; }   }
						if ($qtype eq 'AAAA') {   if (defined( $LNAME6  {$qname} )) { $LNAME6  {$qname} =$LNAME6  {$qname} +1; } else { $LNAME6  {$qname} =1; }   }
						if ($qtype eq 'PTR' ) {
							if (substr($qname, -8, 8) eq 'ip6.arpa'    ) {   if (defined( $LARPA6{$qname} )) { $LARPA6{$qname} =$LARPA6{$qname} +1; } else { $LARPA6{$qname} =1; }   }
							if (substr($qname,-12,12) eq 'in-addr.arpa') {   if (defined( $LARPA4{$qname} )) { $LARPA4{$qname} =$LARPA4{$qname} +1; } else { $LARPA4{$qname} =1; }   }
						}
						if ($qtype eq 'NS'  ) {   if (defined( $LNAMENS {$qname} )) { $LNAMENS {$qname} =$LNAMENS {$qname} +1; } else { $LNAMENS {$qname} =1; }   }
						if ($qtype eq 'MX'  ) {   if (defined( $LNAMEMX {$qname} )) { $LNAMEMX {$qname} =$LNAMEMX {$qname} +1; } else { $LNAMEMX {$qname} =1; }   }
						if ($qtype eq 'TXT' ) {   if (defined( $LNAMETXT{$qname} )) { $LNAMETXT{$qname} =$LNAMETXT{$qname} +1; } else { $LNAMETXT{$qname} =1; }   }
						if ($qtype eq 'SOA' ) {   if (defined( $LNAMESOA{$qname} )) { $LNAMESOA{$qname} =$LNAMESOA{$qname} +1; } else { $LNAMESOA{$qname} =1; }   }
						
						if ($qtype ne 'A' && $qtype ne 'AAAA' && $qtype ne 'PTR' && $qtype ne 'NS' && $qtype ne 'MX' && $qtype ne 'TXT' && $qtype ne 'SOA' ) {   if (defined( $LNAMEX  {$qname} )) { $LNAMEX  {$qname} =$LNAMEX  {$qname} +1; } else { $LNAMEX  {$qname} =1; }   }
						##################
						# QUERY from LAN #
						##################
					} else {
						##################
						# QUERY from WAN #
						##################
						if (defined($IPAWAN{$ipaddr})) { $IPAWAN{$ipaddr}=$IPAWAN{$ipaddr}+1; } else { $IPAWAN{$ipaddr}=1; }
						
						if (!defined($HHWWAN{$hh}{$qtype})) { print("foreach (MYARG{'logsfile'}): while (line): if (!defined(\$HHLLAN{$hh}{$qtype})): qtype=|$qtype|\n"); print("logsfile=$logsfile\n"); print("line=|$line|\n"); }
						if (!defined($HHWWAN{$hh}{$qtype})) { $HHWWAN{$hh}{$qtype}=0; }
						$HHWWAN{$hh}{$qtype} = $HHWWAN{$hh}{$qtype} + 1;
						
						if (defined( $WTYPE{$qtype} )) { $WTYPE{$qtype} =$WTYPE{$qtype} +1; } else { $WTYPE{$qtype} =1; }
						
						if ($qtype eq 'A'   ) {   if (defined( $WNAME4  {$qname} )) { $WNAME4  {$qname} =$WNAME4  {$qname} +1; } else { $WNAME4  {$qname} =1; }   }
						if ($qtype eq 'AAAA') {   if (defined( $WNAME6  {$qname} )) { $WNAME6  {$qname} =$WNAME6  {$qname} +1; } else { $WNAME6  {$qname} =1; }   }
						if ($qtype eq 'PTR' ) {
							if (substr($qname, -8, 8) eq 'ip6.arpa'    ) {   if (defined( $WARPA6{$qname} )) { $WARPA6{$qname} =$WARPA6{$qname} +1; } else { $WARPA6{$qname} =1; }   }
							if (substr($qname,-12,12) eq 'in-addr.arpa') {   if (defined( $WARPA4{$qname} )) { $WARPA4{$qname} =$WARPA4{$qname} +1; } else { $WARPA4{$qname} =1; }   }
						}
						if ($qtype eq 'NS'  ) {   if (defined( $WNAMENS {$qname} )) { $WNAMENS {$qname} =$WNAMENS {$qname} +1; } else { $WNAMENS {$qname} =1; }   }
						if ($qtype eq 'MX'  ) {   if (defined( $WNAMEMX {$qname} )) { $WNAMEMX {$qname} =$WNAMEMX {$qname} +1; } else { $WNAMEMX {$qname} =1; }   }
						if ($qtype eq 'TXT' ) {   if (defined( $WNAMETXT{$qname} )) { $WNAMETXT{$qname} =$WNAMETXT{$qname} +1; } else { $WNAMETXT{$qname} =1; }   }
						if ($qtype eq 'SOA' ) {   if (defined( $WNAMESOA{$qname} )) { $WNAMESOA{$qname} =$WNAMESOA{$qname} +1; } else { $WNAMESOA{$qname} =1; }   }
						
						if ($qtype ne 'A' && $qtype ne 'AAAA' && $qtype ne 'PTR' && $qtype ne 'NS' && $qtype ne 'MX' && $qtype ne 'TXT' && $qtype ne 'SOA' ) {   if (defined( $WNAMEX  {$qname} )) { $WNAMEX  {$qname} =$WNAMEX  {$qname} +1; } else { $WNAMEX  {$qname} =1; }   }
						##################
						# QUERY from WAN #
						##################
					}
					
					
					
				} else {
					# TODO: FIXME: NOTICE: IPv6 LAN vs WAN
					
						if (defined($IPAAAA{$ipaddr})) { $IPAAAA{$ipaddr}=$IPAAAA{$ipaddr}+1; } else { $IPAAAA{$ipaddr}=1; }
					
					
				} # if ($#IP4OCT+1==4)
				
				
				
			} # if (0<$spa && $spa<$sph && $sph<$spn && $spn<$spc && $spc<$spt)
			
		} # else { print("NOK:1:line=|$line|\n"); }
		
		#############################
		# named.log - lame-servers: #
		#############################
		# 26-Jan-2017 03:22:10.496 lame-servers: info: error (unexpected RCODE REFUSED) resolving 'bluray.96.lt/A/IN': 31.170.164.249#53
		#               26         - Jan             - 2047                    03        :  22        : 10           . 496               general:|network:|lame-servers:|security:|query-errors:
		# 26-Jan-2017 03:22:12.309 unexpected RCODE (SERVFAIL) resolving 'bluray.96.lt/A/IN': 10.5.5.5#53
		#               26         - Jan             - 2017                    03        :  22        : 12           . 309               general:|network:|lame-servers:|security:|query-errors:
		if ($line=~m/^([ 0-3][0-9])-([A-Z][a-z][a-z])-([0-9][0-9][0-9][0-9]) ([0-2][0-9]):([0-5][0-9]):([0-5][0-9])(\.[0-9][0-9][0-9])? (general:|network:|lame-servers:|security:|query-errors:) ([A-Za-z0-9\s_]+:) ([A-Za-z0-9]+)/) {
			my ($category, $type, $message);
			$category=$8;
			$type=$9;
			if ($type eq 'debug 2:') { next; }
			if ($type eq 'debug 3:') { next; }
			if ($type eq 'debug 4:') { next; }
			#print("$category / $type - line=|$line|\n");
			if (!defined($7)) { $7=""; }
			$spa=index($line, "$1-$2-$3 $4:$5:$6$7 $8 $9");
			$spe=$spa+length("$1-$2-$3 $4:$5:$6$7 $8 $9")+1;
			#print(basename(__FILE__).':'.__LINE__.": spa=$spa spe=$spe size=|".length($line)."|\n");
			
			if ($spe>=length($line)) { print(basename(__FILE__).':'.__LINE__.": ERR: if (\$spe>=length(\$line)): \$spe=$spe length(\$line)=".length($line)." line=|$line|\n"); next; }
			$message=substr($line, $spe);
			if (!defined($message)) { print(basename(__FILE__).':'.__LINE__.": ERR: if (!defined(\$message)):\n"); next; }
			if ($MYARG{'cutclientport'}==1) {
				if (substr($message,0,6) eq 'client' && ($spn=index($message,'#'))>0 && ($spc=index($message,chr(0x20),$spn))>0) {
					$message=substr($message,0,$spn+1) ."PORT". substr($message,$spc);
				}
			}
			#print("spa=$spa spe=$spe message=|$message|\n");
			if (defined($INFO{$category}{$type}{$message})) {
				$INFO{$category}{$type}{$message}=$INFO{$category}{$type}{$message} + 1;
			} else {
				$INFO{$category}{$type}{$message}=1;
			}
		} # else { print("NOK:2:line=|$line|\n"); }
		
	} # while ($line=<$NAMED>)
	close($NAMED);
} # foreach my $logsfile (@{$MYARG{'logsfile'}})










#######################
#####   DISPLAY   #####
#######################

print("Named/Bind log summaries for $MYARG{'grepdate'} (".strftime('%Y/%m/%d',localtime($MYARG{'greptime'})).")\n");
print("\n");

&show_summary();
print("\n"); print("\n"); print("\n");

&show_info();

&hour_stat_short();
print("\n"); print("\n"); print("\n");

if ($MYARG{'showlongstat'}==1) { &hour_stat_long(); print("\n"); print("\n"); print("\n"); }

&top_stat();
#print("\n"); print("\n"); print("\n");










#####################################
#####   SUBROUTINES SHOW STAT   #####
#####################################

##########################################################################
# sub show_summary()
# global:  %MYARG, %HHSS, %HHLIST, %IPAWAN, %IPALAN, %QNAME4,%QNAME6,%QNAMENS,%QNAMEMX,%QNAMETXT,%QNAMESOA,%QNAMEX, %QTYPE,
# @param   void
# @return  void
sub show_summary {
	#my ()=@_;
	# @_ = ARGS call function
	my ($key, $ki, $kname);
	
	foreach $ki (sort(keys(%HHLIST))) { $key=$ki; last; }
	
	print("Grand Totals\n");
	print("============\n");
# 	print("queries: types\n");
# 	print("--------------\n");
# 	if ($MYARG{'sortquerytypes'}==1) {
# 		my (%HHSS);
# 		foreach $kname (('A','IPv4','NS','CNAME','SOA','NULL','PTR','HINFO','MINFO','MX','TXT','RP','AAAA','IPv6','SRV','NAPTR','A6','AXFR','ANY','A6','SPF')) {
# 		if (!defined($HHSS{$kname})) { $HHSS{$kname}=0; }
# 		$HHSS{$kname}=$HHSS{$kname} + &hash_key2_sum(\%HHLIST,$kname);
# 		}
# 		foreach $kname (reverse(sort { $HHSS{$a} <=> $HHSS{$b} } keys(%HHSS))) {
# 		print(sprintf(" % 7d   $kname ",$HHSS{$kname})."\n");
# 		}
# 	} else {
# 		# $kname (('A','IPv4','NS','CNAME','SOA','NULL','PTR','HINFO','MINFO','MX','TXT','RP','AAAA','IPv6','SRV','NAPTR','A6','AXFR','ANY','A6','SPF'))
# 		foreach $kname (('A','AAAA','PTR','MX','TXT','NS','SOA','CNAME','ANY',    'IPv4','NULL','HINFO','MINFO','RP','IPv6','SRV','NAPTR','A6','AXFR','A6','SPF')) {
# 		print(sprintf(" % 7d   $kname",&hash_key2_sum(\%HHLIST,$kname))."\n");
# 		}
# 	}
# 	print("\n");
	
	print(sprintf(" % 7d   queries unique types",&hash_count(\%QTYPE))."\n");
	print("\n");
	
	print(sprintf(" % 7d   queries for unique A (IPv4)",&hash_count(\%QNAME4))."\n");
	print(sprintf(" % 7d   queries for unique AAAA (IPv6)",&hash_count(\%QNAME6))."\n");
	print(sprintf(" % 7d   queries for unique PTR (IPv4)",&hash_count(\%QARPA4))."\n");
	print(sprintf(" % 7d   queries for unique PTR (IPv6)",&hash_count(\%QARPA6))."\n");
	print(sprintf(" % 7d   queries for unique NS",&hash_count(\%QNAMENS))."\n");
	print(sprintf(" % 7d   queries for unique MX",&hash_count(\%QNAMEMX))."\n");
	print(sprintf(" % 7d   queries for unique TXT",&hash_count(\%QNAMETXT))."\n");
	print(sprintf(" % 7d   queries for unique SOA",&hash_count(\%QNAMESOA))."\n");
	print(sprintf(" % 7d   queries for unique X (other)",&hash_count(\%QNAMEX))."\n");
	print("\n");
	
	print(sprintf(" % 7d   queries from unique hosts from IPv4 WAN",&hash_count(\%IPAWAN))."\n");
	print(sprintf(" % 7d   queries from unique hosts from IPv4 LAN",&hash_count(\%IPALAN))."\n");
	print(sprintf(" % 7d   queries from unique hosts from IP(IPv4)",&hash_count(\%IPAAAA))."\n");
}



##########################################################################
# sub show_info()
# global:  %INFO
# @param   void
# @return  void
sub show_info {
	#my ()=@_;
	# @_ = ARGS call function
	my ($category, $type, $message);
	my ($info1, $info2, $newlines);
	
	$newlines=0;
	print("Status Information Running Server\n");
	print("=================================\n");
	# $INFO{$category}{$type}{$diag}
	foreach $category (keys(%INFO)) {
		#$info1="category: $category";
		#print("$info1\n");
		#$info1=~s,.,-,g;
		#print("$info1\n");
		foreach $type (keys( %{ $INFO{$category} } )) {
			$newlines=1;
			#$info1="type=$type";
			#print("$info1\n");
			$info2="category/type: $category / $type";
			print("$info2\n"); $info2=~s,.,-,g; print("$info2\n");
			foreach $message (reverse(sort( { ${ ${ $INFO{$category} }{$type} }{$a} <=> ${ ${ $INFO{$category} }{$type} }{$b} || $a cmp $b } keys( %{ ${ $INFO{$category} }{$type} } )))) {
				#print("message=$message\n");
				print(${ ${ $INFO{$category} }{$type} }{$message}." time(s): $message\n");
			}
			print("\n\n\n");
		}
	}
	if ($newlines==0) { print("\n\n\n"); }
}



##########################################################################
# sub hour_stat_short()
# global:  %HHLIST,%HHLLAN,%HHWWAN
# @param   void
# @return  void
sub hour_stat_short {
	#my ()=@_;
	# @_ = ARGS call function
	my ($ii, $hh);
	
if ($MYARG{'splitquerylanwan'}==1) {
	print("LAN Per-Hour Traffic Summary (Short)\n");
	print("====================================\n");
	print("time:        |       A |    AAAA |     PTR |     MX |       NS |     TXT |   CNAME |     SOA |\n");
	print("-------------+---------+---------+---------+--------+----------+---------+---------+---------+\n");
	foreach $ii (sort(keys(%HHLLAN))) {
		$hh=sprintf("%02d",$ii);
		print(sprintf("%02d:00-%02d:00  | % 7d | % 7d | % 7d | % 7d | % 7d | % 7d | % 7d | % 7d |", $hh, $hh+1, $HHLLAN{$hh}{'A'}, $HHLLAN{$hh}{'AAAA'}, $HHLLAN{$hh}{'PTR'}, $HHLLAN{$hh}{'MX'}, $HHLLAN{$hh}{'NS'}, $HHLLAN{$hh}{'TXT'}, $HHLLAN{$hh}{'CNAME'}, $HHLLAN{$hh}{'SOA'})."\n");
	}
	print("\n");
} # if ($MYARG{'splitquerylanwan'}==1)
	
if ($MYARG{'splitquerylanwan'}==1) {
	print("WAN Per-Hour Traffic Summary (Short)\n");
	print("====================================\n");
	print("time:        |       A |    AAAA |     PTR |     MX |       NS |     TXT |   CNAME |     SOA |\n");
	print("-------------+---------+---------+---------+--------+----------+---------+---------+---------+\n");
	foreach $ii (sort(keys(%HHLIST))) {
		$hh=sprintf("%02d",$ii);
		print(sprintf("%02d:00-%02d:00  | % 7d | % 7d | % 7d | % 7d | % 7d | % 7d | % 7d | % 7d |", $hh, $hh+1, $HHWWAN{$hh}{'A'}, $HHWWAN{$hh}{'AAAA'}, $HHWWAN{$hh}{'PTR'}, $HHWWAN{$hh}{'MX'}, $HHWWAN{$hh}{'NS'}, $HHWWAN{$hh}{'TXT'}, $HHWWAN{$hh}{'CNAME'}, $HHWWAN{$hh}{'SOA'})."\n");
	}
	print("\n");
} # if ($MYARG{'splitquerylanwan'}==1)
	
if ($MYARG{'splitquerylanwan'}==0) {
	print("Per-Hour Traffic Summary (Short)\n");
	print("================================\n");
	print("time:        |       A |    AAAA |     PTR |     MX |       NS |     TXT |   CNAME |     SOA |\n");
	print("-------------+---------+---------+---------+--------+----------+---------+---------+---------+\n");
	foreach $ii (sort(keys(%HHLIST))) {
		$hh=sprintf("%02d",$ii);
		print(sprintf("%02d:00-%02d:00  | % 7d | % 7d | % 7d | % 7d | % 7d | % 7d | % 7d | % 7d |", $hh, $hh+1, $HHLIST{$hh}{'A'}, $HHLIST{$hh}{'AAAA'}, $HHLIST{$hh}{'PTR'}, $HHLIST{$hh}{'MX'}, $HHLIST{$hh}{'NS'}, $HHLIST{$hh}{'TXT'}, $HHLIST{$hh}{'CNAME'}, $HHLIST{$hh}{'SOA'})."\n");
	}
	print("\n");
} # if ($MYARG{'splitquerylanwan'}==0)
	
}



##########################################################################
# sub hour_stat_long()
# global:  %HHLIST,%HHLLAN,%HHWWAN
# @param   void
# @return  void
sub hour_stat_long {
	#my ()=@_;
	# @_ = ARGS call function
	my ($ii, $hh);
	
if ($MYARG{'splitquerylanwan'}==1) {
	print("LAN Per-Hour Traffic Summary (Long)\n");
	print("===================================\n");
	print("time:        |       A |    IPv4 |      NS |   CNAME |    SOA |     NULL |     PTR |   HINFO |  MINFO  |      MX |     TXT |      RP |    AAAA |    IPv6 |     SRV |   NAPTR |      A6 |    AXFR |     ANY |\n");
	print("-------------+---------+---------+---------+---------+--------+----------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+\n");
	foreach $ii (sort(keys(%HHLIST))) {
		$hh=sprintf("%02d",$ii);
		print(sprintf("%02d:00-%02d:00  | % 7d | % 7d | % 7d | % 7d | % 7d | % 7d | % 7d | % 7d | % 7d | % 7d | % 7d | % 7d | % 7d | % 7d | % 7d | % 7d | % 7d | % 7d | % 7d |", $hh, $hh+1, $HHLLAN{$hh}{'A'}, $HHLLAN{$hh}{'IPv4'}, $HHLLAN{$hh}{'NS'}, $HHLLAN{$hh}{'CNAME'}, $HHLLAN{$hh}{'SOA'}, $HHLLAN{$hh}{'NULL'}, $HHLLAN{$hh}{'PTR'}, $HHLLAN{$hh}{'HINFO'}, $HHLLAN{$hh}{'MINFO'}, $HHLLAN{$hh}{'MX'}, $HHLLAN{$hh}{'TXT'}, $HHLLAN{$hh}{'RP'}, $HHLLAN{$hh}{'AAAA'}, $HHLLAN{$hh}{'IPv6'}, $HHLLAN{$hh}{'SRV'}, $HHLLAN{$hh}{'NAPTR'}, $HHLLAN{$hh}{'A6'}, $HHLLAN{$hh}{'AXFR'}, $HHLLAN{$hh}{'ANY'})."\n");
	}
	print("\n");
} # if ($MYARG{'splitquerylanwan'}==1)
	
if ($MYARG{'splitquerylanwan'}==1) {
	print("WAN Per-Hour Traffic Summary (Long)\n");
	print("===================================\n");
	print("time:        |       A |    IPv4 |      NS |   CNAME |    SOA |     NULL |     PTR |   HINFO |  MINFO  |      MX |     TXT |      RP |    AAAA |    IPv6 |     SRV |   NAPTR |      A6 |    AXFR |     ANY |\n");
	print("-------------+---------+---------+---------+---------+--------+----------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+\n");
	foreach $ii (sort(keys(%HHLIST))) {
		$hh=sprintf("%02d",$ii);
		print(sprintf("%02d:00-%02d:00  | % 7d | % 7d | % 7d | % 7d | % 7d | % 7d | % 7d | % 7d | % 7d | % 7d | % 7d | % 7d | % 7d | % 7d | % 7d | % 7d | % 7d | % 7d | % 7d |", $hh, $hh+1, $HHWWAN{$hh}{'A'}, $HHWWAN{$hh}{'IPv4'}, $HHWWAN{$hh}{'NS'}, $HHWWAN{$hh}{'CNAME'}, $HHWWAN{$hh}{'SOA'}, $HHWWAN{$hh}{'NULL'}, $HHWWAN{$hh}{'PTR'}, $HHWWAN{$hh}{'HINFO'}, $HHWWAN{$hh}{'MINFO'}, $HHWWAN{$hh}{'MX'}, $HHWWAN{$hh}{'TXT'}, $HHWWAN{$hh}{'RP'}, $HHWWAN{$hh}{'AAAA'}, $HHWWAN{$hh}{'IPv6'}, $HHWWAN{$hh}{'SRV'}, $HHWWAN{$hh}{'NAPTR'}, $HHWWAN{$hh}{'A6'}, $HHWWAN{$hh}{'AXFR'}, $HHWWAN{$hh}{'ANY'})."\n");
	}
	print("\n");
} # if ($MYARG{'splitquerylanwan'}==1)
	
if ($MYARG{'splitquerylanwan'}==0) {
	print("Per-Hour Traffic Summary (Long)\n");
	print("===============================\n");
	print("time:        |       A |    IPv4 |      NS |   CNAME |    SOA |     NULL |     PTR |   HINFO |  MINFO  |      MX |     TXT |      RP |    AAAA |    IPv6 |     SRV |   NAPTR |      A6 |    AXFR |     ANY |\n");
	print("-------------+---------+---------+---------+---------+--------+----------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+\n");
	foreach $ii (sort(keys(%HHLIST))) {
		$hh=sprintf("%02d",$ii);
		print(sprintf("%02d:00-%02d:00  | % 7d | % 7d | % 7d | % 7d | % 7d | % 7d | % 7d | % 7d | % 7d | % 7d | % 7d | % 7d | % 7d | % 7d | % 7d | % 7d | % 7d | % 7d | % 7d |", $hh, $hh+1, $HHLIST{$hh}{'A'}, $HHLIST{$hh}{'IPv4'}, $HHLIST{$hh}{'NS'}, $HHLIST{$hh}{'CNAME'}, $HHLIST{$hh}{'SOA'}, $HHLIST{$hh}{'NULL'}, $HHLIST{$hh}{'PTR'}, $HHLIST{$hh}{'HINFO'}, $HHLIST{$hh}{'MINFO'}, $HHLIST{$hh}{'MX'}, $HHLIST{$hh}{'TXT'}, $HHLIST{$hh}{'RP'}, $HHLIST{$hh}{'AAAA'}, $HHLIST{$hh}{'IPv6'}, $HHLIST{$hh}{'SRV'}, $HHLIST{$hh}{'NAPTR'}, $HHLIST{$hh}{'A6'}, $HHLIST{$hh}{'AXFR'}, $HHLIST{$hh}{'ANY'})."\n");
	}
	print("\n");
} # if ($MYARG{'splitquerylanwan'}==0)
	
}



##########################################################################
# sub top_stat()
# global:  %MYARG, %QTYPE, %QNAME4,%QNAME6,%QNAMENS,%QNAMEMX,%QNAMETXT,%QNAMESOA,%QNAMEX, %QARPA4, %QARPA6, %IPAWAN, %IPALAN,
# @param   void
# @return  void
sub top_stat {
	#my ()=@_;
	# @_ = ARGS call function
	my ($info1, $info2, $ii);
	my ($qtype, $qname, $ipaddr);
	
	
	
if ($MYARG{'splitquerylanwan'}==1) {
	# QUERY top query types
	$info1="LAN top $MYARG{'maxtypes'} query types (ALL query types: ".&hash_count(\%LTYPE).")";
	print("$info1\n"); $info1=~s,.,-,g; print("$info1\n");
	$info2=" cnt      | query type";
	print("$info2\n"); $info2=~s,.,-,g; print("$info2\n");
	$ii=0;
	foreach $qtype (reverse sort { $LTYPE{$a} <=> $LTYPE{$b} || lc($b) cmp lc($a) } keys(%LTYPE)) {
		print(sprintf("% 9d",$LTYPE{$qtype}) ." | $qtype\n");
		if ($ii++>=$MYARG{'maxtypes'}) { last; }
	}
	print("\n");
	print("\n");
	print("\n");
} # if ($MYARG{'splitquerylanwan'}==1)
	
	
	
if ($MYARG{'splitquerylanwan'}==1) {
	# QUERY top query types
	$info1="WAN top $MYARG{'maxtypes'} query types (ALL query types: ".&hash_count(\%WTYPE).")";
	print("$info1\n"); $info1=~s,.,-,g; print("$info1\n");
	$info2=" cnt      | query type";
	print("$info2\n"); $info2=~s,.,-,g; print("$info2\n");
	$ii=0;
	foreach $qtype (reverse sort { $WTYPE{$a} <=> $WTYPE{$b} || lc($b) cmp lc($a) } keys(%WTYPE)) {
		print(sprintf("% 9d",$WTYPE{$qtype}) ." | $qtype\n");
		if ($ii++>=$MYARG{'maxtypes'}) { last; }
	}
	print("\n");
	print("\n");
	print("\n");
	
	print("\n");
	print("\n");
	print("\n");
} # if ($MYARG{'splitquerylanwan'}==1)
	
	
	
if ($MYARG{'splitquerylanwan'}==0) {
	# QUERY top query types
	$info1="top $MYARG{'maxtypes'} query types (ALL query types: ".&hash_count(\%QTYPE).")";
	print("$info1\n"); $info1=~s,.,-,g; print("$info1\n");
	$info2=" cnt      | query type";
	print("$info2\n"); $info2=~s,.,-,g; print("$info2\n");
	$ii=0;
	foreach $qtype (reverse sort { $QTYPE{$a} <=> $QTYPE{$b} || lc($b) cmp lc($a) } keys(%QTYPE)) {
		print(sprintf("% 9d",$QTYPE{$qtype}) ." | $qtype\n");
		if ($ii++>=$MYARG{'maxtypes'}) { last; }
	}
	print("\n");
	print("\n");
	print("\n");
	
	print("\n");
	print("\n");
	print("\n");
} # if ($MYARG{'splitquerylanwan'}==0)
	
	
	
	
	
if ($MYARG{'splitquerylanwan'}==1) {
	# QUERY top from LAN
	$info1="LAN top query types A(IPv4)/AAAA(IPv6)/NS/MX/TXT/SOA/X(other)/PTR(IPv4)/PTR(IPv6)";
	print("$info1\n"); $info1=~s,.,=,g; print("$info1\n");
	print("\n");
	
	$info1="LAN top $MYARG{'maxnames'} query A=IPv4 (ALL query A=IPv4: ".&hash_count(\%LNAME4).")";
	print("$info1\n"); $info1=~s,.,-,g; print("$info1\n");
	$info2=" cnt      | query A=IPv4";
	print("$info2\n"); $info2=~s,.,-,g; print("$info2\n");
	$ii=0;
	foreach $qname (reverse sort { $LNAME4{$a} <=> $LNAME4{$b} || lc($b) cmp lc($a) } keys(%LNAME4)) {
		print(sprintf("% 9d",$LNAME4{$qname}) ." | $qname\n");
		if ($ii++>=$MYARG{'maxnames'}) { last; }
	}
	print("\n");
	print("\n");
	print("\n");
	
	$info1="LAN top $MYARG{'maxnames'} query AAAA=IPv6 (ALL query AAAA=IPv6: ".&hash_count(\%LNAME6).")";
	print("$info1\n"); $info1=~s,.,-,g; print("$info1\n");
	$info2=" cnt      | query AAAA=IPv6";
	print("$info2\n"); $info2=~s,.,-,g; print("$info2\n");
	$ii=0;
	foreach $qname (reverse sort { $LNAME6{$a} <=> $LNAME6{$b} || lc($b) cmp lc($a) } keys(%LNAME6)) {
		print(sprintf("% 9d",$LNAME6{$qname}) ." | $qname\n");
		if ($ii++>=$MYARG{'maxnames'}) { last; }
	}
	print("\n");
	print("\n");
	print("\n");
	
	$info1="LAN top $MYARG{'maxnames'} query NS (ALL query NS: ".&hash_count(\%LNAMENS).")";
	print("$info1\n"); $info1=~s,.,-,g; print("$info1\n");
	$info2=" cnt      | query NS";
	print("$info2\n"); $info2=~s,.,-,g; print("$info2\n");
	$ii=0;
	foreach $qname (reverse sort { $LNAMENS{$a} <=> $LNAMENS{$b} || lc($b) cmp lc($a) } keys(%LNAMENS)) {
		print(sprintf("% 9d",$LNAMENS{$qname}) ." | $qname\n");
		if ($ii++>=$MYARG{'maxnames'}) { last; }
	}
	print("\n");
	print("\n");
	print("\n");
	
	$info1="LAN top $MYARG{'maxnames'} query MX (ALL query MX: ".&hash_count(\%LNAMEMX).")";
	print("$info1\n"); $info1=~s,.,-,g; print("$info1\n");
	$info2=" cnt      | query MX";
	print("$info2\n"); $info2=~s,.,-,g; print("$info2\n");
	$ii=0;
	foreach $qname (reverse sort { $LNAMEMX{$a} <=> $LNAMEMX{$b} || lc($b) cmp lc($a) } keys(%LNAMEMX)) {
		print(sprintf("% 9d",$LNAMEMX{$qname}) ." | $qname\n");
		if ($ii++>=$MYARG{'maxnames'}) { last; }
	}
	print("\n");
	print("\n");
	print("\n");
	
	$info1="LAN top $MYARG{'maxnames'} query TXT (ALL query TXT: ".&hash_count(\%LNAMETXT).")";
	print("$info1\n"); $info1=~s,.,-,g; print("$info1\n");
	$info2=" cnt      | query TXT";
	print("$info2\n"); $info2=~s,.,-,g; print("$info2\n");
	$ii=0;
	foreach $qname (reverse sort { $LNAMETXT{$a} <=> $LNAMETXT{$b} || lc($b) cmp lc($a) } keys(%LNAMETXT)) {
		print(sprintf("% 9d",$LNAMETXT{$qname}) ." | $qname\n");
		if ($ii++>=$MYARG{'maxnames'}) { last; }
	}
	print("\n");
	print("\n");
	print("\n");
	
	$info1="LAN top $MYARG{'maxnames'} query SOA (ALL query SOA: ".&hash_count(\%LNAMESOA).")";
	print("$info1\n"); $info1=~s,.,-,g; print("$info1\n");
	$info2=" cnt      | query SOA";
	print("$info2\n"); $info2=~s,.,-,g; print("$info2\n");
	$ii=0;
	foreach $qname (reverse sort { $LNAMESOA{$a} <=> $LNAMESOA{$b} || lc($b) cmp lc($a) } keys(%LNAMESOA)) {
		print(sprintf("% 9d",$LNAMESOA{$qname}) ." | $qname\n");
		if ($ii++>=$MYARG{'maxnames'}) { last; }
	}
	print("\n");
	print("\n");
	print("\n");
	
	$info1="LAN top $MYARG{'maxnames'} query X(other) (ALL query X(other): ".&hash_count(\%LNAMEX).")";
	print("$info1\n"); $info1=~s,.,-,g; print("$info1\n");
	$info2=" cnt      | query X(other)";
	print("$info2\n"); $info2=~s,.,-,g; print("$info2\n");
	$ii=0;
	foreach $qname (reverse sort { $LNAMEX{$a} <=> $LNAMEX{$b} || lc($b) cmp lc($a) } keys(%LNAMEX)) {
		print(sprintf("% 9d",$LNAMEX{$qname}) ." | $qname\n");
		if ($ii++>=$MYARG{'maxnames'}) { last; }
	}
	print("\n");
	print("\n");
	print("\n");
	
	
	
	$info1="LAN top $MYARG{'maxarpas'} query arpa PTR=IPv4 (ALL query arpa PTR=IPv4: ".&hash_count(\%LARPA4).")";
	print("$info1\n"); $info1=~s,.,-,g; print("$info1\n");
	$info2=" cnt      | query arpa PTR=IPv4";
	print("$info2\n"); $info2=~s,.,-,g; print("$info2\n");
	$ii=0;
	foreach $qname (reverse sort { $LARPA4{$a} <=> $LARPA4{$b} || lc($b) cmp lc($a) } keys(%LARPA4)) {
		print(sprintf("% 9d",$LARPA4{$qname}) ." | $qname\n");
		if ($ii++>=$MYARG{'maxarpas'}) { last; }
	}
	print("\n");
	print("\n");
	print("\n");
	
	$info1="LAN top $MYARG{'maxarpas'} query arpa PTR=IPv6 (ALL query arpa PTR=IPv6: ".&hash_count(\%LARPA6).")";
	print("$info1\n"); $info1=~s,.,-,g; print("$info1\n");
	$info2=" cnt      | query arpa PTR=IPv6";
	print("$info2\n"); $info2=~s,.,-,g; print("$info2\n");
	$ii=0;
	foreach $qname (reverse sort { $LARPA6{$a} <=> $LARPA6{$b} || lc($b) cmp lc($a) } keys(%LARPA6)) {
		print(sprintf("% 9d",$LARPA6{$qname}) ." | $qname\n");
		if ($ii++>=$MYARG{'maxarpas'}) { last; }
	}
	print("\n");
	print("\n");
	print("\n");
	
	print("\n");
	print("\n");
	print("\n");
} # if ($MYARG{'splitquerylanwan'}==1)
	
	
	
	
	
if ($MYARG{'splitquerylanwan'}==1) {
	# QUERY top from WAN
	$info1="WAN top query types A(IPv4)/AAAA(IPv6)/NS/MX/TXT/SOA/X(other)/PTR(IPv4)/PTR(IPv6)";
	print("$info1\n"); $info1=~s,.,=,g; print("$info1\n");
	print("\n");
	
	$info1="WAN top $MYARG{'maxnames'} query A=IPv4 (ALL query A=IPv4: ".&hash_count(\%WNAME4).")";
	print("$info1\n"); $info1=~s,.,-,g; print("$info1\n");
	$info2=" cnt      | query A=IPv4";
	print("$info2\n"); $info2=~s,.,-,g; print("$info2\n");
	$ii=0;
	foreach $qname (reverse sort { $WNAME4{$a} <=> $WNAME4{$b} || lc($b) cmp lc($a) } keys(%WNAME4)) {
		print(sprintf("% 9d",$WNAME4{$qname}) ." | $qname\n");
		if ($ii++>=$MYARG{'maxnames'}) { last; }
	}
	print("\n");
	print("\n");
	print("\n");
	
	$info1="WAN top $MYARG{'maxnames'} query AAAA=IPv6 (ALL query AAAA=IPv6: ".&hash_count(\%WNAME6).")";
	print("$info1\n"); $info1=~s,.,-,g; print("$info1\n");
	$info2=" cnt      | query AAAA=IPv6";
	print("$info2\n"); $info2=~s,.,-,g; print("$info2\n");
	$ii=0;
	foreach $qname (reverse sort { $WNAME6{$a} <=> $WNAME6{$b} || lc($b) cmp lc($a) } keys(%WNAME6)) {
		print(sprintf("% 9d",$WNAME6{$qname}) ." | $qname\n");
		if ($ii++>=$MYARG{'maxnames'}) { last; }
	}
	print("\n");
	print("\n");
	print("\n");
	
	$info1="WAN top $MYARG{'maxnames'} query NS (ALL query NS: ".&hash_count(\%WNAMENS).")";
	print("$info1\n"); $info1=~s,.,-,g; print("$info1\n");
	$info2=" cnt      | query NS";
	print("$info2\n"); $info2=~s,.,-,g; print("$info2\n");
	$ii=0;
	foreach $qname (reverse sort { $WNAMENS{$a} <=> $WNAMENS{$b} || lc($b) cmp lc($a) } keys(%WNAMENS)) {
		print(sprintf("% 9d",$WNAMENS{$qname}) ." | $qname\n");
		if ($ii++>=$MYARG{'maxnames'}) { last; }
	}
	print("\n");
	print("\n");
	print("\n");
	
	$info1="WAN top $MYARG{'maxnames'} query MX (ALL query MX: ".&hash_count(\%WNAMEMX).")";
	print("$info1\n"); $info1=~s,.,-,g; print("$info1\n");
	$info2=" cnt      | query MX";
	print("$info2\n"); $info2=~s,.,-,g; print("$info2\n");
	$ii=0;
	foreach $qname (reverse sort { $WNAMEMX{$a} <=> $WNAMEMX{$b} || lc($b) cmp lc($a) } keys(%WNAMEMX)) {
		print(sprintf("% 9d",$WNAMEMX{$qname}) ." | $qname\n");
		if ($ii++>=$MYARG{'maxnames'}) { last; }
	}
	print("\n");
	print("\n");
	print("\n");
	
	$info1="WAN top $MYARG{'maxnames'} query TXT (ALL query TXT: ".&hash_count(\%WNAMETXT).")";
	print("$info1\n"); $info1=~s,.,-,g; print("$info1\n");
	$info2=" cnt      | query TXT";
	print("$info2\n"); $info2=~s,.,-,g; print("$info2\n");
	$ii=0;
	foreach $qname (reverse sort { $WNAMETXT{$a} <=> $WNAMETXT{$b} || lc($b) cmp lc($a) } keys(%WNAMETXT)) {
		print(sprintf("% 9d",$WNAMETXT{$qname}) ." | $qname\n");
		if ($ii++>=$MYARG{'maxnames'}) { last; }
	}
	print("\n");
	print("\n");
	print("\n");
	
	$info1="WAN top $MYARG{'maxnames'} query SOA (ALL query SOA: ".&hash_count(\%WNAMESOA).")";
	print("$info1\n"); $info1=~s,.,-,g; print("$info1\n");
	$info2=" cnt      | query SOA";
	print("$info2\n"); $info2=~s,.,-,g; print("$info2\n");
	$ii=0;
	foreach $qname (reverse sort { $WNAMESOA{$a} <=> $WNAMESOA{$b} || lc($b) cmp lc($a) } keys(%WNAMESOA)) {
		print(sprintf("% 9d",$WNAMESOA{$qname}) ." | $qname\n");
		if ($ii++>=$MYARG{'maxnames'}) { last; }
	}
	print("\n");
	print("\n");
	print("\n");
	
	$info1="WAN top $MYARG{'maxnames'} query X(other) (ALL query X(other): ".&hash_count(\%WNAMEX).")";
	print("$info1\n"); $info1=~s,.,-,g; print("$info1\n");
	$info2=" cnt      | query X(other)";
	print("$info2\n"); $info2=~s,.,-,g; print("$info2\n");
	$ii=0;
	foreach $qname (reverse sort { $WNAMEX{$a} <=> $WNAMEX{$b} || lc($b) cmp lc($a) } keys(%WNAMEX)) {
		print(sprintf("% 9d",$WNAMEX{$qname}) ." | $qname\n");
		if ($ii++>=$MYARG{'maxnames'}) { last; }
	}
	print("\n");
	print("\n");
	print("\n");
	
	
	
	$info1="WAN top $MYARG{'maxarpas'} query arpa PTR=IPv4 (ALL query arpa PTR=IPv4: ".&hash_count(\%WARPA4).")";
	print("$info1\n"); $info1=~s,.,-,g; print("$info1\n");
	$info2=" cnt      | query arpa PTR=IPv4";
	print("$info2\n"); $info2=~s,.,-,g; print("$info2\n");
	$ii=0;
	foreach $qname (reverse sort { $WARPA4{$a} <=> $WARPA4{$b} || lc($b) cmp lc($a) } keys(%WARPA4)) {
		print(sprintf("% 9d",$WARPA4{$qname}) ." | $qname\n");
		if ($ii++>=$MYARG{'maxarpas'}) { last; }
	}
	print("\n");
	print("\n");
	print("\n");
	
	$info1="WAN top $MYARG{'maxarpas'} query arpa PTR=IPv6 (ALL query arpa PTR=IPv6: ".&hash_count(\%WARPA6).")";
	print("$info1\n"); $info1=~s,.,-,g; print("$info1\n");
	$info2=" cnt      | query arpa PTR=IPv6";
	print("$info2\n"); $info2=~s,.,-,g; print("$info2\n");
	$ii=0;
	foreach $qname (reverse sort { $WARPA6{$a} <=> $WARPA6{$b} || lc($b) cmp lc($a) } keys(%WARPA6)) {
		print(sprintf("% 9d",$WARPA6{$qname}) ." | $qname\n");
		if ($ii++>=$MYARG{'maxarpas'}) { last; }
	}
	print("\n");
	print("\n");
	print("\n");
	
	print("\n");
	print("\n");
	print("\n");
	
} # if ($MYARG{'splitquerylanwan'}==1)
	
	
	
	
	
if ($MYARG{'splitquerylanwan'}==0) {
	
	# QUERY top from ALL
	$info1="ALL top query types A(IPv4)/AAAA(IPv6)/NS/MX/TXT/SOA/X(other)/PTR(IPv4)/PTR(IPv6)";
	print("$info1\n"); $info1=~s,.,=,g; print("$info1\n");
	print("\n");
	
	$info1="top $MYARG{'maxnames'} query A=IPv4 (ALL query A=IPv4: ".&hash_count(\%QNAME4).")";
	print("$info1\n"); $info1=~s,.,-,g; print("$info1\n");
	$info2=" cnt      | query A=IPv4";
	print("$info2\n"); $info2=~s,.,-,g; print("$info2\n");
	$ii=0;
	foreach $qname (reverse sort { $QNAME4{$a} <=> $QNAME4{$b} || lc($b) cmp lc($a) } keys(%QNAME4)) {
		print(sprintf("% 9d",$QNAME4{$qname}) ." | $qname\n");
		if ($ii++>=$MYARG{'maxnames'}) { last; }
	}
	print("\n");
	print("\n");
	print("\n");
	
	$info1="ALL top $MYARG{'maxnames'} query AAAA=IPv6 (ALL query AAAA=IPv6: ".&hash_count(\%QNAME6).")";
	print("$info1\n"); $info1=~s,.,-,g; print("$info1\n");
	$info2=" cnt      | query AAAA=IPv6";
	print("$info2\n"); $info2=~s,.,-,g; print("$info2\n");
	$ii=0;
	foreach $qname (reverse sort { $QNAME6{$a} <=> $QNAME6{$b} || lc($b) cmp lc($a) } keys(%QNAME6)) {
		print(sprintf("% 9d",$QNAME6{$qname}) ." | $qname\n");
		if ($ii++>=$MYARG{'maxnames'}) { last; }
	}
	print("\n");
	print("\n");
	print("\n");
	
	$info1="ALL top $MYARG{'maxnames'} query NS (ALL query NS: ".&hash_count(\%QNAMENS).")";
	print("$info1\n"); $info1=~s,.,-,g; print("$info1\n");
	$info2=" cnt      | query NS";
	print("$info2\n"); $info2=~s,.,-,g; print("$info2\n");
	$ii=0;
	foreach $qname (reverse sort { $QNAMENS{$a} <=> $QNAMENS{$b} || lc($b) cmp lc($a) } keys(%QNAMENS)) {
		print(sprintf("% 9d",$QNAMENS{$qname}) ." | $qname\n");
		if ($ii++>=$MYARG{'maxnames'}) { last; }
	}
	print("\n");
	print("\n");
	print("\n");
	
	$info1="ALL top $MYARG{'maxnames'} query MX (ALL query MX: ".&hash_count(\%QNAMEMX).")";
	print("$info1\n"); $info1=~s,.,-,g; print("$info1\n");
	$info2=" cnt      | query MX";
	print("$info2\n"); $info2=~s,.,-,g; print("$info2\n");
	$ii=0;
	foreach $qname (reverse sort { $QNAMEMX{$a} <=> $QNAMEMX{$b} || lc($b) cmp lc($a) } keys(%QNAMEMX)) {
		print(sprintf("% 9d",$QNAMEMX{$qname}) ." | $qname\n");
		if ($ii++>=$MYARG{'maxnames'}) { last; }
	}
	print("\n");
	print("\n");
	print("\n");
	
	$info1="ALL top $MYARG{'maxnames'} query TXT (ALL query TXT: ".&hash_count(\%QNAMETXT).")";
	print("$info1\n"); $info1=~s,.,-,g; print("$info1\n");
	$info2=" cnt      | query TXT";
	print("$info2\n"); $info2=~s,.,-,g; print("$info2\n");
	$ii=0;
	foreach $qname (reverse sort { $QNAMETXT{$a} <=> $QNAMETXT{$b} || lc($b) cmp lc($a) } keys(%QNAMETXT)) {
		print(sprintf("% 9d",$QNAMETXT{$qname}) ." | $qname\n");
		if ($ii++>=$MYARG{'maxnames'}) { last; }
	}
	print("\n");
	print("\n");
	print("\n");
	
	$info1="ALL top $MYARG{'maxnames'} query SOA (ALL query SOA: ".&hash_count(\%QNAMESOA).")";
	print("$info1\n"); $info1=~s,.,-,g; print("$info1\n");
	$info2=" cnt      | query SOA";
	print("$info2\n"); $info2=~s,.,-,g; print("$info2\n");
	$ii=0;
	foreach $qname (reverse sort { $QNAMESOA{$a} <=> $QNAMESOA{$b} || lc($b) cmp lc($a) } keys(%QNAMESOA)) {
		print(sprintf("% 9d",$QNAMESOA{$qname}) ." | $qname\n");
		if ($ii++>=$MYARG{'maxnames'}) { last; }
	}
	print("\n");
	print("\n");
	print("\n");
	
	$info1="ALL top $MYARG{'maxnames'} query X(other) (ALL query X(other): ".&hash_count(\%QNAMEX).")";
	print("$info1\n"); $info1=~s,.,-,g; print("$info1\n");
	$info2=" cnt      | query X(other)";
	print("$info2\n"); $info2=~s,.,-,g; print("$info2\n");
	$ii=0;
	foreach $qname (reverse sort { $QNAMEX{$a} <=> $QNAMEX{$b} || lc($b) cmp lc($a) } keys(%QNAMEX)) {
		print(sprintf("% 9d",$QNAMEX{$qname}) ." | $qname\n");
		if ($ii++>=$MYARG{'maxnames'}) { last; }
	}
	print("\n");
	print("\n");
	print("\n");
	
	
	
	$info1="ALL top $MYARG{'maxarpas'} query arpa PTR=IPv4 (ALL query arpa PTR=IPv4: ".&hash_count(\%QARPA4).")";
	print("$info1\n"); $info1=~s,.,-,g; print("$info1\n");
	$info2=" cnt      | query arpa PTR=IPv4";
	print("$info2\n"); $info2=~s,.,-,g; print("$info2\n");
	$ii=0;
	foreach $qname (reverse sort { $QARPA4{$a} <=> $QARPA4{$b} || lc($b) cmp lc($a) } keys(%QARPA4)) {
		print(sprintf("% 9d",$QARPA4{$qname}) ." | $qname\n");
		if ($ii++>=$MYARG{'maxarpas'}) { last; }
	}
	print("\n");
	print("\n");
	print("\n");
	
	$info1="ALL top $MYARG{'maxarpas'} query arpa PTR=IPv6 (ALL query arpa PTR=IPv6: ".&hash_count(\%QARPA6).")";
	print("$info1\n"); $info1=~s,.,-,g; print("$info1\n");
	$info2=" cnt      | query arpa PTR=IPv6";
	print("$info2\n"); $info2=~s,.,-,g; print("$info2\n");
	$ii=0;
	foreach $qname (reverse sort { $QARPA6{$a} <=> $QARPA6{$b} || lc($b) cmp lc($a) } keys(%QARPA6)) {
		print(sprintf("% 9d",$QARPA6{$qname}) ." | $qname\n");
		if ($ii++>=$MYARG{'maxarpas'}) { last; }
	}
	print("\n");
	print("\n");
	print("\n");
	
	print("\n");
	print("\n");
	print("\n");
	
} # if ($MYARG{'splitquerylanwan'}==0)
	
	
	
	
	
	# QUERY top from
	$info1="top query from source ipaddr";
	print("$info1\n"); $info1=~s,.,=,g; print("$info1\n");
	print("\n");
	
	$info1="top $MYARG{'maxaddrs'} query from ipaddr IPv4 WAN (ALL query ipaddr IPv4 WAN: ".&hash_count(\%IPAWAN).")";
	print("$info1\n"); $info1=~s,.,-,g; print("$info1\n");
	$info2=" cnt      | query from ipaddr IPv4 WAN";
	print("$info2\n"); $info2=~s,.,-,g; print("$info2\n");
	$ii=0;
	foreach $ipaddr (reverse sort { $IPAWAN{$a} <=> $IPAWAN{$b} || unpack(N=>pack(CCCC=>split(/\./=>$b)))<=>unpack(N=>pack(CCCC=>split(/\./=>$a))) } keys(%IPAWAN)) {
		print(sprintf("% 9d",$IPAWAN{$ipaddr}) ." | $ipaddr\n");
		if ($ii++>=$MYARG{'maxaddrs'}) { last; }
	}
	print("\n");
	print("\n");
	print("\n");
	
	$info1="top $MYARG{'maxaddrs'} query from ipaddr IPv4 LAN (ALL query ipaddr IPv4 LAN: ".&hash_count(\%IPALAN).")";
	print("$info1\n"); $info1=~s,.,-,g; print("$info1\n");
	$info2=" cnt      | query from ipaddr IPv4 LAN";
	print("$info2\n"); $info2=~s,.,-,g; print("$info2\n");
	$ii=0;
	foreach $ipaddr (reverse sort { $IPALAN{$a} <=> $IPALAN{$b} || unpack(N=>pack(CCCC=>split(/\./=>$b)))<=>unpack(N=>pack(CCCC=>split(/\./=>$a))) } keys(%IPALAN)) {
		print(sprintf("% 9d",$IPALAN{$ipaddr}) ." | $ipaddr\n");
		if ($ii++>=$MYARG{'maxaddrs'}) { last; }
	}
	print("\n");
	print("\n");
	print("\n");
	
	$info1="top $MYARG{'maxaddrs'} query from ipaddr IPv6 (ALL query ipaddr IPv6: ".&hash_count(\%IPAAAA).")";
	print("$info1\n"); $info1=~s,.,-,g; print("$info1\n");
	$info2=" cnt      | query from ipaddr IPv6";
	print("$info2\n"); $info2=~s,.,-,g; print("$info2\n");
	$ii=0;
	foreach $ipaddr (reverse sort { $IPAAAA{$a} <=> $IPAAAA{$b} || lc($b) cmp lc($a) } keys(%IPAAAA)) {
		print(sprintf("% 9d",$IPAAAA{$ipaddr}) ." | $ipaddr\n");
		if ($ii++>=$MYARG{'maxaddrs'}) { last; }
	}
}









##################################
#####   SUBROUTINES COMMON   #####
##################################

##########################################################################
# sub hash_count(\%HASH)
# global:  -----
# @param   HASH   \%HASH - reference to HASH
# @return  int    $#KLIST+1
sub hash_count {
	my ($RHASH)=@_;
	# @_ = ARGS call function
	my (@KLIST);
	
	@KLIST=keys(%{$RHASH});
	return $#KLIST+1;
}



##########################################################################
# sub hash_key2_sum(\%HASH, $kname)
# global:  -----
# @param   HASH   \%HASH - reference to HASH
# @param   string $kname
# @return  int    $sumlist
sub hash_key2_sum {
	my ($RHASH, $kname)=@_;
	# @_ = ARGS call function
	my ($sumlist, $key, $ksec);
	
	$sumlist=0;
	foreach $key (sort(keys(%{$RHASH}))) {
		$sumlist=$sumlist+ ${$RHASH}{$key}{$kname};
	}
	return $sumlist;
}


