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

# Code inspire par :
# -----------------
# based on mailmgr (c) 2003, Julian Haight, All Rights reserved under GPL license:
# http://www.gnu.org/licenses/gpl.txt
# Modified on 02AUG04 as provided under GNU GPL licensing
# no rights reserved under this modification
#
#  See http://www.pettingers.org/code/SSHBlack.html for details on this
#
# Ajout du parametre nombre de tentatives et de la liberation conditionnelle des Ips
# blacklistées en fonction d'un délai paramétrable.
#
# Description :
# ------------
# Ce script analye en temps reel le fichier /var/log/messages et detecte les
# tentatives d'intrusion via ssh. Au bout de 3 (configurable) tentatives, l'adresse
# IP est blacklistée. Elle sera retablie par le script un-black.pl lancé par un
# cron toutes les heures (par exemple). 
#
# Installation :
# -------------
# Répertoire d'installation: /root/bin.
# chown root:root ssh-black.pl
# chmod 700 ssh-black.pl
# Il est lancé depuis /etc/rc.d/rc.local par un script /root/bin/ssh-blacklist.sh.
# 
#    #! /bin/bash
#    /root/bin/ssh-black.pl >>/var/log/blacklisting 2>&1 &
#
# ce qui permet d'avoir un log des actions.
# Il faut créer les répertoires :
# /root/tmp/Ips
# /root/tmp/Ips/black
#

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

use strict;
use Socket;

# path du fichier log a analyser (/var/log/messages ou /var/log/secure)
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 ;

# regex for whitelisted IPs - never blacklist these addresses
# ajoutez ici vos Ips fixes si vous le souhaitez.
my($LOCALNET) = '^(?:127\.0\.0\.1|192\.168\.0)';

# your kernel-firewall tweaker, see "iptables" func to redefine params used
my($IPTABLES) = '/sbin/iptables';

# Regex of reasons to get firewalled
# This VARIES BASED ON THE VERSION OF SOFTWARE YOU ARE RUNNING
# Look at your logs and adjust as necessary.

my($REASONS) = '(Illegal user|illegal user)';

my($OCT) = '(?:25[012345]|2[0-4]\d|1?\d\d?)';
my($IP) = $OCT . '\.' . $OCT . '\.' . $OCT . '\.' . $OCT;
my($HOST) = `uname -n` ;
chop($HOST);

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 "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, " $HOST($$): $ip blacklisted ($reason) \n";
                   } 			
 		} elsif ($line =~ m/from ([a-zA-Z0-9\.\-]+)/) {
		    $ip = $1; 
		    $ip = getip($ip);
		    if ($ip) {
                        if (evalIp($ip)) {
                             print scalar localtime, " $HOST($$): $ip blacklisted ($reason) \n";
			}			     
		    } else {
			print "Failed to find IP: $line\n";
		    }
		} else {
		    print "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) ;

}
