Skip to content

Instantly share code, notes, and snippets.

@ckhung
Last active December 3, 2019 02:49
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ckhung/bc7bcc519c1da8ef0d44922062e6f6e3 to your computer and use it in GitHub Desktop.
Save ckhung/bc7bcc519c1da8ef0d44922062e6f6e3 to your computer and use it in GitHub Desktop.
summarize sites/subnets repeatedly banned by fail2ban
#!/usr/bin/perl -w
# 詳見: 「fail2ban: 新手老手 root 網管都要練的金鐘罩」
# http://newtoypia.blogspot.tw/2016/04/fail2ban.html
use DateTime;
use Getopt::Std;
my (%opts) = (
d => 7, # number of days to look back
g => 3, # threshhold number of offending ips in a subnet
i => 8, # threshhold number of repeated bans of an offending ip
f => "hosts.deny", # output format. "hosts.deny" or "apache2"
l => "/var/log/fail2ban.log", # fail2ban log file name
);
getopts('d:g:i:f:l:', \%opts);
my $today = DateTime->today(time_zone=>'local');
my $start_date = $today->clone()->subtract(days=>$opts{d});
$today = $today->ymd('');
$start_date = $start_date->ymd('');
my $offender;
sub parse_line {
my ($line) = @_;
my ($y, $m, $d, $subnet, $ip) = $line =~ /(\d+)-(\d+)-(\d+)\s.*\sBan\s(\S+)\.(\d+)/;
if ($y and "$y$m$d" ge $start_date) {
++$offender->{$subnet}{$ip};
}
}
open F, "$opts{l}.1" or die "cannot open $opts{l}.1";
while (<F>) { parse_line($_); }
close F;
open F, "$opts{l}" or die "cannot open $opts{l}";
while (<F>) { parse_line($_); }
close F;
my ($deny_list, $subnet, $ip) = ("");
foreach $subnet (keys %$offender) {
my (@ips) = keys %{$offender->{$subnet}};
my ($nips) = $#ips + 1;
if ($nips >= $opts{g}) {
my ($k);
foreach $ip (@ips) { $k += $offender->{$subnet}{$ip}; }
$deny_list .= " $subnet.[$nips]($k)";
} else {
foreach $ip (@ips) {
$deny_list .= " $subnet.$ip($offender->{$subnet}{$ip})"
if $offender->{$subnet}{$ip} > $opts{i};
}
}
}
print "# repeated-fail2ban: [$start_date-$today g=$opts{g} i=$opts{i}] $deny_list\n";
$deny_list =~ s/\(.*?\)//g;
$deny_list =~ s/\[.*?\]//g;
if ($deny_list =~ /\S/) {
if ($opts{f} eq "hosts.deny") {
print "ALL:$deny_list\n";
} elsif ($opts{f} eq "apache2") {
$deny_list .= " ";
$deny_list =~ s#\. #.0/24 #g;
$deny_list =~ s/ $//;
print "Deny from$deny_list\n";
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment