#!/usr/bin/perl -w
#
# ssh-black.pl		par Bernard FRIT <bernard@frit.net> le 18 février 2005
#

# v.0.4

use strict;
use Socket;

# nom du programme
my($PROG) = 'ssh-black.pl' ;

# version du programme
my($VER) = '0.4' ;

################## Configuration ############################################################

# path du fichier log a analyser
my($LOG) = '/var/log/messages';

# path du répertoire contenant les Ips en cours d'analyse
my($TMP) = '/root/tmp/Ips' ;

# path du répertoire contenant les Ips blacklistées
my($BLACK) = '/root/tmp/Ips-black' ;

# nombre de tentatives autorisées
my($MAX) = 3 ;

# ajoutez ici vos Ips fixes si vous le souhaitez.
my($LOCALNET) = '^(127\.0\.0\.1|192\.168\.0)';

# path d'Iptables
my($IPTABLES) = '/sbin/iptables';

# chaines de caractères à rechercher dans les logs.
my($REASONS) = '(Illegal user|illegal user|Failed password|failed password)';

################## Fin de Config ############################################################

my($IP) = '[0-9]{1,3}(\.[0-9]{1,3}){3}';

my($HOST) = `uname -n` ;
chop($HOST);
$HOST =~ /^(.+)(\..+){0,3}/ ;
$HOST = $1 ;

my($INFO) = " $HOST $PROG v.$VER($$): ";

print scalar localtime, $INFO, "Initializing...\n";

taillog();

sub taillog {
   my($offset, $name, $line, $ip, $reason);
   $offset = (-s $LOG); # Don't start at begining, go to end
#    $offset=0;
   while (1==1) {
       sleep(1);
       $| = 1;
       if ((-s $LOG) < $offset) {
           print scalar localtime,$INFO,"Log shrunk, resetting..\n";
           $offset = 0;
       }
       open(TAIL, $LOG) || print STDERR "Error opening $LOG: $!\n";

        if (seek(TAIL, $offset, 0)) {
           # found offset, log not rotated
       } else {
           # log reset, follow
           $offset=0;
           seek(TAIL, $offset, 0);
       }
       while ($line = <TAIL>) {
           chop($line);
           if (($REASONS) && ($line =~ m/$REASONS/)) {
               $reason = $1;
               if ($line =~ m/($IP)/) {
                   $ip = $1;
                   if (evalIp($ip)) {
                       print scalar localtime, $INFO, "$ip blacklisted (ssh: $reason) \n";
                   } 			
 		} elsif ($line =~ m/from ([a-zA-Z0-9\.\-]+)/) {
		    $ip = $1; 
		    if ($ip) {
                        if (evalIp($ip)) {
                             print scalar localtime, $INFO, "$ip blacklisted (ssh: $reason) \n";
			}			     
		    } else {
			print scalar localtime, $INFO, "Failed to find IP: $line\n";
		    }
		} else {
		    print scalar localtime, $INFO, "Should have blocked?: $line\n";
		}
		next;
           }
       }
       $offset=tell(TAIL);
       close(TAIL);
   }
}

sub evalIp {
   my($ip) = @_;
   my($cnt) = 1 ;

   if ($ip =~ m/$LOCALNET/) {
       return;
   }
   if (-e("$TMP/$ip")) {
   	$cnt = `cat $TMP/$ip` ;
   	chop($cnt) ;
   	if (($cnt++>$MAX) and (!-e("$BLACK/$ip"))){
	    blockIp($ip) ;	   		
   	    `mv $TMP/$ip $BLACK/$ip` ;
            return 1 ;
        }            
    }
    `echo $cnt > $TMP/$ip` ;
} 					

sub blockIp {
   my($ip) = @_;

   my(@args) = ($IPTABLES,
                '-I',
                'INPUT', '--source',
                $ip,
                '-j', 'REJECT', '--reject-with', 'icmp-host-prohibited');

#   print "system(@args)\n";

    system(@args) ;

}
