#!/usr/local/bin/perl5 # Version 0.1 # ------------------------------------------------------------------------ # README ----------------------------------------------------------------- # ------------------------------------------------------------------------ # - This script requires Net::DNS. If you don't have it, get it from your # next CPAN archive # - PLEASE look at the config section and adjust to your needs. # - This script takes as input a logfile from bind-8.x that contains # lines from the security log channel. If you have other lines in # that file, it will probably choke because of lots off ERRLINE # output (all the lines that it doesn't know how to handle are # output as "ERRLINE: $line" # - if you have questions/improvements feel free to contact me (address # below). Please include the above Version number for reference. # # Have fun! # \Maex # ------------------------------------------------------------------------ # ------------------------------------------------------------------------ # CONFIG ----------------------------------------------------------------- # ------------------------------------------------------------------------ $MASTER = 'NNN.NNN.NNN.NNN'; # this is the DNS Server to use # for queries $USE_BARS = 0; # draw lines around the tables # don't list SUCCESSFUL AXFRs from these IP addresses in detail # useful for e.g. RIPE hostcount %COLLAPSE = ( '129.70.132.100' => 1, # DE hostcount '129.70.132.4' => 1, # DE hostcount (alternative host) ); # ------------------------------------------------------------------------ # ------------------------------------------------------------------------ use Net::DNS; # # process the input file # while (<>) { chomp; $reason = ''; $UPDATE=' '; ($approved, $ip, $domain, $reason) = ( m/.*: ([^ ]*) AXFR .*\[([^\]]*)\].*"([^"]*)"(.*)/ ); $reason =~ s/^[ ]*//; $reason = '(not m/s)' if ('(not master/slave)' eq $reason); if ('' eq $domain) { ($approved, $ip, $domain) = ( m/.*: ([^ ]*) update from \[([^\]]*)\].* for (.*)/ ); $UPDATE='U'; } # # don't know how to handle this type of messages # print the message and skip to next line # if ('' eq $domain) { print "ERRLINE: $_\n"; next; } $NUM{$ip}++; $app = 'approved' eq $approved ? ' ' : '* '; # # hide successful AXFRs from "collapse me" IPs # unless ((1 == $COLLAPSE{$ip}) and ('approved' eq $approved)) { if (1 == $USE_BARS) { $msg = sprintf("%-51s |%-11s |", "| $UPDATE$app| $domain", $reason); } else { $msg = sprintf("%-51s %-11s ", " $UPDATE$app $domain", $reason); } $XFERS{$ip}{$msg}++; } } # # output # foreach (sort keys %XFERS) { # # try to get the hostname # $res = new Net::DNS::Resolver; $res->nameservers($MASTER); $query = $res->query($_, 'PTR'); if ($query) { foreach $rr ($query->answer) { # $rr->print; next unless $rr->type eq "PTR"; # print '***', $rr->nsdname, "\n"; $ipdomain = lc $rr->ptrdname; } } else { $ipdomain = ''; } # # output IP address, number of AXFRs, hostname and whether it's collapsed # $num = $NUM{$_}; $collapse = ( 1 == $COLLAPSE{$_} ) ? ' (COLL)' : ''; if (1 == $USE_BARS) { # printf "%73s\n", '+------+'; printf "%73s\n", '| |'; printf "%-19s %-45s| %4d |\n", "[$_]", "$ipdomain$collapse", $num; } else { printf "%-19s %-45s %4d \n", "[$_]", "$ipdomain$collapse", $num; } # # output the zones tranferred (and number of transfers for that zone) # if (1 == $USE_BARS) { printf "+----+%-46s+------------+------+------+\n", '-' x 46; } foreach $line (sort keys %{$XFERS{$_}}) { if (1 == $USE_BARS) { printf "%-66s %4d | %4d |\n", $line, $num, $XFERS{$_}{$line}; } else { printf "%-66s %4d %4d \n", $line, $num, $XFERS{$_}{$line}; } } if (1 == $USE_BARS) { printf "+----+%-46s+------------+------+------+\n", '-' x 46; } else { print "\n"; } undef $res; } exit 0;