Ban ssh bruteforce with pf.pl
From wiki.perl.lt
#!/usr/bin/perl
# ban_ssh_bruteforce_with_pf.pl v.1.1
# copyleft algirdas @ perl.lt
#
# tested on freebsd 8.0-* (2010.05.23)
#
# first create /var/db/blacklist for lusers
# and /var/db/whitelist for elite :-)
#
# to enable add pf rules:
#
# table <bruteforce> persist file "/var/db/blacklist"
# block quick from <bruteforce>
#
# and to enable autorun on every event add:
#
# auth.info;authpriv.info | exec /usr/bin/perl /sbin/ban_ssh_bruteforce_with_pf.pl
#
# to /etc/syslog.conf and run /etc/rc.d/syslogd restart
#
# also you can edit $limit for your satisfaction :-)
#
# to display what pf is currently blocking type pfctl -t bruteforce -T show
# to delete something from the table: pfctl -t bruteforce -T del $ip
# to add something to the table: pfctl -t bruteforce -T add $ip
# to temporarily disable pf: pfctl -d
# to reenable pf: pfctl -e
use strict;
use POSIX qw(strftime);
my $limit = 3;
my $assholes;
my $asshole;
my $lusers;
my $today = strftime "%b %e", localtime;
my @old = `pfctl -t bruteforce -T show`;
# scan /var/log/auth.log for ($today) login errors
open (F, "</var/log/auth.log");
while (<F>) {
if (/($today)(.*)(Invalid user.*|Did not receive identification string.*)from ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)/) {
$assholes->{$1}->{$4}->{'n'}++;
}
}
close (F);
# check if error limit for $ip is reached, and check if it $ip is not in the whitelist
foreach $asshole (keys (%{$assholes->{$today}})) {
if ($assholes->{$today}->{$asshole}->{'n'} >= $limit) {
open (F,"</var/db/whitelist") ;
while (<F>) {
if (/$asshole/) {
undef ($asshole);
last;
}
}
close (F);
$lusers .= "$asshole ";
}
}
# remove previous pf rules for bruteforce table
foreach (@old) {
if (/([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)/) {
`/sbin/pfctl -t bruteforce -T del $1`;
}
}
# add $lusers to pf bruteforce table
exec "/sbin/pfctl -t bruteforce -T add $lusers";