App-BlockWebFlooders
view release on metacpan or search on metacpan
script/block-web-flooders view on Meta::CPAN
$Opts{lacks_pattern} = [map { qr/$_/ } @{ $Opts{lacks_pattern} }];
}
}
sub connectdb {
require DBI;
require SQL::Schema::Versioned;
return if $Dbh;
$Dbh = DBI->connect("dbi:SQLite:dbname=/var/run/block-web-flooders.db");
my $res = SQL::Schema::Versioned::create_or_update_db_schema(
dbh => $Dbh, spec => $Dbspec);
die "Cannot initialize DB: $res->[0] - $res->[1]" unless $res->[0] == 200;
}
sub _set_need_reload {
$Dbh->do("INSERT OR IGNORE INTO meta (name,value) VALUES ('_need_reload',0)");
$Dbh->do("UPDATE meta SET value=$_[0] WHERE name='_need_reload'");
}
sub _reload_data_from_db {
my $force = shift;
my ($need_reload) = $Dbh->selectrow_array("SELECT value FROM meta WHERE name='_need_reload'");
return if !$force && defined $need_reload && !$need_reload;
%Blocked = ();
my $sth = $Dbh->prepare("SELECT * FROM blocked");
$sth->execute;
while (my $row = $sth->fetchrow_hashref) {
$Blocked{ $row->{ip} } = $row->{ctime};
}
unshift @Messages, "(re)loaded data from db";
_set_need_reload(0);
}
sub _init {
connectdb();
_reload_data_from_db(1); # force
%Whitelisted = map { $_=>1 } @{ $Opts{whitelist_ip} };
}
sub _block_or_unblock_ip {
my ($which, $ip, $update_messages) = @_;
$update_messages //= 1;
if ($which eq 'block') {
return if $Blocked{$ip};
} else {
return unless $Blocked{$ip};
}
system(
{
die => ($which eq 'block' ? 1:0),
dry_run => $Opts{dry_run},
(capture_stderr => \my $stderr) x ($which eq 'block' ? 0:1),
},
"iptables", ($which eq 'block' ? "-A" : "-D"), "INPUT", "-s", $ip,
"-p", "tcp", "-m", "multiport", "--dports", "80,443",
"-j", "DROP",
);
my $now = time();
if ($which eq 'block') {
unshift @Messages, "$ip BLOCKED".($Opts{dry_run} ? " (dry-run)" : "")
if $update_messages;
$Dbh->do("INSERT OR IGNORE INTO blocked (ip,ctime) VALUES (?,?)", {}, $ip, $now);
$Blocked{$ip} = time();
} else {
unshift @Messages, "$ip unblocked".($Opts{dry_run} ? " (dry-run)" : "")
if $update_messages;
$Dbh->do("DELETE FROM blocked WHERE ip=?", {}, $ip);
delete $Blocked{$ip};
}
}
sub block_ip { _block_or_unblock_ip("block", @_) }
sub unblock_ip { _block_or_unblock_ip("unblock", @_) }
sub _block_or_unblock_ips {
my $which = shift;
_init();
# get IP's from command-line arguments if specified, otherwise from stdin
my $iter;
if (@ARGV) {
require Array::Iter;
$iter = Array::Iter::array_iter(\@ARGV);
} else {
$iter = sub { scalar <STDIN> };
}
while (defined(my $ip = $iter->())) {
chomp($ip);
unless ($ip =~ /\A$RE{ipv4}\z/) {
warn "$PROG: Invalid IP address '$ip', skipped\n";
next;
}
_block_or_unblock_ip($which, $ip, 1); # don't update messages
}
}
sub action_block {
_block_or_unblock_ips("block");
_set_need_reload(1);
}
sub action_unblock {
_block_or_unblock_ips("unblock");
_set_need_reload(1);
}
sub action_list_blocked {
_init();
( run in 1.348 second using v1.01-cache-2.11-cpan-39bf76dae61 )