#!/usr/bin/perl
##########################################################################
# $Id: named,v 1.26 2003/01/13 04:28:06 kirk Exp $
##########################################################################

########################################################
# This was written and is maintained by:
#    Kirk Bauer <kirk@kaybee.org>
#
# Please send all comments, suggestions, bug reports,
#    etc, to kirk@kaybee.org.
########################################################

$Debug = $ENV{'LOGWATCH_DEBUG'};
$DoLookup = $ENV{'named_ip_lookup'};
$Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'};

sub LookupIP {
   my ($name, $a1, $a2,$a3,$a4,$PackedAddr,$Addr);
   $Addr = $_[0];
   ($a1,$a2,$a3,$a4) = split /\./,$Addr;
   $PackedAddr = pack('C4',$a1,$a2,$a3,$a4);
   if ($DoLookup) {
      if ($name = gethostbyaddr ($PackedAddr,2)) {
         return ($name . " (" . $Addr . ")");
      } else {
         return ($Addr);
      }
   }
   else {
      return ($Addr);
   }
}

if ( $Debug >= 5 ) {
    print STDERR "\n\nDEBUG: Inside Named Filter \n\n";
}

while (defined($ThisLine = <STDIN>)) {
   if ( ($ThisLine =~ /RR negative cache entry/) or
         ($ThisLine =~ /^ns_....: .* NS points to CNAME/) or
         ($ThisLine =~ /^accept: connection reset by peer/) or
         ($ThisLine =~ /Connection reset by peer/) or
         ($ThisLine =~ /^There may be a name server already running/) or
         ($ThisLine =~ /^exiting/) or
         ($ThisLine =~ /^NSTATS /) or
         ($ThisLine =~ /Cleaned cache of \d+ RRs/) or
         ($ThisLine =~ /USAGE \d+ \d+ CPU=\d+.*/) or
         ($ThisLine =~ /^XSTATS /) or
         ($ThisLine =~ /^Ready to answer queries/) or
         ($ThisLine =~ /^Forwarding source address is/) or
         ($ThisLine =~ /^bad referral/) or
         ($ThisLine =~ /prerequisite not satisfied/) or
         ($ThisLine =~ /^rcvd NOTIFY/) or
         ($ThisLine =~ /^Sent NOTIFY/) or
         ($ThisLine =~ /^ns_resp: TCP truncated/) or
         ($ThisLine =~ /No possible A RRs/) or
         ($ThisLine =~ /NS points to CNAME/) or
         ($ThisLine =~ /points to a CNAME/) or
         ($ThisLine =~ /^dangling CNAME pointer/) or
         ($ThisLine =~ /^listening on/) or
         ($ThisLine =~ /^unrelated additional info/) or
         ($ThisLine =~ /^Response from unexpected source/) or
         ($ThisLine =~ /^No root nameservers for class IN/) or
         ($ThisLine =~ /^recvfrom: No route to host/) or
         ($ThisLine =~ /Connection refused/) or
         ($ThisLine =~ /lame server resolving/) or
         ($ThisLine =~ /transfer of/) or
         ($ThisLine =~ /^using \d+ CPU/) or
         ($ThisLine =~ /^starting BIND/) or
         ($ThisLine =~ /^loading configuration/) or
         ($ThisLine =~ /^command channel listening/) or
         ($ThisLine =~ /^no IPv6 interfaces found/) or
         ($ThisLine =~ /^running/) or
         ($ThisLine =~ /^exiting/) or
         ($ThisLine =~ /^no longer listening/) or
         ($ThisLine =~ /^shutting down/) or
         ($ThisLine =~ /^the default for the .* option is now/) or
         ($ThisLine =~ /^Malformed response from/) or
         ($ThisLine =~ /client .+#\d+: query:/) or
         # Do we really want to ignore these?
         #($ThisLine =~ /unknown logging category/) or
         #($ThisLine =~ /^couldn't add command channel/) or
         ($ThisLine =~ /^could not open entropy source/) or
         ($ThisLine =~ /\/etc\/rndc.key: file not found/)
         ) {
            # Don't care about these...
   } elsif ( ( $ThisLine =~ /^starting\..*named/) or
         ($ThisLine =~ /^named startup succeeded/) ) {
      $StartNamed++;
   } elsif ( $ThisLine =~ /^reloading nameserver/ ) {
      $ReloadNamed++;
   } elsif ( ( $ThisLine =~ /^named shutting down/ ) or
         ( $ThisLine =~ /^named shutdown succeeded/ ) ) {
      $ShutdownNamed++;
   } elsif ( ($Host, $Zone) = ( $ThisLine =~ /client ([^\#]+)#[^\:]+: zone transfer '(.+)' denied/ ) ) {
      $DeniedZoneTransfers{$Host}{$Zone}++;
   } elsif ( ($Zone) = ( $ThisLine =~ /cache zone \"(.*)\" loaded/ ) ) {
      $ZoneLoaded{"cache $Zone"}++;
   } elsif ( ($Zone) = ( $ThisLine =~ /cache zone \"(.*)\" .* loaded/ ) ) {
      $ZoneLoaded{"cache $Zone"}++;
   } elsif ( ($Zone) = ( $ThisLine =~ /primary zone \"(.+)\" loaded/ ) ) {
      $ZoneLoaded{$Zone}++;
   } elsif ( ($Zone) = ( $ThisLine =~ /master zone \"(.+)\" .* loaded/ ) ) {
      $ZoneLoaded{$Zone}++;
   } elsif ( ($Zone) = ( $ThisLine =~ /secondary zone \"(.+)\" loaded/ ) ) {
      $ZoneLoaded{"secondary $Zone"}++;
   } elsif ( ($Zone) = ( $ThisLine =~ /slave zone \"(.+)\" .* loaded/ ) ) {
      $ZoneLoaded{"secondary $Zone"}++;
   } elsif ( (undef,$Addr,undef,$Server) = ( $ThisLine =~ /ame server (on|resolving) '(.+)' \(in .+\):\s+(\[.+\]\.\d+)?\s*'?(.+)'?:?/ ) ) {
      $LameServer{"$Addr ($Server)"}++;
   } elsif ( ($Zone) = ( $ThisLine =~ /Zone \"(.+)\" was removed/ ) ) {
      $ZoneRemoved{$Zone}++;
   } elsif ( ($Host) = ( $ThisLine =~ /^([^ ]+) has CNAME and other data \(invalid\)/ ) ) {
      push @CNAMEAndOther, $Host;
   } elsif ( ($Way,$Host) = ( $ThisLine =~ /^([^ ]+): sendto\(\[([^ ]+)\].+\): Network is unreachable/ ) ) {
      $FullHost = LookupIP ($Host);
      $NetworkUnreachable{$Way}{$FullHost}++;
   } elsif ( ($Zone,$Message) = ( $ThisLine =~ /^client [^\#]+#[^\:]+: updating zone '([^\:]+)': (.*)$/ ) ) {
      $ZoneUpdates{$Zone}{$Message}++;
   } elsif ( ($Host,$Zone) = ( $ThisLine =~ /approved AXFR from \[(.+)\]\..+ for \"(.+)\"/ ) ) {
      $FullHost = LookupIP ($Host);
      $AXFR{$Zone}{$FullHost}++;
   } elsif ( ($Client) = ( $ThisLine =~ /client (.*)#\d+: query \(cache\) denied/ ) ) {
      $FullClient = LookupIP ($Client);
      $DeniedQuery{$FullClient}++;
   } elsif ( ($Rhost, $Ldom) = ($ThisLine =~ /^client ([\d\.]+)#\d+: update '(.*)' denied/)) {
      $UpdateDenied{"$Rhost ($Ldom)"}++;
   } else {
      # Report any unmatched entries...
      # remove PID from named messages
      $ThisLine =~ s/^(client [.0-9]+)\S+/$1/;
      chomp($ThisLine);
      $OtherList{$ThisLine}++;
   }
}

if ( ( $Detail >= 5 ) and ($StartNamed) ) {
   print "Named started: $StartNamed Time(s)\n";
}

if ( ( $Detail >= 5 ) and ($ReloadNamed) ) {
   print "Named reloaded: $ReloadNamed Time(s)\n";
}

if ( ( $Detail >= 5 ) and ($ShutdownNamed) ) {
   print "Named shutdown: $ShutdownNamed Time(s)\n";
}

if ( ( $Detail >= 5 ) and (keys %ZoneLoaded) ) {
   print "\nLoaded Zones:\n";
   foreach $ThisOne (sort {$a cmp $b} keys %ZoneLoaded) {
      print "   " . $ThisOne . ": " . $ZoneLoaded{$ThisOne} . " Time(s)\n";
   }
}

if ( ( $Detail >= 5 ) and (keys %DeniedZoneTransfers) ) {
   print "\nDenied Zone Transfers:\n";
   foreach my $Host (keys %DeniedZoneTransfers) {
      print "   $Host: ";
      foreach my $Zone (keys %{$DeniedZoneTransfers{$Host}}) {
         print $DeniedZoneTransfers{$Host}{$Zone}. ' ';
      }
      print "\n";
   }
}

if ( ( $Detail >= 5 ) and (keys %ZoneRemoved) ) {
   print "\nRemoved Zones:\n";
   foreach $ThisOne (sort {$a cmp $b} keys %ZoneRemoved) {
      print "   " . $ThisOne . ": " . $ZoneRemoved{$ThisOne} . " Time(s)\n";
   }
}

if ( ( $Detail >= 5 ) and (keys %AXFR) ) {
   print "\nZone Transfers:\n";
   foreach $ThisOne (keys %AXFR) {
      print "   Zone: " . $ThisOne . "\n";
      foreach $Temp (keys %{$AXFR{$ThisOne}}) {
         print "      by " . $Temp . ": " . $AXFR{$ThisOne}{$Temp} . " Time(s)\n";
      }
   }
}

if ( ( $Detail >= 5 ) and (keys %DeniedQuery) ) {
   print "\nQueries (cache) that were denied:\n";
   foreach $ThisOne (keys %DeniedQuery) {
      print "   from " . $ThisOne . ": " . $DeniedQuery{$ThisOne} . " Time(s)\n";
   }
}

if ( ( $Detail >= 10 ) and (@CNAMEAndOther) ) {
   print "\nThese hosts have CNAME and other data (invalid):\n";
   foreach $ThisOne (@CNAMEAndOther) {
      print "   " . $ThisOne . "\n";
   }
}

if ( ( $Detail >= 10 ) and (keys %LameServer) ) {
   print "\nThese addresses had lame server references:\n";
   foreach $ThisOne (keys %LameServer) {
      print "   " . $ThisOne . ": " . $LameServer{$ThisOne} . " Time(s)\n";
   }
}

if ( ( $Detail >= 10 ) and (keys %NetworkUnreachable) ) {
   print "\nNetwork is unreachable for:\n";
   foreach $ThisOne (sort {$a cmp $b} keys %NetworkUnreachable) {
      print "   " . $ThisOne . ":\n";
      foreach $Host (sort {$a cmp $b} keys %{$NetworkUnreachable{$ThisOne}}) {
         print "      " . $Host . ": $NetworkUnreachable{$ThisOne}{$Host} Time(s)\n";
      } 
   }
}

if ( ( $Detail >= 5 ) and (keys %ZoneUpdates) ) {
   print "\nZone Updates:\n";
   foreach $ThisOne (sort {$a cmp $b} keys %ZoneUpdates) {
      print "   " . $ThisOne . ":\n";
      foreach $Message (sort {$a cmp $b} keys %{$ZoneUpdates{$ThisOne}}) {
         print "      " . $Message . ": $ZoneUpdates{$ThisOne}{$Message} Time(s)\n";
      } 
   }
}

if ( keys %UpdateDenied ) {
   print "\nZone update refused:\n";
   foreach $ThisOne (sort {$a cmp $b} keys %UpdateDenied) {
      print "   " . $ThisOne . ": " . $UpdateDenied{$ThisOne} . " Time(s)\n";
   }
}

if (keys %OtherList) {
   print "\n**Unmatched Entries**\n";
   foreach $line (sort {$a cmp $b} keys %OtherList) {
      print "   $line: $OtherList{$line} Time(s)\n";
   }
}

exit(0);

