##########################################################################
# logwatch script for sshdfilter
# built for logwatch v6.1.1
#
########################################################
# This was written and is maintained by Ian Tomkinson @
#    sshdfilter@gmail.com
#
########################################################
#
# change log 
#
# version 1.3.3
#
# added more lines to ignore - 
#    "Flushing SSHD chain"
#    "sshd received signal \d+, closing sshdfilter"
#    "sshd sent signal \d+, closing sshdfilter"
#    "Cancelled guesswork based block of ([\d\.:a-f]+)"
# added more lines to look for, (but at the moment then ignore)
#    "NOID ip=([\d\.:a-f]+)"
#    "INVALID: user=wobbly, ip=138.253.184.144"
#    "QUIT: signal=\d+"

#
# version 1.3.2
#
# added check for sshdfilter startup with version number
#
# version 1.3.1
#
# added 'Cancelled instant block of' to ignore list - need to move to not-ignored
#
# version 1.3
#
# upgraded for sshdfilter v1.3 - harmonised versions
# added debug msgs from sshdfilter v1.3
# fixed bugs with displaying startup/shutdowns
#
# 1.2 XXX
# 
# version 1.1
#
# added lookups with $secure_ip_lookup check inherited from secure.conf
# add chain as log to ignore
#
# version 1.0
#
# first release, no look-ups
#
#
# todo
#
# test check of debug msgs

use Logwatch ':all';

$Debug = ValueOrDefault($ENV{'LOGWATCH_DEBUG'}, 0);
$Detail = ValueOrDefault($ENV{'LOGWATCH_DETAIL_LEVEL'}, 0);

# Avoid "Use of uninitialized value" warning messages.
sub ValueOrDefault {
	my ($value, $default) = @_;
	return ($value ? $value : $default);
}

sub LookupIP {
   if ($secure_ip_lookup = 1 ) {
      my ($name, $a1, $a2,$a3,$a4,$PackedAddr,$Addr);
      $Addr = $_[0];
      # Trim off beginning if it is a IPv6 address
      $Addr =~ s/^::ffff://;
      return ($Addr) if ($Addr =~ /:/);
      ($a1,$a2,$a3,$a4) = split /\./,$Addr;
      $PackedAddr = pack('C4',$a1,$a2,$a3,$a4);
      if ($name = gethostbyaddr ($PackedAddr,2)) {
         return ($name . " (" . $Addr . ")");
      } else {
         return ($Addr);
      }
   } else {
	  return ($Addr); 
   }
}

my $sftpRequests = 0;

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

while (defined($ThisLine = <STDIN>)) {
   if ( $Debug >= 5 ) {
      print STDERR "DEBUG($DebugCounter): $ThisLine";
      $DebugCounter++;
   }
   chomp($ThisLine);
   if 
   
      #
      # Ignore these
      #
      (
      ($ThisLine =~ /^iptables is missing SSHD redirect/) or
      ($ThisLine =~ /^iptables is missing SSHD chain/) or
      ($ThisLine =~ /repurgetime=/) or
      ($ThisLine =~ /maxblocktime=/) or
      ($ThisLine =~ /maxchances=/) or
      ($ThisLine =~ /interface=/) or
      ($ThisLine =~ /sshdpath=/) or
      ($ThisLine =~ /debug=/) or
      ($ThisLine =~ /sshd args=/) or
      ($ThisLine =~ /Flushing SSHD chain/) or
      ($ThisLine =~ /sshd received signal \d+, closing sshdfilter/) or
      ($ThisLine =~ /sshd sent signal \d+, closing sshdfilter/) or
      ($ThisLine =~ /^Cancelled instant block of ([\d\.:a-f]+)/) or
      ($ThisLine =~ /^Cancelled guesswork based block of ([\d\.:a-f]+)/) or
      ($ThisLine =~ /^sshd: /) # anything starting with sshd: - old version of sshdfilter

      ) {
	  # do nothing
   }
      #
      # look at these
      #
      # Illegal user name, instant block - "Illegal user name, instant block of 81.97.8.81"
      #
   elsif ($ThisLine =~ /^Illegal user name, instant block of ([\d\.:a-f]+)/) {
      if ($Debug >= 5) {
         print STDERR "DEBUG: Found instant block of $1\n";
      }
      $instant{$1}++;
      
      #
      # Too many tries, block - "Too many password guesses, blocking 81.178.219.40"
      #
   } elsif ($ThisLine =~ /^Too many password guesses, blocking ([\d\.:a-f]+)/) {
      if ( $Debug >= 5 ) {
         print STDERR "DEBUG: Found -too many attempts block-\n";
      }
      $toomany{$1}++;
      #
      # no ssh id string, instant block - "No ssh id string from client, instant block of 130.237.13.73"
      #
      } elsif ($ThisLine =~ /^No ssh id string from client, instant block of ([\d\.:a-f]+)/) {
      if ( $Debug >= 5 ) {
         print STDERR "DEBUG: Found nostring instant block\n";
      }
      $NoString{$1}++;
      #
      # legal user name, 1 of 5 chances - "Chanced 81.178.219.40, tries=0"
      #
   } elsif ($ThisLine =~ /^Chanced ([\d\.:a-f]+), tries=\d+/) {
      if ( $Debug >= 5 ) {
         print STDERR "DEBUG: Found a valid login attempt...\n";
      }
      $valid{$1}++;
      #
      # debug messages
      #
      # NOID: ip=127.0.0.1
      # ACCEPT: user=iant, ip=146.87.153.135 
      # FAILILL: user=admin, ip=80.87.128.99 
      # FAILVAL: user=root, ip=127.0.0.1
      # INVALID: user=root, ip=127.0.0.1
      # QUIT: signal=15
      #
      } elsif ($ThisLine =~ /^NOID: ip=([\d\.:a-f]+)/) {
      if ( $Debug >= 5 ) {
         print STDERR "DEBUG: Found sshdfilt debug no id line\n";
      }
      $ThisLine = "$1 tried from " . LookupIP($2) ;
      $DebugNoId{$ThisLine}++;
      #
      } elsif ($ThisLine =~ /^ACCEPT: user=(\S+), ip=([\d\.:a-f]+)/) {
      if ( $Debug >= 5 ) {
         print STDERR "DEBUG: Found sshdfilt debug accept line\n";
      }
      $ThisLine = "$1 accepted from " . LookupIP($2) ;
      $DebugAccept{$ThisLine}++;
      #
      } elsif ($ThisLine =~ /^FAILILL: user=(\S+), ip=([\d\.:a-f]+)/) {
      if ( $Debug >= 5 ) {
         print STDERR "DEBUG: Found sshdfilt debug illegal user line\n";
      }
      $ThisLine = "$1 tried from " . LookupIP($2) ;
      $DebugIllegal{$ThisLine}++;
      #
      } elsif ($ThisLine =~ /^FAILVAL: user=(\S+), ip=([\d\.:a-f]+)/) {
      if ( $Debug >= 5 ) {
         print STDERR "DEBUG: Found sshdfilt debug valid user failure line\n";
      }
      $ThisLine = "$1 tried from " . LookupIP($2) ;
      $DebugValid{$ThisLine}++;
      } elsif ($ThisLine =~ /^INVALID: user=(\S+), ip=([\d\.:a-f]+)/) {
      if ( $Debug >= 5 ) {
         print STDERR "DEBUG: Found sshdfilt debug invalid line\n";
      }
      $ThisLine = "$1 tried from " . LookupIP($2) ;
      $DebugValid{$ThisLine}++;
      } elsif ($ThisLine =~ /^QUIT: signal=(\d+)/) {
      if ( $Debug >= 5 ) {
         print STDERR "DEBUG: Found sshdfilt debug quitting\n";
      }
      $ThisLine = "$1 tried from " . LookupIP($2) ;
      $DebugValid{$ThisLine}++;
      #      
      #
      # startup - "sshdfilter starting up, running sshd proper"
      #
   } elsif ( ($ThisLine =~ /^sshdfilter ([\d\.:a-f]+) starting up, running sshd proper/) or 
             ($ThisLine =~ /^sshdfilter starting up, running sshd proper/) ) {
      if ( $Debug >= 5 ) {
         print STDERR "DEBUG: Found startup line\n";
      }
      $StartUp{ 0 }++;

      #
      # quit - "sshd quit, closing sshdfilter"
      #
   } elsif ($ThisLine =~ /^sshd quit, closing sshdfilter/) {
      if ( $Debug >= 5 ) {
         print STDERR "DEBUG: Found shutdown line\n";
      }
      $ShutDown{ 0 }++;

   } else {
      #
	  # Report any unmatched entries...
	  #
      push @OtherList, "$ThisLine\n";
      
   }
}

