2017-02-22 21:42:53 -06:00
|
|
|
#!/usr/bin/env perl
|
2017-12-30 05:39:36 -06:00
|
|
|
# Author: Zane C. Bowers-Hadley <vvelox@vvelox.net>
|
2017-02-16 10:50:46 -06:00
|
|
|
|
2017-12-30 05:39:36 -06:00
|
|
|
# https://docs.librenms.org/#Extensions/Applications/#fail2ban
|
|
|
|
# See the above for additional information not documented in the POD below.
|
2017-02-19 23:41:51 -06:00
|
|
|
|
2017-12-30 05:39:36 -06:00
|
|
|
=head1 DESCRIPTION
|
2017-02-19 23:41:51 -06:00
|
|
|
|
2017-12-30 05:39:36 -06:00
|
|
|
A basic SNMP extend for polling fail2ban for LibreNMS.
|
2017-02-23 08:45:04 -06:00
|
|
|
|
2017-12-30 05:39:36 -06:00
|
|
|
=head1 SWITCHES
|
|
|
|
|
|
|
|
=head2 -c
|
|
|
|
|
|
|
|
Prints the cache file.
|
|
|
|
|
|
|
|
=head2 -C <file>
|
|
|
|
|
|
|
|
Uses the specified file as the cache file.
|
|
|
|
|
|
|
|
If not specified, /var/cache/fail2ban is used.
|
|
|
|
|
|
|
|
=head2 -f <fail2ban-client>
|
|
|
|
|
|
|
|
This is the path to the fail2ban-client if needed.
|
|
|
|
|
|
|
|
If not specified, "/usr/bin/env fail2ban-client" is used.
|
|
|
|
|
2018-05-28 07:22:09 -05:00
|
|
|
=head2 -p
|
|
|
|
|
|
|
|
Pretty prints the JSON.
|
|
|
|
|
2017-12-30 05:39:36 -06:00
|
|
|
=head2 -u
|
|
|
|
|
|
|
|
Updates the cache.
|
|
|
|
|
|
|
|
=head2 -U
|
|
|
|
|
|
|
|
When used with -c, allows attempted cache updating if the file is older
|
|
|
|
than 360 seconds or does not exist.
|
|
|
|
|
|
|
|
=head1 CRON EXAMPLE
|
|
|
|
|
|
|
|
*/3 * * * * /etc/snmp/fail2ban -u
|
|
|
|
|
|
|
|
or
|
|
|
|
|
|
|
|
*/3 * * * * /etc/snmp/fail2ban -u -C /foo/bar/cache
|
|
|
|
|
|
|
|
3 minutes is used as LibreNMS runs every 5 minutes, this helps ensure it
|
|
|
|
is most likely up to date in between runs.
|
|
|
|
|
|
|
|
|
|
|
|
=head1 SNMPD SETUP EXAMPLES
|
|
|
|
|
|
|
|
extend fail2ban /etc/snmp/fail2ban
|
2017-02-20 03:49:50 -06:00
|
|
|
|
2017-12-30 05:39:36 -06:00
|
|
|
The above will set it up for basic uncached usage.
|
|
|
|
|
|
|
|
This is likely fine for most configurations.
|
|
|
|
|
|
|
|
extend fail2ban /etc/snmp/fail2ban -c
|
|
|
|
|
|
|
|
Will use the cache.
|
|
|
|
|
|
|
|
extend fail2ban /etc/snmp/fail2ban -c -U
|
|
|
|
|
|
|
|
Will use the cache and update if needed.
|
|
|
|
|
|
|
|
extend fail2ban /etc/snmp/fail2ban -f /foo/bin/fail2ban-client
|
|
|
|
|
|
|
|
Run it with fail2ban being installed under /foo the the path to
|
|
|
|
fail2ban-cleint being /foo/bin/fail2ban-client.
|
|
|
|
|
|
|
|
=cut
|
2017-02-20 03:49:50 -06:00
|
|
|
|
2017-02-19 23:41:51 -06:00
|
|
|
use strict;
|
|
|
|
use warnings;
|
2017-02-20 03:49:50 -06:00
|
|
|
use Getopt::Std;
|
2018-05-28 07:22:09 -05:00
|
|
|
use JSON;
|
2017-02-20 03:49:50 -06:00
|
|
|
|
2017-12-30 05:39:36 -06:00
|
|
|
#fail2ban-client path
|
|
|
|
my $f2bc="/usr/bin/env fail2ban-client";
|
|
|
|
|
|
|
|
#the path to the cache
|
|
|
|
my $cache='/var/cache/fail2ban';
|
|
|
|
|
2017-02-20 03:49:50 -06:00
|
|
|
$Getopt::Std::STANDARD_HELP_VERSION = 1;
|
|
|
|
sub main::VERSION_MESSAGE {
|
2017-12-30 05:39:36 -06:00
|
|
|
print "fail2ban-client SNMP extend 1.0.0\n";
|
2017-02-20 03:49:50 -06:00
|
|
|
};
|
2017-02-19 23:41:51 -06:00
|
|
|
|
2017-02-20 03:49:50 -06:00
|
|
|
sub main::HELP_MESSAGE {
|
|
|
|
print "\n".
|
2017-12-30 05:39:36 -06:00
|
|
|
"-c Print from the cache.\n".
|
|
|
|
"-C <file> Use this as the cache file.\n".
|
|
|
|
"-f <fail2ban-client> The fail2ban-client path if needed.".
|
2018-05-28 07:22:09 -05:00
|
|
|
"-p Pretty prints the JSON.\n".
|
2017-12-30 05:39:36 -06:00
|
|
|
"-u Update the cache, '".$cache."'\n".
|
|
|
|
"-U When used with -c, allow update of the cache file if it does not exist or is older than 360 seconds.".
|
|
|
|
"\n".
|
|
|
|
"Unless -c or -u is given, it just talks to fail2ban-client and prints the results.\n";
|
2017-02-18 00:09:12 -06:00
|
|
|
}
|
|
|
|
|
2017-12-30 05:39:36 -06:00
|
|
|
#generats stats
|
|
|
|
sub stats{
|
2018-05-28 07:22:09 -05:00
|
|
|
my %toReturn;
|
2018-06-25 16:10:00 +02:00
|
|
|
$toReturn{data}={};
|
|
|
|
$toReturn{data}{total}=0; # total number in jails
|
|
|
|
$toReturn{data}{jails}={}; # each jail
|
2018-05-28 07:22:09 -05:00
|
|
|
$toReturn{error}=0; # error code, 0 if good
|
|
|
|
$toReturn{errorString}=''; # detailed description of any errors
|
|
|
|
$toReturn{version}='1'; # format version of the returned data
|
|
|
|
|
2017-02-20 03:49:50 -06:00
|
|
|
#gets a list of jails
|
|
|
|
my $jailsOutput=`$f2bc status`;
|
2018-05-28 07:22:09 -05:00
|
|
|
$toReturn{error}=$?;
|
2017-02-20 03:49:50 -06:00
|
|
|
|
2018-05-28 07:22:09 -05:00
|
|
|
if ( $? == -1){
|
|
|
|
$toReturn{errorString}='failed to run fail2ban-client';
|
|
|
|
}
|
|
|
|
elsif ($? & 127) {
|
|
|
|
$toReturn{errorString}= sprintf "fail2ban-client died with signal %d, %s coredump\n",
|
|
|
|
($? & 127), ($? & 128) ? 'with' : 'without';
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
$toReturn{error}=$? >> 8;
|
|
|
|
$toReturn{errorString}="fail2ban-client exited with ".$toReturn{error};
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( $toReturn{error} == 0 ){
|
2017-02-20 03:49:50 -06:00
|
|
|
|
2018-05-28 07:22:09 -05:00
|
|
|
my @jailsOutputA=split(/\n/, $jailsOutput);
|
|
|
|
my ( $jailsS )=grep( /Jail\ list/, @jailsOutputA );
|
|
|
|
$jailsS=~s/.*\://;
|
|
|
|
$jailsS=~s/\s//g;
|
|
|
|
my @jails=split(/\,/, $jailsS);
|
2017-02-20 03:49:50 -06:00
|
|
|
|
2018-05-28 07:22:09 -05:00
|
|
|
#process jails
|
|
|
|
my $int=0;
|
|
|
|
while(defined($jails[$int])){
|
|
|
|
|
|
|
|
#get the total for this jail
|
|
|
|
my $jailStatusOutput=`$f2bc status $jails[$int]`;
|
|
|
|
my @jailStatusOutputA=split(/\n/, $jailStatusOutput);
|
|
|
|
my ( $jailTotal )=grep(/Currently\ banned\:/, @jailStatusOutputA);
|
|
|
|
$jailTotal=~s/.*\://;
|
|
|
|
$jailTotal=~s/\s//g;
|
|
|
|
|
|
|
|
#tally the total and add this jail to the list
|
2018-06-25 16:10:00 +02:00
|
|
|
$toReturn{data}{total} = $toReturn{data}{total} + $jailTotal;
|
|
|
|
$toReturn{data}{jails}{ $jails[$int] } = $jailTotal;
|
2018-05-28 07:22:09 -05:00
|
|
|
|
|
|
|
$int++;
|
|
|
|
}
|
2017-02-20 03:49:50 -06:00
|
|
|
|
2018-05-28 07:22:09 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
my $j=JSON->new;
|
|
|
|
|
|
|
|
if ( $_[0] ){
|
|
|
|
$j->pretty(1);
|
|
|
|
return $j->encode( \%toReturn );
|
2017-02-20 03:49:50 -06:00
|
|
|
}
|
2017-02-20 13:18:50 -06:00
|
|
|
|
2018-05-28 07:22:09 -05:00
|
|
|
return $j->encode( \%toReturn )."\n";
|
2017-12-30 05:39:36 -06:00
|
|
|
}
|
2017-02-20 13:18:50 -06:00
|
|
|
|
2017-12-30 05:39:36 -06:00
|
|
|
#updates $cache
|
|
|
|
sub cacheUpdate{
|
2018-05-28 07:22:09 -05:00
|
|
|
my $stats=stats($_[0]);
|
2017-12-30 05:39:36 -06:00
|
|
|
|
|
|
|
open(my $writefh, ">", $cache) or die "Can't open '".$cache."'";
|
|
|
|
print $writefh $stats;
|
|
|
|
close($writefh);
|
|
|
|
}
|
|
|
|
|
|
|
|
#prints $cache
|
|
|
|
sub cachePrint{
|
|
|
|
my $old='';
|
|
|
|
open(my $readfh, "<", $cache) or die "Can't open '".$cache."'";
|
|
|
|
# if this is over 2048, something is most likely wrong
|
|
|
|
read($readfh , $old , 10240);
|
|
|
|
close($readfh);
|
|
|
|
print $old;
|
|
|
|
}
|
|
|
|
|
|
|
|
#gets the options
|
|
|
|
my %opts=();
|
2018-05-28 07:22:09 -05:00
|
|
|
getopts('puUcC:f:', \%opts);
|
2017-12-30 05:39:36 -06:00
|
|
|
|
|
|
|
#use custom cache file if needed
|
|
|
|
if ( defined( $opts{C} ) ){
|
|
|
|
$cache=$opts{C};
|
|
|
|
}
|
|
|
|
|
|
|
|
#use custom fail2ban location if needed
|
|
|
|
if ( defined( $opts{f} ) ){
|
|
|
|
$f2bc=$opts{f};
|
|
|
|
}
|
|
|
|
|
|
|
|
#use the cache
|
|
|
|
if ( defined( $opts{c} ) ){
|
|
|
|
my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
|
|
|
|
$atime,$mtime,$ctime,$blksize,$blocks) = stat($cache);
|
2017-02-20 13:18:50 -06:00
|
|
|
|
2017-12-30 05:39:36 -06:00
|
|
|
if (( -f $cache ) && defined( $mtime ) && ( (time-$mtime) < 360 )){
|
|
|
|
#cache exists and time is fine
|
|
|
|
cachePrint;
|
|
|
|
exit 0;
|
|
|
|
}else{
|
|
|
|
#cache does not exist or is old
|
|
|
|
if ( $opts{U} ){
|
|
|
|
#allowed to update it via -U
|
2018-05-28 07:22:09 -05:00
|
|
|
cacheUpdate( $opts{p} );
|
2017-12-30 05:39:36 -06:00
|
|
|
cachePrint;
|
|
|
|
exit 0;
|
|
|
|
}else{
|
|
|
|
#-U not given
|
|
|
|
warn("'".$cache."' does not exist or is to old and -U was not given");
|
|
|
|
exit 1;
|
2017-02-20 13:18:50 -06:00
|
|
|
}
|
|
|
|
}
|
2017-12-30 05:39:36 -06:00
|
|
|
warn('we should never get here...');
|
|
|
|
exit 2;
|
|
|
|
}
|
2017-02-20 13:18:50 -06:00
|
|
|
|
2017-12-30 05:39:36 -06:00
|
|
|
#update the cache
|
|
|
|
if (defined( $opts{u} )){
|
2018-05-28 07:22:09 -05:00
|
|
|
cacheUpdate( $opts{p} );
|
2017-02-20 03:49:50 -06:00
|
|
|
|
|
|
|
exit 0;
|
|
|
|
}
|
2017-12-30 05:39:36 -06:00
|
|
|
|
|
|
|
#no cache opions given, just print it
|
2018-05-28 07:22:09 -05:00
|
|
|
print &stats( $opts{p} );
|
2017-12-30 05:39:36 -06:00
|
|
|
|
|
|
|
exit 0;
|