#!/usr/bin/perl -wT use strict; $| = 1; # # named-report.pl - summarize ISC BIND 9 log messages # $Id: named-report.pl,v 1.5 2008/11/07 17:54:08 jtk Exp $ # # Copyright (C) 2002-2008 John Kristoff # # 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 any later # version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public LICENSE # for more details. # # You should 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. # # Author: John Kristoff # # Usage: ./named-report.pl named.log # or: ./named-report.pl < named.log # or: STDOUT | ./named-report.pl # # Needs a ISC BIND 9 named log file as an argument or as input # via STDIN. This will produce a summary of the log messages. # View the README file for further information and instructions. # # 2002-12-05,jtk: Initial coding and testing # 2003-01-21,jtk: bcq_ and ztd_ reporting, regexps ignore case, minor edits, # enabled warnings/strict, zts_target_count/vsd_source bugs, # disabled output buffering # 2003-04-01,jtk: qrrc_, qrtc_, fe_ and rnna_ reporting, ls_servzone_count, # cqd_ and cqcd_, log_count, hourly bargraph, PRINT_TIME # option, localtime, getcwd, taint mode, report loop $TOPx # bug, @ARGV usage bug, elimination of $_, for loops replace # foreach, minor edits # 2003-07-22,jtk: bug in bcq regexp, bug in vsd regexp, bug in cqd regexp, # category_count, severity_count, generic cqd regexp, # print_time auto-detect, logs_per_hour is now a hash, # s_, slc_, snif_, sr_, se_, ssd_, sscc_, sloi_, snll_, zl_, # zt_, zrfto_, zrrle_, sn_, snf_, ic_, esr_, jfc_ and iu_ # reporting, minor edits # 2003-12-01,jtk: handle messages in syslog format, minor edits # 2005-12-07,jtk: handle new flags # 2006-02-13,jtk: compute percentage of total queries for some reports # cq_srcport (note: need more src port totals) # 2007-03-19,jtk: added GetOpt::Std # 2007-05-30,jtk: support for DD-Mon-YYYY timestamp, fixed cqview handling # 2008-11-07,jtk: updated contact info # use Getopt::Std; my %opts; getopt('dprt:', \%opts); my $DEBUG_start_time = 0; if ($opts{d}) { $DEBUG_start_time = localtime; print "[DEBUG] debug mode enabled\n\n"; } use Socket; # for gethostbyaddr (resolving IPs to names) use Cwd; # for getcwd (getting current working directory) my $TOPx = $opts{t} || 20; # max no. of rows for each report (5-25 recommended) if ($TOPx < 1 || $TOPx > 1000) { die "TOPx value out of range, hack code if you know what you're doing"; } # initialize 24-hour log usage statistics my %logs_per_hour = (); # initialize category and severity log message detail hash arrays my %category_count = (); my %severity_count = (); # initialize log message totals my $log_total = 0; # total log messages my $s_total = 0; # total server (status) messages my $slc_total = 0; # total server loading configurationss my $snif_total = 0; # total server no interface finds my $sr_total = 0; # total server runs my $se_total = 0; # total server exits my $ssd_total = 0; # total server shut downs my $sscc_total = 0; # total server stop command channel messages my $sloi_total = 0; # total server listening on interface messages my $snll_total = 0; # total server no longer listening messages my $ic_total = 0; # total invalid commands my $jfc_total = 0; # total journal file creations my $cq_total = 0; # total client queries my $cqd_total = 0; # total client query denies my $cqcd_total = 0; # total client query cache denies my $zl_total = 0; # total zone loads my $sf_total = 0; # total server fetches my $zt_total = 0; # total zones transfered my $zts_total = 0; # total zone transfers started my $ztr_total = 0; # total zone transfers received my $ztf_total = 0; # total zone transfer failures my $ztd_total = 0; # total zone transfers denied my $bzt_total = 0; # total bad zone transfers my $zrfto_total = 0; # total zone refresh failure time outs my $zrrle_total = 0; # total zone refresh retry limits exceeded my $zu_total = 0; # total zone updates my $zuf_total = 0; # total zone update failures my $ls_total = 0; # total lame servers my $vs_total = 0; # total version scans my $vsd_total = 0; # total version scans denied my $bcq_total = 0; # total broken client queries my $qrrc_total = 0; # total quota reached recursive clients my $qrtc_total = 0; # total quota reached TCP clients my $fe_total = 0; # total format errors my $sn_total = 0; # total send notifies my $snf_total = 0; # total send notify failures my $rnna_total = 0; # total receive notify not authoritative errors my $esr_total = 0; # total error sending responses my $iu_total = 0; # total insecure updates my $other_total = 0; # total other (unknown) log messages # initialize log data hash arrays my %slc_file_count = (); # server loading configuration file my %sscc_ip_count = (); # server stop command channel ip my %sloi_int_count = (); # server listening on interface interface my %sloi_ip_count = (); # server listening on interface ip my %snll_ip_count = (); # server no longer listening ip my %ic_source_count = (); # invalid command ip my %ic_desc_count = (); # invalid command description my %jfc_file_count = (); # journal file creation file my %cq_source_count = (); # client query source my %cq_srcport_count = (); # client query source port my %cq_view_count = (); # client view my %cq_data_count = (); # client query data my %cq_type_count = (); # client query type my %cqd_source_count = (); # client query deny source my %cqd_data_count = (); # client query deny data my %cqcd_source_count = (); # client query cache deny source my %zl_zone_count = (); # zone load zone my %sf_target_count = (); # server fetch target my %sf_type_count = (); # server fetch type my %zt_zone_count = (); # zone transfered zone my %zt_serial_count = (); # zone transfered serial my %zts_target_count = (); # zone transfer started target my %zts_zone_count = (); # zone transfer started zone my %zts_type_count = (); # zone transfer started type my %ztr_zone_count = (); # zone transfer received zone my %ztr_source_count = (); # zone transfer received source my %ztf_zone_count = (); # zone transfer failure zone my %ztf_source_count = (); # zone transfer failure source my %ztf_error_count = (); # zone transfer failure error my %ztd_source_count = (); # zone transfer deny source my %ztd_zone_count = (); # zone transfer deny zone my %bzt_source_count = (); # bad zone transfer source my %bzt_zone_count = (); # bad zone transfer zone my %bzt_desc_count = (); # bad zone transfer description my %zrfto_zone_count = (); # zone refresh failure timed out zone my %zrfto_master_count = ();# zone refresh failure timed out master my %zrrle_zone_count = (); # zone refresh retry limit exceeded zone my %zrrle_master_count = ();# zone refresh retry limit exceeded master my %zu_source_count = (); # zone update source my %zu_zone_count = (); # zone update zone my %zu_desc_count = (); # zone update description my %zuf_source_count = (); # zone update failure source my %zuf_zone_count = (); # zone update failure zone my %zuf_desc_count = (); # zone update failure description my %ls_record_count = (); # lame server record my %ls_zone_count = (); # lame server zone my %ls_server_count = (); # lame server server my %ls_servzone_count = (); # lame server/zone my %vs_source_count = (); # version scan source my %vsd_source_count = (); # version scan deny source my %bcq_source_count = (); # broken client query source my %bcq_class_count = (); # broken client query class my %qrrc_source_count = (); # quota reached recursive client source my %qrtc_source_count = (); # quota reached TCP client source my %fe_source_count = (); # format error source my %sn_zone_count = (); # send notify zone my %sn_serial_count = (); # send notify serial my %snf_zone_count = (); # send notify failure zones my %snf_dst_count = (); # send notify failure destinations my %snf_desc_count = (); # send notify failure descriptions my %rnna_zone_count = (); # receive notify not authoritative zone my %esr_dst_count = (); # error sending response destination my %esr_desc_count = (); # error sending response description my %iu_zone_count = (); # insecure update zones my @arguments = @ARGV; # save arguments (files) from shift in <> loop # Pass named.log (or whatever filenames) as script argument or send # properly formatted log messages to the script via unix STDIN. my $savelog = ""; my $redo_count = 0; while (defined(my $log = <>)) { chomp $log; my $msg = $log; LOG: $log_total++; # alternative timestamp if ($msg =~ /^\d{2}\-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\- \d{4}\s+[0-2][0-9]\: # year hour [0-5][0-9]\: # minute [0-5][0-9] # second (?:\.[0-9]{3})?\s+/x) { my ($day, $month, $year, $hour, $minute, $seconds, $milliseconds) = ("", "", "", "", "", "", ""); ($day, $month, $year, $hour, $minute, $seconds, $milliseconds, $msg) = split (/\s+|\:|\-|\./, $msg, 8); # strip out leading zero so we can use $hour in loops if ($hour =~ /^0(\d)$/) { $hour = $1; } $logs_per_hour{$hour}++; #print $msg,"\n"; } # peel out date/time if present - note: comes before category and severity if ($msg =~ /^(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s+ [0-3]?[0-9]\s+ # day [0-2][0-9]\: # hour [0-5][0-9]\: # minute [0-5][0-9] # second ((\.\d{3})?| # microsecond if present (\s\S+\s+named\[\d+\]\:)?) # syslog id if present \s+/x ) { my ($month, $day, $hour, $minute, $second ) = ("", "", "", "", ""); ($month, $day, $hour, $minute, $second, $msg) = split (/\s+|\:/, $msg, 6); # strip out leading zero so we can use $hour in loops if ($hour =~ /^0(\d)$/) { $hour = $1; } # strip out syslog id if present # HACK: 2005-12-07: added second ID check for FreeBSD syslogs if ($msg =~ /^\S+\snamed\[\d+\]\:\s(?:\[ID \d+ \S+\.\S+\]\s)?(.*)$/) { $msg = $1; } $logs_per_hour{$hour}++; } # redo last log if Linux syslog gives us a repeat message # Mon DD HH:MM:SS hostname last message repeated \d+ time[s] if ($msg =~ /\S+ last message repeated \d+ time[s]?$/) { ($redo_count) = $log =~ /last message repeated (\d+) time[s]/; $log = $savelog; goto LOG; } #TODO: deal with BIND timestmap format, hacked fornow if ($msg =~ /^\d+\-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)/) { my ($year, $month, $day, $hour, $minute, $second, $millisecond ) = ("", "", "", "", "", "", ""); ($day, $month, $year, $hour, $minute, $second, $millisecond, $msg) = split (/\s+|\:|\.|\-/, $msg, 8); # strip out leading zero so we can use $hour in loops if ($hour =~ /^0(\d)$/) { $hour = $1; } $logs_per_hour{$hour}++; } # peel out category if present - note: colon differentiates between cq_ if ( $msg =~ /^(client|config|database|default|dispatch|dnssec|general| lame-servers|network|notify|queries|resolver|security| unmatched|update|xfer-in|xfer-out)\:\s+/x ) { (my $category, $msg) = split (/\:\s+/, $msg, 2); $category_count{$category}++; } # peel out severity if present - note: severity comes after category if ( $msg =~ /^(critical|error|warning|notice|info|debug\s*\d*)\:\s+/x ) { # debug serverity may be followed by a level, strip out (my $severity, $msg) = split (/\:\s+/, $msg, 2); $severity_count{$severity}++; } # not a switch, but a group of if($msg =~ //i) {... next} evals SWITCH: { # server (status) # # loading configuration from '[/path/to/file]' # no IPv6 interfaces found # running # exiting # shutting down # stopping command channel on [ip]#[port] # listening on IPv[version] interface [interface], [ip]#[port] # no longer listening on [ip]#[port] if ($msg =~ /^loading\s+configuration\s+from\s+\'\S+\'/i ) { $s_total++; $slc_total++; my ($slc_file) = (0); ($slc_file) = $msg =~ /^loading\s+configuration\s+from\s+\' (\S+) # slc_file \'/ix; $slc_file_count{$slc_file}++; next; } if ($msg =~ /^running/i ) { $s_total++; $sr_total++; next; } if ($msg =~ /^no\s+IPv6\s+interfaces\s+found/i ) { $s_total++; $snif_total++; next; } if ($msg =~ /^exiting/i ) { $s_total++; $se_total++; next; } if ($msg =~ /^shutting\s+down/i ) { $s_total++; $ssd_total++; next; } if ($msg =~ /^stopping\s+command\s+channel\s+on\s+\d+\.\d+\.\d+\.\d+\#\d+/i ) { $s_total++; $sscc_total++; my ($sscc_ip) = (0); ($sscc_ip) = $msg =~ /^stopping\s+command\s+channel \s+on\s+ (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) # sscc_ip \#\d+/ix; $sscc_ip_count{$sscc_ip}++; next; } if ($msg =~ /^listening\s+on\s+IPv4\s+interface\s+\S+\,\s+\d+\.\d+\.\d+\.\d+\#\d+/i ) { $s_total++; $sloi_total++; my ($sloi_int, $sloi_ip) = (0, 0); ($sloi_int, $sloi_ip) = $msg =~ /^listening\s+on\s+IPv4\s+interface\s+ (\S+) # sloi_int \,\s+ (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) # sloi_ip \#\d+/ix; $sloi_int_count{$sloi_int}++; $sloi_ip_count{$sloi_ip}++; next; } if ($msg =~ /^no\s+longer\s+listening\s+on\s+\d+\.\d+\.\d+\.\d+\#\d+/i ) { $s_total++; $snll_total++; my ($snll_ip) = (0, 0); ($snll_ip) = $msg =~ /^no\s+longer\s+listening\s+on\s+ (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) # snll_ip \#\d+/ix; $snll_ip_count{$snll_ip}++; next; } # invalid command # # invalid command from [ip]#[port]: [description] if ($msg =~ /^invalid\s+command\s+from\s+\d+\.\d+\.\d+\.\d+\#\d+\:\s+.*/i ) { $ic_total++; my ($ic_source, $ic_desc) = (0, 0); ($ic_source, $ic_desc) = $msg =~ /^invalid\s+command\s+from\s+ (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) # ic_source \#\d+\:\s+ (.*) # ic_desc /ix; $ic_source_count{$ic_source}++; $ic_desc_count{$ic_desc}++; next; } # journal file creation # # journal file [file] does not exist, creating it if ($msg =~ /^journal\s+file\s+\S+\s+does\s+not\s+exist\,\s+creating\s+it/i ) { $jfc_total++; my ($jfc_file) = (0); ($jfc_file) = $msg =~ /^journal\s+file\s+ (\S+) # jfc_file \s+does\s+not\s+exist\, \s+creating\s+it/ix; $jfc_file_count{$jfc_file}++; next; } # # client query # # client [ip]#[port]: view [view]: query: [record] [IN/ANY] [type] [-+SE] #TODO: flags, hacked it for now if ($msg =~ /^client\s+\d+\.\d+\.\d+\.\d+\#\d+\:\s+(?:view (\S+)\:\s+)?query\:\s+\S+\s+(IN|ANY)\s+\S+/i ) { $cq_total++; my ($cq_source, $cq_srcport, $cq_view, $cq_data, $cq_type) = (0, 0, 0, 0, 0); if ($opts{p}) { ($cq_source, $cq_srcport, $cq_view, $cq_data, $cq_type) = $msg =~ /^client\s+ (\d{1,3}\.\d{1,3}\.\d{1,3}) # cq_source 24-bit subnet \.\d{1,3} \# (\d{1,5}) # cq_srcport \:\s+ (?:view\s+(\S+)\:\s+)? # cq_view query\:\s+ (\S+) # cq_data \s+\S+\s+ (\S+) # cq_type /ix; } else { ($cq_source, $cq_srcport, $cq_view, $cq_data, $cq_type) = $msg =~ /^client\s+ (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) # cq_source 32-bit host \# (\d{1,5}) # cq_srcport \:\s+ (?:view\s+(\S+)\:\s+)? # cq_view query\:\s+ (\S+) # cq_data \s+\S+\s+ (\S+) # cq_type /ix; } $cq_source_count{$cq_source}++; $cq_srcport_count{$cq_srcport}++; $cq_view_count{$cq_view}++ if defined($cq_view); $cq_data_count{lc($cq_data)}++; $cq_type_count{$cq_type}++; next; } # client queries denied # # client [ip]#[port]: query '[record]/[IN|ANY]' denied # client [ip]#[port]: query denied if ($msg =~ /^client\s+\d+\.\d+\.\d+\.\d+\#\d+\:\s+query\s+\'\S+\/(IN|ANY)\'\s+denied/i ) { $cqd_total++; my ($cqd_source, $cqd_data) = (0, 0); ($cqd_source, $cqd_data) = $msg =~ /^client\s+ (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) # cqd_source \#\d+\:\s+query\s+\' (\S+) # cqd_data \/(IN|ANY)\'\s+denied/ix; $cqd_source_count{$cqd_source}++; $cqd_data_count{lc($cqd_data)}++; next; } if ($msg =~ /^client\s+\d+\.\d+\.\d+\.\d+\#\d+\:\s+query\s+denied/i ) { $cqd_total++; my ($cqd_source) = (0); ($cqd_source) = $msg =~ /^client\s+ (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) # cqd_source \#\d+\:\s+query\s+denied/ix; $cqd_source_count{$cqd_source}++; next; } # client queries cache denied # # client [ip]#[port]: query (cache) denied if ($msg =~ /^client\s+\d+\.\d+\.\d+\.\d+\#\d+\:\s+query\s+\(cache\)\s+denied/i ) { $cqcd_total++; my ($cqcd_source) = (0); ($cqcd_source) = $msg =~ /^client\s+ (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) # cqcd_source \#\d+\:\s+query\s+\(cache\)\s+denied/ix; $cqcd_source_count{$cqcd_source}++; next; } # zone loads # # zone [zone]/IN: loaded serial [serial] if ($msg =~ /^zone\s+\S+\/IN\:\s+loaded\s+serial\s+\d+/i ) { $zl_total++; my ($zl_zone) = (0); ($zl_zone) = $msg =~ /^zone\s+ (\S+) # zl_zone \/IN\:\s+loaded\s+serial\s+\d+/ix; $zl_zone_count{$zl_zone}++; next; } # server fetch requests # # createfetch: [target] [type] if ($msg =~ /^createfetch\:\s+\S+\s+\S+/i ) { $sf_total++; my ($sf_target, $sf_type) = (0, 0); ($sf_target, $sf_type) = $msg =~ /^createfetch\:\s+ (\S+) # sf_target \s+ (\S+) # sf_type /ix; $sf_target_count{lc($sf_target)}++; $sf_type_count{$sf_type}++; next; } # zone transferred # # note: BIND 9.2.1 logging spells 'transferred' wrong # zone [zone]/IN: transferr?ed serial [serial] if ($msg =~ /^zone\s+\S+\/IN\:\s+transferr?ed\s+serial\s+\d+/i ) { $zt_total++; my ($zt_zone, $zt_serial) = (0, 0); ($zt_zone, $zt_serial) = $msg =~ /^zone\s+ (\S+) # zt_zone \/IN\:\s+transferr?ed\s+serial\s+ (\d+) # zt_serial /ix; $zt_zone_count{$zt_zone}++; $zt_serial_count{$zt_serial}++; next; } # zone transfer started # # client [ip]#[port]: transfer of '[zone]/IN': # (AXFR|IXFR|AFXR-style IXFR) started if ($msg =~ /^client\s+\d+\.\d+\.\d+\.\d+\#\d+\:\s+transfer\s+of\s+\'\S+\/IN\'\:\s+(AXFR|AXFR-style IXFR|IXFR)\s+started/i ) { $zts_total++; my ($zts_target, $zts_zone, $zts_type) = (0, 0, 0); ($zts_target, $zts_zone, $zts_type) = $msg =~ /^client\s+ (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) # zts_target \#\d+\:\s+transfer\s+of\s+\' (\S+) # zts_zone \/IN\'\:\s+ (AXFR|AXFR\-style\s+IXFR|IXFR) # zts_type \s+started/ix; $zts_target_count{$zts_target}++; $zts_zone_count{$zts_zone}++; $zts_type_count{$zts_type}++; next; } # zone transfer received # # transfer of '[zone]/IN' from [ip]#[port]: end of transfer if ($msg =~ /^transfer\s+of\s+\'\S+\/IN\'\s+from\s+\d+\.\d+\.\d+\.\d+\#\d+\:\s+end\s+of\s+transfer/i ) { $ztr_total++; my ($ztr_zone, $ztr_source) = (0, 0); ($ztr_zone, $ztr_source) = $msg =~ /^transfer\s+of\s+\' (\S+) # ztr_zone \/IN\'\s+from\s+ (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) # ztr_source \#\d+\:\s+end\s+of\s+transfer/ix; $ztr_zone_count{lc($ztr_zone)}++; $ztr_source_count{$ztr_source}++; next; } # zone transfer failure # # transfer of '[zone]/IN' from [ip]#[port:] failed while receiving \ # responses: [error] if ($msg =~ /^transfer\s+of\s+\'\S+\/IN\'\s+from\s+\d+\.\d+\.\d+\.\d+\#\d+\:\s+failed\s+while\s+receiving\s+responses\:\s+\S+/i ) { $ztf_total++; my ($ztf_zone, $ztf_source, $ztf_error) = (0, 0, 0); ($ztf_zone, $ztf_source, $ztf_error) = $msg =~ /^transfer\s+of\s+\' (\S+) # ztf_zone \/IN\'\s+from\s+ (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) # ztf_source \#\d+\:\s+failed\s+while\s+ receiving\s+responses\:\s+ (\S+) # ztf_error /ix; $ztf_zone_count{lc($ztf_zone)}++; $ztf_source_count{$ztf_source}++; $ztf_error_count{$ztf_error}++; next; } # zone transfer denied # # client [ip]#[port]: zone transfer '[zone]/IN' denied if ($msg =~ /^client\s+\d+\.\d+\.\d+\.\d+\#\d+\:\s+zone\s+transfer\s+\'\S+\'\s+denied/i ) { $ztd_total++; my ($ztd_source, $ztd_zone) = (0, 0); ($ztd_source, $ztd_zone) = $msg =~ /^client\s+ (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) # ztd_source \#\d+\:\s+zone\s+transfer\s+\' (\S+) # ztd_zone \/IN\'\s+denied/ix; $ztd_source_count{$ztd_source}++; $ztd_zone_count{lc($ztd_zone)}++; next; } # bad zone transfer # # client [ip]#[port]: bad zone transfer request: '[zone]/IN': [desc] if ($msg =~ /^client\s+\d+\.\d+\.\d+\.\d+\#\d+\:\s+bad\s+zone\s+transfer\s+request\:\s+\'\S+\/IN\'\:\s+.*/i ) { $bzt_total++; my ($bzt_source, $bzt_zone, $bzt_desc) = (0, 0, 0); ($bzt_source, $bzt_zone, $bzt_desc) = $msg =~ /^client\s+ (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) # bzt_source \#\d+\:\s+bad\s+zone\s+transfer\s+ request\:\s+\' (\S+) # bzt_zone \/IN\'\:\s+ (.*) # bzt_desc /ix; $bzt_source_count{$bzt_source}++; $bzt_zone_count{$bzt_zone}++; $bzt_desc_count{$bzt_desc}++; next; } # zone refresh failure timed out # # zone [zone]/IN: refresh: failure trying master [ip]#[port]: timed out if ($msg =~ /^zone\s+\S+\/IN\:\s+refresh\:\s+failure\s+trying\s+master\s+\d+\.\d+\.\d+\.\d+\#\d+\:\s+timed\s+out/i ) { $zrfto_total++; my ($zrfto_zone, $zrfto_master) = (0, 0); ($zrfto_zone, $zrfto_master) = $msg =~ /^zone\s+ (\S+) # zrfto_zone \/IN\:\s+refresh\:\s+failure\s+ trying\s+master\s+ (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) # zrfto_master \#\d+\:\s+timed\s+out/ix; $zrfto_zone_count{$zrfto_zone}++; $zrfto_master_count{$zrfto_master}++; next; } # zone refresh retry limit exceeded # # zone [zone]/IN: refresh: retry limit for master [ip]#[port] exceeded if ($msg =~ /^zone\s+\S+\/IN\:\s+refresh\:\s+retry\s+limit\s+for\s+master\s+\d+\.\d+\.\d+\.\d+\#\d+\s+exceeded/i ) { $zrrle_total++; my ($zrrle_zone, $zrrle_master) = (0, 0); ($zrrle_zone, $zrrle_master) = $msg =~ /^zone\s+ (\S+) # zrrle_zone \/IN\:\s+refresh\:\s+retry\s+limit\s+ for\s+master\s+ (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) # zrrle_master \#\d+\s+exceeded/ix; $zrrle_zone_count{$zrrle_zone}++; $zrrle_master_count{$zrrle_master}++; next; } # zone update # # client [ip]#[port]: updating zone '[zone]/IN': (adding|deleting) an # (RR|rrset) if ($msg =~ /^client\s+\d+\.\d+\.\d+\.\d+\#\d+\:\s+updating\s+zone\s+\'\S+\/IN\'\:\s+(adding|deleting)\s+an\s+(RR|rrset)/i ) { $zu_total++; my ($zu_source, $zu_zone, $zu_desc) = (0, 0, 0); ($zu_source, $zu_zone, $zu_desc) = $msg =~ /^client\s+ (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) # zu_source \#\d+\:\s+updating\s+zone\s+\' (\S+) # zu_zone \/IN\'\:\s+ (.*) # zu_desc /ix; $zu_source_count{$zu_source}++; $zu_zone_count{$zu_zone}++; $zu_desc_count{$zu_desc}++; next; } # zone update failure # # client [ip]#[port]: updating zone '[zone]/IN': update failed: [desc] # client [ip]#[port]: update '[zone]/IN' denied if ($msg =~ /^client\s+\d+\.\d+\.\d+\.\d+\#\d+\:\s+updating\s+zone\s+\'\S+\/IN\'\:\s+update\s+failed\:\s+.*/i ) { $zuf_total++; my ($zuf_source, $zuf_zone, $zuf_desc) = (0, 0, 0); ($zuf_source, $zuf_zone, $zuf_desc) = $msg =~ /^client\s+ (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) # zuf_source \#\d+\:\s+updating\s+zone\s+\' (\S+) # zuf_zone \/IN\'\:\s+update\s+failed\:\s+ (.*) # zuf_desc /ix; $zuf_source_count{$zuf_source}++; $zuf_zone_count{$zuf_zone}++; $zuf_desc_count{$zuf_desc}++; next; } if ($msg =~ /^client\s+\d+\.\d+\.\d+\.\d+\#\d+\:\s+update\s+\'\S+\/IN\'\s+denied/i ) { $zuf_total++; my ($zuf_source, $zuf_zone) = $msg =~ /^client\s+ (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) # zuf_source \#\d+\:\s+update\s+\' (\S+) # zuf_zone \/IN\'\s+denied/ix; $zuf_source_count{$zuf_source}++; $zuf_zone_count{$zuf_zone}++; next; } # lame server report # # note: bind 9.2.x changed 'on' to 'resolving' # lame server [on|resolving] '[record]' (in '[zone]'?): [ip]#[port] if ($msg =~ /^lame\s+server\s+(on|resolving)\s+\'\S+\'\s+\(in\s+\'\S+\'\?\)\:\s+\S+\#\S+/i ) { $ls_total++; my ($ls_record, $ls_zone, $ls_server) = (0, 0, 0); ($ls_record, $ls_zone, $ls_server) = $msg =~ /^lame\s+server\s+\S+\s+\' (\S+) # ls_record \'\s+\(in\s+\' (\S+) # ls_zone \'\?\)\:\s+ (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) # ls_server \#\d+/ix; $ls_record_count{lc($ls_record)}++; $ls_zone_count{lc($ls_zone)}++; $ls_server_count{$ls_server}++; $ls_servzone_count{$ls_server . "\t" . lc($ls_zone)}++; next; } # version scanning # # client [ip]#[port]: query: VERSION.BIND CH TXT if ($msg =~ /^client\s+\d+\.\d+\.\d+\.\d+\#\d+\:\s+query\:\s+VERSION.BIND\s+CH\s+TXT/i ) { $vs_total++; my $vs_source = 0; ($vs_source) = $msg =~ /^client\s+ (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) # vs_source \S+\s+query\:\s+ VERSION\.BIND\s+CH\s+TXT/ix; $vs_source_count{$vs_source}++; next; } # version scanning denied # # client [ip]#[port]: query 'VERSION.BIND/CH' denied if ($msg =~ /^client\s+\d+\.\d+\.\d+\.\d+\#\d+\:\s+query\s+\'VERSION.BIND\/CH\'\s+denied/i ) { $vsd_total++; my $vsd_source = 0; ($vsd_source) = $msg =~ /^client\s+ (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) # vsd_source \S+\s+query\s+\ \'VERSION\.BIND\/CH\'\s+denied/ix; $vsd_source_count{$vsd_source}++; next; } # broken client queries # # client [ip]#[port]: no matching view in class 'CLASS[class]' # client [ip]#[port]: message class could not be determined if ($msg =~ /^client\s+\d+\.\d+\.\d+\.\d+\#\d+\:\s+no\s+matching\s+view\s+in\s+class\s+\'CLASS\d+\'/i ) { $bcq_total++; my ($bcq_source, $bcq_class) = (0, 0); ($bcq_source, $bcq_class) = $msg =~ /^client\s+ (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) # bcq_source \S+\s+ no\s+matching\s+view\s+in\s+class\s+ \'CLASS (\d+) # bcq_class \'/ix; $bcq_source_count{$bcq_source}++; $bcq_class_count{$bcq_class}++; next; } if ($msg =~ /^client\s+\d+\.\d+\.\d+\.\d+\#\d+\:\s+message\s+class\s+could\s+not\s+be\s+determined/i ) { $bcq_total++; my ($bcq_source) = (0); ($bcq_source) = $msg =~ /^client\s+ (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) # bcq_source \#\d+\:\s+message\s+class\s+could \s+not\s+be\s+determined/ix; $bcq_source_count{$bcq_source}++; next; } # quota reached - recursive clients # # client [ip]#[port]: no more recursive clients: quota reached if ($msg =~ /^client\s+\d+\.\d+\.\d+\.\d+\#\d+\:\s+no\s+more\s+recursive\s+clients\:\s+quota\s+reached/i ) { $qrrc_total++; my ($qrrc_source) = (0); ($qrrc_source) = $msg =~ /^client\s+ (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) # qrrc_source \#\d+\:\s+no\s+more\s+recursive \s+clients\:\s+quota\s+reached/ix; $qrrc_source_count{$qrrc_source}++; next; } # quota reached - TCP clients # # client [ip]#[port]: no more TCP clients: quota reached if ($msg =~ /^client\s+\d+\.\d+\.\d+\.\d+\#\d+\:\s+no\s+more\s+TCP\s+clients\:\s+quota\s+reached/i ) { $qrtc_total++; my ($qrtc_source) = (0); ($qrtc_source) = $msg =~ /^client\s+ (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) # qrtc_source \#\d+\:\s+no\s+more\s+TCP\s+clients \s\:\s+quota\s+reached/ix; $qrtc_source_count{$qrtc_source}++; next; } # format error # # client [ip]#[port]: possible error packet loop, FORMERR dropped if ($msg =~ /^client\s+\d+\.\d+\.\d+\.\d+\#\d+\:\s+possible\s+error\s+packet\s+loop\,\s+FORMERR\s+dropped/i ) { $fe_total++; my ($fe_source) = (0); ($fe_source) = $msg =~ /^client\s+ (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) # fe_source \#\d+\:\s+possible\s+error\s+packet \s+loop\,\s+FORMERR\s+dropped/ix; $fe_source_count{$fe_source}++; next; } # sending notify # # zone [zone]/IN: sending notifies (serial [serial]) if ($msg =~ /^zone\s+\S+\/IN\:\s+sending\s+notifies\s+\(serial\s+\d+\)/i ) { $sn_total++; my ($sn_zone, $sn_serial) = (0, 0); ($sn_zone, $sn_serial) = $msg =~ /^zone\s+ (\S+) # sn_zone \/IN\:\s+sending\s+notifies\s+ \(serial\s+ (\d+) # sn_serial \)/ix; $sn_zone_count{$sn_zone}++; $sn_serial_count{$sn_serial}++; next; } # sending notify failed # # zone [zone]/IN: notify to [ip]#[port]: retries exceeded # zone [zone]/IN: notify to [ip]#[port] failed: [description] if ($msg =~ /^zone\s+\S+\/IN\:\s+notify\s+to\s+\d+\.\d+\.\d+\.\d+\#\d+(\s+failed)?\:\s+.*/i ) { $snf_total++; my ($snf_zone, $snf_dst, $snf_desc) = (0, 0, 0); ($snf_zone, $snf_dst, $snf_desc) = $msg =~ /^zone\s+ (\S+) # snf_zone \/IN\:\s+notify\s+to\s+ (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) # snf_dst \#\d+.*\:\s+ (.*) # snf_desc /ix; $snf_zone_count{$snf_zone}++; $snf_dst_count{$snf_dst}++; $snf_desc_count{$snf_desc}++; next; } # received notify - not authoritative # # received notify for zone '[zone]': not authoritative if ($msg =~ /^received\s+notify\s+for\s+zone\s+\'\S+\'\:\s+not\s+authoritative/i ) { $rnna_total++; my ($rnna_zone) = (0); ($rnna_zone) = $msg =~ /^received\s+notify\s+for\s+zone\s+\' (\S+) # rnna_zone \'\:\s+not\s+authoritative/ix; $rnna_zone_count{$rnna_zone}++; next; } # error sending response # # client [ip]#[port]: error sending response: [description] if ($msg =~ /^client\s+\d+\.\d+\.\d+\.\d+\#\d+\:\s+error\s+sending\s+response\:\s+.*/i ) { $esr_total++; my ($esr_dst, $esr_desc) = (0, 0); ($esr_dst, $esr_desc) = $msg =~ /^client\s+ (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) # esr_dst \#\d+\:\s+error\s+sending\s+response\:\s+ (.*) # esr_desc /ix; $esr_dst_count{$esr_dst}++; $esr_desc_count{$esr_desc}++; next; } # insecure updates # # zone '[zone]' allows updates by IP address, which is insecure if ($msg =~ /^zone\s+\'\S+\'\s+allows\s+updates\s+by\s+IP\s+address\,\s+which\s+is\s+insecure/i ) { $iu_total++; my ($iu_zone) = (0); ($iu_zone) = $msg =~ /^zone\s+\' (\S+) # iu_zone \'\s+allows\s+updates\s+by\s+IP\s+ address\,\s+which\s+is\s+insecure/ix; $iu_zone_count{$iu_zone}++; next; } # other (unknown log messages) - DEFAULT CASE $other_total++; if ($opts{d}) { print "[DEBUG] UNKNOWN LOG MESSAGE: $log\n"; } } # END SWITCH # if in a multiple repeat message redo loop, keep going if (--$redo_count > 0) { goto LOG; } } # END WHILE # # generate output # # If there are unknown log messages and DEBUG is disabled, issue warning if ($other_total && !$opts{d}) { print "WARNING: unknown log messages detected, enable DEBUG to view.\n\n"; } print "-----------------------------------\n"; print " ISC BIND named log summary report \n"; print "-----------------------------------\n"; print "Total log messages: $log_total\n"; if ($s_total) { print "Total server status messages: $s_total\n"; } if ($slc_total) { print "Total server config loads: $slc_total\n"; } if ($snif_total) { print "Total IPv6 interfaces not found: $snif_total\n"; } if ($sr_total) { print "Total server runs: $sr_total\n"; } if ($se_total) { print "Total server exits: $se_total\n"; } if ($ssd_total) { print "Total server shut downs: $ssd_total\n"; } if ($sscc_total) { print "Total server command channel stops: $sscc_total\n"; } if ($snll_total) { print "Total server run stops: $snll_total\n"; } if ($ic_total) { print "Total invalid commands: $ic_total\n"; } if ($jfc_total) { print "Total journal file creations: $jfc_total\n"; } if ($cq_total) { print "Total client queries: $cq_total\n"; } if ($cqd_total){ print "Total client denies: $cqd_total\n"; } if ($cqcd_total) { print "Total client cache denies: $cqcd_total\n"; } if ($zl_total) { print "Total zone loads: $zl_total\n"; } if ($sf_total) { print "Total server fetches: $sf_total\n"; } if ($zts_total) { print "Total zone transfers started: $zts_total\n"; } if ($ztr_total) { print "Total zone transfers received: $ztr_total\n"; } if ($ztf_total) { print "Total zone transfer failures: $ztf_total\n"; } if ($ztd_total) { print "Total zone transfer denies: $ztd_total\n"; } if ($bzt_total) { print "Total bad zone transfers: $bzt_total\n"; } if ($zrfto_total) { print "Total zone refresh time outs: $zrfto_total\n"; } if ($zrrle_total) { print "Total zone refresh retry exceeds: $zrrle_total\n"; } if ($zu_total) { print "Total zone update messages: $zu_total\n"; } if ($zuf_total) { print "Total zone update failure messages: $zuf_total\n"; } if ($ls_total) { print "Total lame server reports: $ls_total\n"; } if ($vs_total) { print "Total version scans: $vs_total\n"; } if ($vsd_total) { print "Total version scans denied: $vsd_total\n"; } if ($bcq_total) { print "Total broken client queries: $bcq_total\n"; } if ($qrrc_total || $qrtc_total) { print "Total quota reached attempts: " . ($qrrc_total + $qrtc_total) . "\n"; } if ($fe_total) { print "Total format errors: $fe_total\n"; } if ($sn_total) { print "Total notifies sent: $sn_total\n"; } if ($snf_total) { print "Total notify send failures: $snf_total\n"; } if ($rnna_total) { print "Total receive notify not auth errs: $rnna_total\n"; } if ($esr_total) { print "Total error sending responses: $esr_total\n"; } if ($other_total) { print "Total other (unknown) messages: $other_total\n"; } ## BEGIN $TOPx reports below ### # slc_file_count - server load configuration file count if ($slc_total) { print "\nTop $TOPx server config loads\n"; print "Count\tFile\n"; my $counter = 1; for my $item (sort{$slc_file_count{$b} - $slc_file_count{$a}} keys %slc_file_count) { print "$slc_file_count{$item}\t$item\n"; last if ++$counter > $TOPx; } } # sscc_ip_count - server stop command channel ip count if ($sscc_total) { print "\nTop $TOPx server command channel IP stops\n"; print "Count\tIP\n"; my $counter = 1; for my $item (sort{$sscc_ip_count{$b} - $sscc_ip_count{$a}} keys %sscc_ip_count) { print "$sscc_ip_count{$item}\t$item\n"; last if ++$counter > $TOPx; } } # sloi_int_count - server listening on interface interface count if ($sloi_total) { print "\nTop $TOPx server interfaces listening\n"; print "Count\tInterface\n"; my $counter = 1; for my $item (sort{$sloi_int_count{$b} - $sloi_int_count{$a}} keys %sloi_int_count) { print "$sloi_int_count{$item}\t$item\n"; last if ++$counter > $TOPx; } } # sloi_ip_count - server listening on interface ip count if ($sloi_total) { print "\nTop $TOPx server IPs listening\n"; print "Count\tIP\n"; my $counter = 1; for my $item (sort{$sloi_ip_count{$b} - $sloi_ip_count{$a}} keys %sloi_ip_count) { print "$sloi_ip_count{$item}\t$item\n"; last if ++$counter > $TOPx; } } # snll_ip_count - server no longer running ip count if ($snll_total) { print "\nTop $TOPx server run stop\n"; print "Count\tIP\n"; my $counter = 1; for my $item (sort{$snll_ip_count{$b} - $snll_ip_count{$a}} keys %snll_ip_count) { print "$snll_ip_count{$item}\t$item\n"; last if ++$counter > $TOPx; } } # ic_source_count - invalid command source count if ($ic_total) { print "\nTop $TOPx IPs sourcing invalid commands\n"; print "Count\tSource\n"; my $counter = 1; for my $item (sort{$ic_source_count{$b} - $ic_source_count{$a}} keys %ic_source_count) { # don't bother trying to resolve a loopback IP if ($opts{r} && $item !~ /^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$/) { my $name = ""; $name = gethostbyaddr(inet_aton($item), AF_INET) or $name = "[lookup failed]"; print "$ic_source_count{$item}\t$item\t$name\n"; } else { print "$ic_source_count{$item}\t$item\n"; } last if ++$counter > $TOPx; } } # ic_desc_count - invalid command description count if ($ic_total) { print "\nTop $TOPx invalid command responses\n"; print "Count\tResponse\n"; my $counter = 1; for my $item (sort{$ic_desc_count{$b} - $ic_desc_count{$a}} keys %ic_desc_count) { print "$ic_desc_count{$item}\t$item\n"; last if ++$counter > $TOPx; } } # jfc_file_count - journal file creation file count if ($jfc_total) { print "\nTop $TOPx journal files created\n"; print "Count\tFile\n"; my $counter = 1; for my $item (sort{$jfc_file_count{$b} - $jfc_file_count{$a}} keys %jfc_file_count) { print "$jfc_file_count{$item}\t$item\n"; last if ++$counter > $TOPx; } } # cq_source_count - client query source count if ($cq_total) { print "\nTop $TOPx IP clients\n"; print "Count\tSource "; if ($opts{p}) { print "(/24 subnet)\n"; } else { print "(/32 host)\n"; } my $counter = 1; for my $item (sort{$cq_source_count{$b} - $cq_source_count{$a}} keys %cq_source_count) { if (!$opts{p} && $opts{r}) { my $name = ""; $name = gethostbyaddr(inet_aton($item), AF_INET) or $name = "[lookup failed]"; print "$cq_source_count{$item} "; printf "\(%.2f%%\)\t", ($cq_source_count{$item}/$cq_total) * 100; print "$item\t$name\n"; } else { print "$cq_source_count{$item} "; printf "\(%.2f%%\)\t", ($cq_source_count{$item}/$cq_total) * 100; print "$item\n"; } last if ++$counter > $TOPx; } } # cq_srcport_count - client query source port count if ($cq_total) { print "\nTop $TOPx Source Ports\n"; print "Count\tQuery\n"; my $counter = 1; for my $item (sort{$cq_srcport_count{$b} - $cq_srcport_count{$a}} keys %cq_srcport_count) { print "$cq_srcport_count{$item}\t$item\n"; last if ++$counter > $TOPx; } } # cq_view_count - client query view count if ($cq_total) { print "\nTop $TOPx Views\n"; print "Count\tView\n"; my $counter = 1; for my $item (sort{$cq_view_count{$b} - $cq_view_count{$a}} keys %cq_view_count) { print "$cq_view_count{$item}\t$item\n"; last if ++$counter > $TOPx; } } # cq_data_count - client query data count if ($cq_total) { print "\nTop $TOPx Queries\n"; print "Count\tQuery\n"; my $counter = 1; for my $item (sort{$cq_data_count{$b} - $cq_data_count{$a}} keys %cq_data_count) { print "$cq_data_count{$item} "; printf " \(%.2f%%\)\t", ($cq_data_count{$item}/$cq_total) * 100; print "$item\n"; last if ++$counter > $TOPx; } } # cq_type_count - client query type count if ($cq_total) { print "\nTop $TOPx Query Types\n"; print "Count\tType\n"; my $counter = 1; for my $item (sort{$cq_type_count{$b} - $cq_type_count{$a}} keys %cq_type_count) { print "$cq_type_count{$item} "; printf " \(%.2f%%\)\t", ($cq_type_count{$item}/$cq_total) * 100; print "$item\n"; last if ++$counter > $TOPx; } } # cqd_data_count - client query denied data count if ($cqd_total) { print "\nTop $TOPx queries denied\n"; print "Count\tQuery\n"; my $counter = 1; for my $item (sort{$cqd_data_count{$b} - $cqd_data_count{$a}} keys %cqd_data_count) { print "$cqd_data_count{$item}\t$item\n"; last if ++$counter > $TOPx; } } # cqcd_source_count - client query cache denied source count if ($cqcd_total) { print "\nTop $TOPx IP client query cache denies\n"; print "Count\tSource\n"; my $counter = 1; for my $item (sort{$cqcd_source_count{$b} - $cqcd_source_count{$a}} keys %cqcd_source_count) { if ($opts{r}) { my $name = ""; $name = gethostbyaddr(inet_aton($item), AF_INET) or $name = "[lookup failed]"; print "$cqcd_source_count{$item}\t$item\t$name\n"; } else { print "$cqcd_source_count{$item}\t$item\n"; } last if ++$counter > $TOPx; } } # zl_zone_count - zone load zone count if ($zl_total) { print "\nTop $TOPx zones loaded\n"; print "Count\tZone\n"; my $counter = 1; for my $item (sort{$zl_zone_count{$b} - $zl_zone_count{$a}} keys %zl_zone_count) { print "$zl_zone_count{$item}\t$item\n"; last if ++$counter > $TOPx; } } # sf_target_count - server fetch target count if ($sf_total) { print "\nTop $TOPx fetches\n"; print "Count\tTarget\n"; my $counter = 1; for my $item (sort{$sf_target_count{$b} - $sf_target_count{$a}} keys %sf_target_count) { print "$sf_target_count{$item}\t$item\n"; last if ++$counter > $TOPx; } } # sf_type_count - server fetch type count if ($sf_total) { print "\nTop $TOPx fetch types\n"; print "Count\tType\n"; my $counter = 1; for my $item (sort{$sf_type_count{$b} - $sf_type_count{$a}} keys %sf_type_count) { print "$sf_type_count{$item}\t$item\n"; last if ++$counter > $TOPx; } } # zt_zone_count - zone transferred zone count if ($zt_total) { print "\nTop $TOPx zones transferred\n"; print "Count\tZone\n"; my $counter = 1; for my $item (sort{$zt_zone_count{$b} - $zt_zone_count{$a}} keys %zt_zone_count) { print "$zt_zone_count{$item}\t$item\n"; last if ++$counter > $TOPx; } } # zt_serial_count - zone transferred serial count if ($zt_total) { print "\nTop $TOPx zone transferred serials\n"; print "Count\tSerial\n"; my $counter = 1; for my $item (sort{$zt_serial_count{$b} - $zt_serial_count{$a}} keys %zt_serial_count) { print "$zt_serial_count{$item}\t$item\n"; last if ++$counter > $TOPx; } } # zts_zone_count - zone transfer started zone count if ($zts_total) { print "\nTop $TOPx zone transfers started\n"; print "Count\tZone\n"; my $counter = 1; for my $item (sort{$zts_zone_count{$b} - $zts_zone_count{$a}} keys %zts_zone_count) { print "$zts_zone_count{$item}\t$item\n"; last if ++$counter > $TOPx; } } # zts_target_count - zone transfer started target count if ($zts_total) { print "\nTop $TOPx zone transfer started targets\n"; print "Count\tTarget\n"; my $counter = 1; for my $item (sort{$zts_target_count{$b} - $zts_target_count{$a}} keys %zts_target_count) { if ($opts{r}) { my $name = ""; $name = gethostbyaddr(inet_aton($item), AF_INET) or $name = "[lookup failed]"; print "$zts_target_count{$item}\t$item\t$name\n"; } else { print "$zts_target_count{$item}\t$item\n"; } last if ++$counter > $TOPx; } } # zts_type_count - zone transfer started type count if ($zts_total) { print "\nTop $TOPx zone transfers started types\n"; print "Count\tType\n"; my $counter = 1; for my $item (sort{$zts_type_count{$b} - $zts_type_count{$a}} keys %zts_type_count) { print "$zts_type_count{$item}\t$item\n"; last if ++$counter > $TOPx; } } # ztr_zone_count - zone transfer received zone count if ($ztr_total) { print "\nTop $TOPx zone transfers received\n"; print "Count\tZone\n"; my $counter = 1; for my $item (sort{$ztr_zone_count{$b} - $ztr_zone_count{$a}} keys %ztr_zone_count) { print "$ztr_zone_count{$item}\t$item\n"; last if ++$counter > $TOPx; } } # ztr_source_count - zone transfer received source count if ($ztr_total) { print "\nTop $TOPx zone transfer receive sources\n"; print "Count\tSource\n"; my $counter = 1; for my $item (sort{$ztr_source_count{$b} - $ztr_source_count{$a}} keys %ztr_source_count) { if ($opts{r}) { my $name = ""; $name = gethostbyaddr(inet_aton($item), AF_INET) or $name = "[lookup failed]"; print "$ztr_source_count{$item}\t$item\t$name\n"; } else { print "$ztr_source_count{$item}\t$item\n"; } last if ++$counter > $TOPx; } } # ztf_zone_count - zone transfer failure zone count if ($ztf_total) { print "\nTop $TOPx zones transferred unsuccessfully\n"; print "Count\tZone\n"; my $counter = 1; for my $item (sort{$ztf_zone_count{$b} - $ztf_zone_count{$a}} keys %ztf_zone_count) { print "$ztf_zone_count{$item}\t$item\n"; last if ++$counter > $TOPx; } } # ztf_source_count - zone transfer failure source count if ($ztf_total) { print "\nTop $TOPx sources of failed zone transfers\n"; print "Count\tSource\n"; my $counter = 1; for my $item (sort{$ztf_source_count{$b} - $ztf_source_count{$a}} keys %ztf_source_count) { if ($opts{r}) { my $name = ""; $name = gethostbyaddr(inet_aton($item), AF_INET) or $name = "[lookup failed]"; print "$ztf_source_count{$item}\t$item\t$name\n"; } else { print "$ztf_source_count{$item}\t$item\n"; } last if ++$counter > $TOPx; } } # ztf_error_count - zone transfer failure error count if ($ztf_total) { print "\nTop $TOPx zone transfer errors\n"; print "Count\tError\n"; my $counter = 1; for my $item (sort{$ztf_error_count{$b} - $ztf_error_count{$a}} keys %ztf_error_count) { print "$ztf_error_count{$item}\t$item\n"; last if ++$counter > $TOPx; } } # ztd_source_count - zone transfer denied source count if ($ztd_total) { print "\nTop $TOPx zone transfer clients denied\n"; print "Count\tSource\n"; my $counter = 1; for my $item (sort{$ztd_source_count{$b} - $ztd_source_count{$a}} keys %ztd_source_count) { if ($opts{r}) { my $name = ""; $name = gethostbyaddr(inet_aton($item), AF_INET) or $name = "[lookup failed]"; print "$ztd_source_count{$item}\t$item\t$name\n"; } else { print "$ztd_source_count{$item}\t$item\n"; } last if ++$counter > $TOPx; } } # ztd_zone_count - zone transfer denied zone count if ($ztd_total) { print "\nTop $TOPx zone transfer zones denied\n"; print "Count\tZone\n"; my $counter = 1; for my $item (sort{$ztd_zone_count{$b} - $ztd_zone_count{$a}} keys %ztd_zone_count) { print "$ztd_zone_count{$item}\t$item\n"; last if ++$counter > $TOPx; } } # bzt_source_count - bad zone transfer source count if ($bzt_total) { print "\nTop $TOPx bad zone transfer sources\n"; print "Count\tSource\n"; my $counter = 1; for my $item (sort{$bzt_source_count{$b} - $bzt_source_count{$a}} keys %bzt_source_count) { print "$bzt_source_count{$item}\t$item\n"; last if ++$counter > $TOPx; } } # bzt_zone_count - bad zone transfer zone count if ($bzt_total) { print "\nTop $TOPx bad zones attempted transfer\n"; print "Count\tZone\n"; my $counter = 1; for my $item (sort{$bzt_zone_count{$b} - $bzt_zone_count{$a}} keys %bzt_zone_count) { print "$bzt_zone_count{$item}\t$item\n"; last if ++$counter > $TOPx; } } # bzt_desc_count - bad zone transfer description count if ($bzt_total) { print "\nTop $TOPx bad zone attempt reasons\n"; print "Count\tReasons\n"; my $counter = 1; for my $item (sort{$bzt_desc_count{$b} - $bzt_desc_count{$a}} keys %bzt_desc_count) { print "$bzt_desc_count{$item}\t$item\n"; last if ++$counter > $TOPx; } } # zrfto_zone_count - zone refresh failure timed out zone count if ($zrfto_total) { print "\nTop $TOPx refresh failed, timed out zones\n"; print "Count\tZone\n"; my $counter = 1; for my $item (sort{$zrfto_zone_count{$b} - $zrfto_zone_count{$a}} keys %zrfto_zone_count) { print "$zrfto_zone_count{$item}\t$item\n"; last if ++$counter > $TOPx; } } # zrfto_master_count - zone refresh failure timed out master count if ($zrfto_total) { print "\nTop $TOPx refresh failed, timed out masters\n"; print "Count\tMaster\n"; my $counter = 1; for my $item (sort{$zrfto_master_count{$b} - $zrfto_master_count{$a}} keys %zrfto_master_count) { print "$zrfto_master_count{$item}\t$item\n"; last if ++$counter > $TOPx; } } # zrrle_zone_count - zone refresh retry limit exceeded zone count if ($zrrle_total) { print "\nTop $TOPx refresh retry limit exceeded zones\n"; print "Count\tZone\n"; my $counter = 1; for my $item (sort{$zrrle_zone_count{$b} - $zrrle_zone_count{$a}} keys %zrrle_zone_count) { print "$zrrle_zone_count{$item}\t$item\n"; last if ++$counter > $TOPx; } } # zrrle_master_count - zone refresh retry limit exceeded master count if ($zrrle_total) { print "\nTop $TOPx refresh retry limit exceeded masters\n"; print "Count\tMaster\n"; my $counter = 1; for my $item (sort{$zrrle_master_count{$b} - $zrrle_master_count{$a}} keys %zrrle_master_count) { print "$zrrle_master_count{$item}\t$item\n"; last if ++$counter > $TOPx; } } # zu_source_count - zone update source count if ($zu_total) { print "\nTop $TOPx zone update sources\n"; print "Count\tSource\n"; my $counter = 1; for my $item (sort{$zu_source_count{$b} - $zu_source_count{$a}} keys %zu_source_count) { print "$zu_source_count{$item}\t$item\n"; last if ++$counter > $TOPx; } } # zu_zone_count - zone update zone count if ($zu_total) { print "\nTop $TOPx zones in zone update messages\n"; print "Count\tZone\n"; my $counter = 1; for my $item (sort{$zu_zone_count{$b} - $zu_zone_count{$a}} keys %zu_zone_count) { print "$zu_zone_count{$item}\t$item\n"; last if ++$counter > $TOPx; } } # zu_desc_count - zone update description count if ($zu_total) { print "\nTop $TOPx zone update message types\n"; print "Count\tMessage\n"; my $counter = 1; for my $item (sort{$zu_desc_count{$b} - $zu_desc_count{$a}} keys %zu_desc_count) { print "$zu_desc_count{$item}\t$item\n"; last if ++$counter > $TOPx; } } # zuf_source_count - zone update failure source count if ($zuf_total) { print "\nTop $TOPx zone update failure sources\n"; print "Count\tSource\n"; my $counter = 1; for my $item (sort{$zuf_source_count{$b} - $zuf_source_count{$a}} keys %zuf_source_count) { print "$zuf_source_count{$item}\t$item\n"; last if ++$counter > $TOPx; } } # zuf_zone_count - zone update failure zone count if ($zuf_total) { print "\nTop $TOPx zone update failure zones\n"; print "Count\tZone\n"; my $counter = 1; for my $item (sort{$zuf_zone_count{$b} - $zuf_zone_count{$a}} keys %zuf_zone_count) { print "$zuf_zone_count{$item}\t$item\n"; last if ++$counter > $TOPx; } } # zuf_desc_count - zone update failure description count if ($zuf_total) { print "\nTop $TOPx zone update failure reasons\n"; print "Count\tReasons\n"; my $counter = 1; for my $item (sort{$zuf_desc_count{$b} - $zuf_desc_count{$a}} keys %zuf_desc_count) { print "$zuf_desc_count{$item}\t$item\n"; last if ++$counter > $TOPx; } } # ls_zone_count - lame server zone count if ($ls_total) { print "\nTop $TOPx lame zones\n"; print "Count\tZone\n"; my $counter = 1; for my $item (sort{$ls_zone_count{$b} - $ls_zone_count{$a}} keys %ls_zone_count) { print "$ls_zone_count{$item}\t$item\n"; last if ++$counter > $TOPx; } } # ls_server_count - lame server server count if ($ls_total) { print "\nTop $TOPx lame servers\n"; print "Count\tServer\n"; my $counter = 1; for my $item (sort{$ls_server_count{$b} - $ls_server_count{$a}} keys %ls_server_count) { if ($opts{r}) { my $name = ""; $name = gethostbyaddr(inet_aton($item), AF_INET) or $name = "[lookup failed]"; print "$ls_server_count{$item}\t$item\t$name\n"; } else { print "$ls_server_count{$item}\t$item\n"; } last if ++$counter > $TOPx; } } # ls_record_count - lame server record count if ($ls_total) { print "\nTop $TOPx lame records\n"; print "Count\tRecord\n"; my $counter = 1; for my $item (sort{$ls_record_count{$b} - $ls_record_count{$a}} keys %ls_record_count) { print "$ls_record_count{$item}\t$item\n"; last if ++$counter > $TOPx; } } # ls_servzone_count - lame server server/zone tuple count if ($ls_total) { print "\nTop $TOPx lame server/zone tuples\n"; print "Count\tServer [(name)] / Zone\n"; my $counter = 1; for my $item (sort{$ls_servzone_count{$b} - $ls_servzone_count{$a}} keys %ls_servzone_count) { print "$ls_servzone_count{$item}\t"; my $ip = ""; my $zone = ""; ($ip, $zone) = split( /\t/, $item, 2); if ($opts{r}) { my $name = ""; $name = gethostbyaddr(inet_aton($ip), AF_INET) or $name = "[lookup failed]"; print "$ip ($name) / $zone\n"; } else { print "$ip / $zone\n"; } last if ++$counter > $TOPx; } } # vs_source_count - version scanning source count if ($vs_total) { print "\nTop $TOPx version scanning sources\n"; print "Count\tSource\n"; my $counter = 1; for my $item (sort{$vs_source_count{$b} - $vs_source_count{$a}} keys %vs_source_count) { if ($opts{r}) { my $name = ""; $name = gethostbyaddr(inet_aton($item), AF_INET) or $name = "[lookup failed]"; print "$vs_source_count{$item}\t$item\t$name\n"; } else { print "$vs_source_count{$item}\t$item\n"; } last if ++$counter > $TOPx; } } # vsd_source_count - version scanning denied source count if ($vsd_total) { print "\nTop $TOPx version scanning denies\n"; print "Count\tSource\n"; my $counter = 1; for my $item (sort{$vsd_source_count{$b} - $vsd_source_count{$a}} keys %vsd_source_count) { if ($opts{r}) { my $name = ""; $name = gethostbyaddr(inet_aton($item), AF_INET) or $name = "[lookup failed]"; print "$vsd_source_count{$item}\t$item\t$name\n"; } else { print "$vsd_source_count{$item}\t$item\n"; } last if ++$counter > $TOPx; } } # bcq_source_count - broken client query source count if ($bcq_total) { print "\nTop $TOPx broken clients\n"; print "Count\tSource\n"; my $counter = 1; for my $item (sort{$bcq_source_count{$b} - $bcq_source_count{$a}} keys %bcq_source_count) { if ($opts{r}) { my $name = ""; $name = gethostbyaddr(inet_aton($item), AF_INET) or $name = "[lookup failed]"; print "$bcq_source_count{$item}\t$item\t$name\n"; } else { print "$bcq_source_count{$item}\t$item\n"; } last if ++$counter > $TOPx; } } # bcq_class_count - broken client query class count if ($bcq_total) { print "\nTop $TOPx invalid class views\n"; print "Count\tClass\n"; my $counter = 1; for my $item (sort{$bcq_class_count{$b} - $bcq_class_count{$a}} keys %bcq_class_count) { print "$bcq_class_count{$item}\t$item\n"; last if ++$counter > $TOPx; } } # qrrc_source_count - quota reached recursive client source count if ($qrrc_total) { print "\nTop $TOPx quota reached recursive clients\n"; print "Count\tSource\n"; my $counter = 1; for my $item (sort{$qrrc_source_count{$b} - $qrrc_source_count{$a}} keys %qrrc_source_count) { if ($opts{r}) { my $name = ""; $name = gethostbyaddr(inet_aton($item), AF_INET) or $name = "[lookup failed]"; print "$qrrc_source_count{$item}\t$item\t$name\n"; } else { print "$qrrc_source_count{$item}\t$item\n"; } last if ++$counter > $TOPx; } } # qrtc_source_count - quota reached TCP client source count if ($qrtc_total) { print "\nTop $TOPx quota reached TCP clients\n"; print "Count\tSource\n"; my $counter = 1; for my $item (sort{$qrtc_source_count{$b} - $qrtc_source_count{$a}} keys %qrtc_source_count) { if ($opts{r}) { my $name = ""; $name = gethostbyaddr(inet_aton($item), AF_INET) or $name = "[lookup failed]"; print "$qrtc_source_count{$item}\t$item\t$name\n"; } else { print "$qrtc_source_count{$item}\t$item\n"; } last if ++$counter > $TOPx; } } # fe_source_count - format error source count if ($fe_total) { print "\nTop $TOPx format error clients\n"; print "Count\tSource\n"; my $counter = 1; for my $item (sort{$fe_source_count{$b} - $fe_source_count{$a}} keys %fe_source_count) { if ($opts{r}) { my $name = ""; $name = gethostbyaddr(inet_aton($item), AF_INET) or $name = "[lookup failed]"; print "$fe_source_count{$item}\t$item\t$name\n"; } else { print "$fe_source_count{$item}\t$item\n"; } last if ++$counter > $TOPx; } } # sn_zone_count - send notify zone count if ($sn_total) { print "\nTop $TOPx zones sent notifies\n"; print "Count\tZone\n"; my $counter = 1; for my $item (sort{$sn_zone_count{$b} - $sn_zone_count{$a}} keys %sn_zone_count) { print "$sn_zone_count{$item}\t$item\n"; last if ++$counter > $TOPx; } } # sn_serial_count - send notify serial count if ($sn_total) { print "\nTop $TOPx serials in notifies sent\n"; print "Count\tSerial\n"; my $counter = 1; for my $item (sort{$sn_serial_count{$b} - $sn_serial_count{$a}} keys %sn_serial_count) { print "$sn_serial_count{$item}\t$item\n"; last if ++$counter > $TOPx; } } # snf_zone_count - send notify failure zone count if ($snf_total) { print "\nTop $TOPx notify failure zones\n"; print "Count\tZone\n"; my $counter = 1; for my $item (sort{$snf_zone_count{$b} - $snf_zone_count{$a}} keys %snf_zone_count) { print "$snf_zone_count{$item}\t$item\n"; last if ++$counter > $TOPx; } } # snf_dst_count - send notify failure destination count if ($snf_total) { print "\nTop $TOPx notify failure destinations\n"; print "Count\tDestination\n"; my $counter = 1; for my $item (sort{$snf_dst_count{$b} - $snf_dst_count{$a}} keys %snf_dst_count) { print "$snf_dst_count{$item}\t$item\n"; last if ++$counter > $TOPx; } } # snf_desc_count - send notify failure description count if ($snf_total) { print "\nTop $TOPx notify failure reasons\n"; print "Count\tReason\n"; my $counter = 1; for my $item (sort{$snf_desc_count{$b} - $snf_desc_count{$a}} keys %snf_desc_count) { print "$snf_desc_count{$item}\t$item\n"; last if ++$counter > $TOPx; } } # rnna_zone_count - receive notify not authoritative zone count if ($rnna_total) { print "\nTop $TOPx receive notify not authoritative errors\n"; print "Count\tZone\n"; my $counter = 1; for my $item (sort{$rnna_zone_count{$b} - $rnna_zone_count{$a}} keys %rnna_zone_count) { print "$rnna_zone_count{$item}\t$item\n"; last if ++$counter > $TOPx; } } # esr_dst_count - error sending response destination count if ($esr_total) { print "\nTop $TOPx error sending responses\n"; print "Count\tDestination\n"; my $counter = 1; for my $item (sort{$esr_dst_count{$b} - $esr_dst_count{$a}} keys %esr_dst_count) { if ($opts{r}) { my $name = ""; $name = gethostbyaddr(inet_aton($item), AF_INET) or $name = "[lookup failed]"; print "$esr_dst_count{$item}\t$item\t$name\n"; } else { print "$esr_dst_count{$item}\t$item\n"; } last if ++$counter > $TOPx; } } # esr_desc_count - error sending response description if ($esr_total) { print "\nTop $TOPx error sending response reasons\n"; print "Count\tReason\n"; my $counter = 1; for my $item (sort{$esr_desc_count{$b} - $esr_desc_count{$a}} keys %esr_desc_count) { print "$esr_desc_count{$item}\t$item\n"; last if ++$counter > $TOPx; } } # iu_zone_count - insecure update zone count if ($iu_total) { print "\nTop $TOPx insecure update zones\n"; print "Count\tZone\n"; my $counter = 1; for my $item (sort{$iu_zone_count{$b} - $iu_zone_count{$a}} keys %iu_zone_count) { print "$iu_zone_count{$item}\t$item\n"; last if ++$counter > $TOPx; } } # category_count - total categories in log message detail if (%category_count) { print "\nTop $TOPx categories of log messages\n"; print "Count\tCategory\n"; my $counter = 1; for my $item (sort{$category_count{$b} - $category_count{$a}} keys %category_count) { print "$category_count{$item}\t$item\n"; last if ++$counter > $TOPx; } } # severity_count - total categories in log message detail if (%severity_count) { print "\nTop $TOPx severities of log messages\n"; print "Count\tSeverity\n"; my $counter = 1; for my $item (sort{$severity_count{$b} - $severity_count{$a}} keys %severity_count) { print "$severity_count{$item}\t$item\n"; last if ++$counter > $TOPx; } } ## END $TOPx reports ### # logs_per_hour if (%logs_per_hour && $log_total) { print "\nHourly log summary\n"; print "Hour\tLogs \(count\/percent\)\n"; my $counter = 0; for ($counter = 0; $counter < 24; $counter++) { print "$counter\t"; # if no logs this hour, print (0/0.00%) and loop to next if(!$logs_per_hour{$counter}) { print "\(0\/0.00\%\)\n"; next; } # bargraph limited to 50 chars # helps ensure output fits on a single lin w/o wrap # my $bargraph = 0; while ($bargraph < 50) { sub round { my($number) = shift; return int($number + .5 * ($number <=> 0)); } # stop bargraph printing if % of hourly logs < 1% # last if ($logs_per_hour{$counter} / $log_total) * 100 < 1 || ++$bargraph > # percentage of logs = 100% / 2 # round($logs_per_hour{$counter} / $log_total * 50); print "#"; # grow bargraph by one mark } printf "\(%d\/%.2f%%\)\n", $logs_per_hour{$counter}, ($logs_per_hour{$counter} / $log_total) * 100; } } if ($opts{d}) { my $current_dir = getcwd; my $DEBUG_end_time = localtime; print "\n[DEBUG] Script (approximate) start time: $DEBUG_start_time\n"; print "[DEBUG] Script (approximate) stop time: $DEBUG_end_time\n"; print "[DEBUG] Total log messages: $log_total\n"; print "[DEBUG] Resolution: "; if ($opts{r}) { print "ENABLED\n"; } else { print "DISABLED\n"; } print "[DEBUG] Privacy: "; if ($opts{p}) { print "ENABLED\n"; } else { print "DISABLED\n"; } print "[DEBUG] Rows per report: $TOPx\n"; print "[DEBUG] Working directory: $current_dir\n"; print "[DEBUG] Command line: $0"; if (@arguments) { print " @arguments\n";} else { print "\n"; } } ### EOF