###########################################################

if ($ShutDown{ 0 }) {
   if ( $Debug >= 5 ) {
      print STDERR "DEBUG: Printing a shutdown line\n";
   }
   print "\nsshdfilter shut down: " . $ShutDown{ 0 } . " Time(s)\n";
}
if ($StartUp{ 0 }) {
   if ( $Debug >= 5 ) {
      print STDERR "DEBUG: Printing a startup line\n";
   }
   print "\nsshdfilter started: " . $StartUp{ 0 } . " Time(s)\n";
}

if (keys %instant) {
   print "\nInstant block for illegal user by these:\n";
   for (sort keys %instant) {
	  $addr = LookupIP($_) ; 
      print "   $addr: $instant{$_} Time(s)\n";
   }
}

if (keys %toomany) {
   print "\nToo many guesses by these:\n";
   for (sort keys %toomany) {
	  $addr = LookupIP($_) ; 
      print "   $addr: $toomany{$_} Time(s)\n";
   }
}

if (keys %NoString) {
   print "\nNo ssh ID string from these:\n";
   for (sort keys %NoString) {
	   $addr = LookupIP($_) ; 
      print "   $addr: $NoString{$_} Time(s)\n";
   }
}

if (keys %valid) {
   print "\nThese addresses tried valid names at least once:\n";
   for (sort keys %valid) {
	   $addr = LookupIP($_) ; 
      print "   $addr: $valid{$_} Time(s)\n";
   }
}



if ($#OtherList >= 0) {
   print "\n**Unmatched Entries**\n";
   print @OtherList;
}

# if (keys %Users) {
#    print "\nUsers logging in through sshd:\n";
#    foreach $user (sort {$a cmp $b} keys %Users) {
#       print "   $user:\n";
#       my $totalSort = TotalCountOrder(%{$Users{$user}}, \&SortIP);
#       foreach my $ip (sort $totalSort keys %{$Users{$user}}) {
#          my $name = LookupIP($ip);
#          if ($Detail >= 20) {
#             print "      $name:\n";
#             my $sort = CountOrder(%{$Users{$user}{$ip}});
#             foreach my $method (sort $sort keys %{$Users{$user}{$ip}}) {
#                my $val = $Users{$user}{$ip}{$method};
#                my $plural = ($val > 1) ? "s" : "";
#                print "         $method: $val time$plural\n";
#             }
#          } else {
#             my $val = (values %{$Users{$user}{$ip}})[0];
#             my $plural = ($val > 1) ? "s" : "";
#             print "      $name: $val time$plural\n";
#          }
#       }
#    }
# }


exit(0);

# vi: shiftwidth=3 tabstop=3 syntax=perl et
