Below (and atached) is a script I wrote do exactly what you are talking about.
It's commented, so edit to your taste. I have been using to for about 4 months.
-Erik-
#!/usr/bin/perl
# created by hornetmadness at gmail.com 03/05
my $time=localtime();
use strict;
use Time::localtime;
use Mail::Send;
my $hostname="domain.orIP.com";
#LOG to search on
my $logfile="/var/log/auth.log";
#Where to store the cache file. This is removed and updated daily
my $cache="/root/.sshprotect.cache";
#Email setup;
my $to="to\@email.com";
my $from="from\@email.com";
my $cc="";
my $subject="Excesssive login attempts";
my $debug=0;
my $host;
my @logs;
my @whtlst;
my %track;
my @blacklist;
my $block=1;
my @abuse;
my @cache;
my $currentcache;
my @runoutput;
my $version="1.2.1beta";
print "Version: $version\n" if $debug;
if (
/Failed password for illegal user (.*) from (.*) port/
|| /Failed password for (.*) from (.*) port/
|| /Illegal user (.*) from (.*)/
|| /Did not (receive) identification string from (.*)/
){
my $account=$1;
my $host=$2;
ckwhtlst($account, $host);
if ($block == 0 ) { next; }
ckcache($host);
if ($block == 0 ) { next; }
ckblklst($host);
if ($block == 0 ) { next; }
$block=1;
if ($track{$host}) {
$track{$host}=$track{$host}+1;
print "$host is now $track{$host} user=$account\n" if $debug;
} else { $track{$host}=1; }
}
}
close LOG;
#Sends emails
if ($action !~/email/) {
exit;
} elsif (@abuse) {
send_email(@abuse);
}
if ($action !~/abuse/) {
exit;
} elsif (@abuse) {
abuse_email(@abuse);
}
sub ckwhtlst {
(my $account, my $host)=@_;
foreach (@whtlst) {
if (!/$account|$host/) {
$block=1;
return;
} else {
print "$host or $account is on the while list.\n" if $debug;
$block=0;
return;
}
}
}
sub ckblklst {
my $host=@_[0];
foreach (@blacklist) {
if (/$host/) {
print "$host $_ is already blacklisted\n" if $debug;
$block=0;
return;
} else { $block=1; } #print "$host is NOT blacklisted\n" if $debug; }
}
}
sub ckcache {
my $host=@_[0];
if (!@cache) { $block=1; return;}
foreach (@cache) {
if (/$host/) {
$block=0;
print "$host is already cached\n" if $debug;
return;
} else { $block=1; } #print "$host is not found in cache\n" if $debug; }
}
}
sub update {
open (OUT, ">> $blacklist") || die "$blacklist $!\n";
print OUT "@_[0]\n";
system ("pfctl -t $tablename -f /etc/pf.conf");
close OUT;
}
sub send_email {
my $subject="$subject $today";
my $msg = new Mail::Send;
my $host;
$msg->subject($subject);
$msg->to($to);
$msg->cc($cc) if $cc;
$msg->add("From", "$from");
$msg->add("Return-Path", "$from");
$msg->add("Reply-To", "$from");
my $fh=$msg->open;
foreach (@_) {
$host=$_;
if (!$track{$_}) {return;}
print $fh "\nThe host $_ has $track{$_} attempted logins.\n";
}
print $fh "\nThe threshold is set to $attempts attempts\n";
print $fh "\nActions taken: $action\n\n";
if (($action =~/run/ && $command) && !$useip) { print $fh "Ran:
$command\n\n Output:\n at runoutput"; }
if (($action =~/run/ && $command) && $useip) { print $fh "Ran:
$command $host,\n\n Output:\n at runoutput"; }
sub abuse_email {
$subject="[ABUSE] $subject $today";
my $msg;
my $fh;
my $acct;
my $domain;
close WRITECACHE;
close LOG;
use Data::Dumper;
print Dumper %track if $debug;
• Previous message: autoblocking many ssh failed logins from the same IP....
• Next message: autoblocking many ssh failed logins from the same IP....
• Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]