#!/usr/bin/perl # Perl script for blocking ip addresses after several # failed ssh/ftp login attempts within a specified time. # # Some code is from http://anp.ath.cx/sshit/sshit.pl # Thanks Andreas Pettersson from some logics # # This script uses IO::Select, so it does not fork. # # If you has any question, please mail to jnlin _AT_ csie.nctu.edu.tw # use IO::Select; $log = "/var/log/auth.log"; # The path of log file $maxtry = 5; # Number of failed login attempts within time before we block $max_period = 600; # Time in seconds in which all failed login attempts must occur $ban_period = 600; # Time in seconds to block ip in firewall $PFCTL_CMD = "/sbin/pfctl -q"; $PF_TABLE = "badhosts"; open(INPUT, "tail -F $log |"); %list = (); $s = new IO::Select(); $s->add(\*INPUT); while(1) { ($ready) = IO::Select->select($s, undef, undef, 1); foreach $fh (@$ready) { $str = <$fh>; if($str =~ /Failed/ || $str =~ /Illegal/) { if($str =~ /(\d+\.\d+\.\d+\.\d+)/) { $ip = $1; if ($list{$ip}{name}) { $list{$ip}{n}++; if (($list{$ip}{n} >= $maxtry) && (time() - $list{$ip}{time} <= $max_period)) { # Let's block it $list{$ip}{time} = time(); system("$PFCTL_CMD -t $PF_TABLE -Tadd $ip > /dev/null"); } } else { $list{$ip}{name} = $ip; # ip address to watch $list{$ip}{n} = 1; # first occurance $list{$ip}{time} = time(); # time of first occurance } } } } foreach $ip (keys %list) { if ($list{$ip}{n} < $maxtry) { # delete all ip's that hasn't reached $maxtry within time if (time() - $list{$ip}{time} > $max_period) { delete($list{$ip}); } } else { # remove block for ip's that has reached block time if (time() - $list{$ip}{time} > $ban_period) { system("$PFCTL_CMD -t $PF_TABLE -Tdelete $ip > /dev/null"); delete($list{$ip}); } } } }