CODE:
#!/usr/bin/perl
###############################################################################
## DDOSBlock version 0.1 Author: Jo3-GHT #
## #
## Download from https://sourceforge.net/projects/ddosblock #
## #
## To execute, run: #
## #
## ./ddosblock-0.2.pl #
###############################################################################
use strict;
use warnings;
use vars qw(%CONFIG %blocked);
$| = 1;
my %CONFIG = (
## 0 = No output
## 1 = Actions reported
## 2 = Actions + unix commands reported
## 3 = Verbose in the extreme
DEBUG => 2,
## Do we perform checks only - no IPTABLE changes - Good for debugging
TESTMODE => 0,
## Ban IP addresses above this number of accesses
THRESHOLD => 150,
## How long, in seconds, between checks
INTERVAL => 30,
## If we have APF use that, otherwise fallback on iptables
USEAPF => 0,
## How long (in seconds) do we ban people for
## escalating each time they're bad
## This resets to the first item, when they have gone
## a full interval without being flagged
##
## 60, 300, 3600 would mean that they are banned for 60 seconds, then 5 minutes, then an hour
##
## This list can have as many increment levels as you like
BANINCREMENTS => [60, 120, 240, 800, 1200],
## IP ADDRESSES THAT WE WILL NEVER BAN
EXCLUDEIPS => [ "127.0.0.1", "10.0.0.1" ],
## UNIX COMMANDS
NETSTAT => "/bin/netstat",
IPT => "/usr/sbin/iptables",
APF => "/usr/local/sbin/apf",
SENDMAIL => "/usr/sbin/sendmail",
## WHERE TO STORE/SAVE OUTPUT
LOGDIR => "/var/log/ddosblock",
MAILTO => "nobody\@example.com", # NOTE: Under Perl you have to escape the @ symbol with a slash
STDOUT => 1, # In addition to logging, do we want to report it to STDOUT
);
$CONFIG{TOTINCREMENTS} = $#{$CONFIG{BANINCREMENTS}};
$CONFIG{LISTFILE} = "$CONFIG{LOGDIR}/bannedips.txt";
$CONFIG{LASTDAY} = 0;
if ( ! -d $CONFIG{LOGDIR})
{
print "Creating log directory $CONFIG{LOGDIR}\n\n";
mkdir $CONFIG{LOGDIR},700;
}
my $command = qq($CONFIG{NETSTAT} -ntu | awk '{ sub(/(.*)\:/,"",\$4); sub(/\:(.*)/,"",\$5); print \$5,\$4}' | grep ^[0-9] | sort | uniq -c | sort -nr | head -30 );
&rotatelog();
if ($CONFIG{TESTMODE} == 1)
{
&debug(qq(** NOTE **\n\nTest mode - No IPTABLE changes will be made\n));
}
&loadbanned();
while (1)
{
&rotatelog();
&check();
&release();
&debug(qq(- Sleeping for $CONFIG{INTERVAL} seconds\n)) if ($CONFIG{DEBUG} > 1);
sleep $CONFIG{INTERVAL};
}
sub rotatelog
{
my @date = localtime();
my $weekday = $date[6];
if ($weekday != $CONFIG{LASTDAY})
{
if ($CONFIG{LASTDAY})
{
close(DEBUG);
}
$CONFIG{LASTDAY} = $weekday;
open(DEBUG, "> $CONFIG{LOGDIR}/doslog.$weekday.txt");
}
}
sub check
{
my @input = `$command`;
my $now = time;
my $savelist;
INPUTLOOP:
foreach my $item (@input)
{
chomp($item);
$item =~ s/^ +//io;
$item =~ s/ +/ /io;
&debug("-- $item\n") if ($CONFIG{DEBUG} >= 3);
my ($hits, $ipaddress, $port) = split(/ /, $item);
next INPUTLOOP if (grep(/^$ipaddress/, @{$CONFIG{EXCLUDEIPS}}));
next INPUTLOOP if (defined $blocked{$ipaddress} && $now < $blocked{$ipaddress}{sleepuntil});
if ($hits > $CONFIG{THRESHOLD})
{
$blocked{$ipaddress}{blocklevel} = $blocked{$ipaddress}{lastblock} + 1 || 1;
$blocked{$ipaddress}{lastblock} = $blocked{$ipaddress}{blocklevel};
if ($blocked{$ipaddress}{blocklevel} == 1)
{
my $iptcmd = ($CONFIG{USEAPF}) ?
"$CONFIG{APF} -d $ipaddress"
:
"$CONFIG{IPT} -I INPUT -s $ipaddress -j DROP";
my $ok = `$iptcmd` unless ($CONFIG{TESTMODE});
&debug("Adding block for $ipaddress ($hits hits/minute, port $port)") if ($CONFIG{DEBUG} > 0);
&debug("- Command $iptcmd") if ($CONFIG{DEBUG} > 1);
if ($CONFIG{MAILTO})
{
my $localtime = localtime();
open (MAIL, "| $CONFIG{SENDMAIL} -t");
print MAIL qq(To: $CONFIG{MAILTO}\nSubject: IP address $ipaddress banned\n\nBanned ip addresses $ipaddress on $localtime with $hits hits\n);
close (MAIL);
}
}
else
{
&debug("Setting $ipaddress to block level $blocked{$ipaddress}{blocklevel} ($hits hits/minute)") if ($CONFIG{DEBUG} > 0);
}
&updatesleep($ipaddress);
$savelist = 1;
}
}
# Save a list of banned IPs to a file incase this process dies
if ($savelist)
{
&savebanned();
}
}
sub release
{
my $now = time;
my $savelist;
# Loop through all the IP addresses flagged
foreach my $ipaddress (keys %blocked)
{
# No point looking at it until we've gone past the sleep date
if ($now > $blocked{$ipaddress}{sleepuntil})
{
$blocked{$ipaddress}{passcount}++;
# Remove the block on the first pass
# then remove the
if ($blocked{$ipaddress}{passcount} == 1)
{
# Release the block
my $iptcmd = ($CONFIG{USEAPF}) ?
"$CONFIG{IPT} -u "
:
"$CONFIG{IPT} -D INPUT -s $ipaddress -j DROP";
&debug("Removing block from $ipaddress") if ($CONFIG{DEBUG}> 0);
&debug("- Command $iptcmd") if ($CONFIG{DEBUG} > 1);
my $ok = `$iptcmd` unless ($CONFIG{TESTMODE});
$blocked{$ipaddress}{blocklevel} = 0;
}
else
{
&debug("- Two passes without issue $ipaddress, forgetting block level") if ($CONFIG{DEBUG} > 1);
delete $blocked{$ipaddress};
}
$savelist = 1;
}
}
# Save a list of banned IPs to a file incase this process dies
if ($savelist)
{
&savebanned(\%blocked);
}
}
sub updatesleep
{
my ($ipaddress) = @_;
my $blocklevel = $blocked{$ipaddress}{blocklevel};
$blocklevel = ($blocklevel >= $CONFIG{TOTINCREMENTS}) ? $#{$CONFIG{BANINCREMENTS}} : $blocklevel;
my $increment = $CONFIG{BANINCREMENTS}[$blocklevel - 1];
$blocked{$ipaddress}{sleepuntil} = time + $increment;
my $stamp = localtime(time + $increment);
&debug("- Will check $ipaddress after $increment seconds ($stamp) - Block level $blocklevel") if ($CONFIG{DEBUG} > 1);
}
sub loadbanned
{
undef %blocked;
if (-f $CONFIG{LISTFILE})
{
open(LIST, "< $CONFIG{LISTFILE}");
my @list = <LIST>;
close (LIST);
# Rebuild a list of those things we've blocked
foreach my $ipaddress (@list)
{
chomp($ipaddress);
# Let them be released and evaluated again
$blocked{$ipaddress}{sleepuntil} = 1;
$blocked{$ipaddress}{blocklevel} = 1;
$blocked{$ipaddress}{lastblock} = 1;
$blocked{$ipaddress}{passcount} = 0;
&debug("- Loading blocked IP $ipaddress") if ($CONFIG{DEBUG} > 0);
}
}
}
sub savebanned
{
my ($list) = @_;
open(LIST, "> $CONFIG{LISTFILE}");
print LIST join("\n", keys %blocked);
close (LIST);
}
sub debug
{
my ($line) = @_;
print DEBUG localtime() . " $line \n";
if ($CONFIG{STDOUT})
{
print localtime() . " $line \n";
}
}
BÌNH LUẬN (0)
Một số lưu ý khi bình luận
Mọi bình luận sai nội quy sẽ bị xóa mà không cần báo trước (xem nội quy)
Bấm Thông báo cho tôi bên dưới khung bình luận để nhận thông báo khi admin trả lời
Để bình luận một đoạn code, hãy mã hóa code trước nhé