So for the past year I been trying everywhere to get someone to make me this script to block these type attacks. I remember even asking here and for some reason or another was turned down but now I finally got someone to code it for me.
It has been tested by me and a few other people and it works. Its actually pretty simple.
I think another method that would work too is like the mod_security failure function to simply tail the specified domlog for the specified or if the script is real smart - the ability to pick up any request being requiested over and over abnormally.
This new script is called Block Apache Request Floods - B.A.R.F.and I think if this or something similar was integrated into csf it would totally complete everything it needs to provide effective and automatic ddos protection for all types of attacks. However in this script's current state the request, domain, and other paramters must be specified.
For example, I got a site under attack and the bots are making this request over and over again.
"GET / HTTP/1.1"
Ok, say I want to block any ip making this request over 2 times in 5 seconds I would enter
barf domain.com -n 2 -t 5 -s "GET / HTTP/1.1"
Here is script:
Code: Select all
#!/usr/bin/perl
##############################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# Copyright 2009 jpetersen
#
##############################################################################
##############################################################################
# _ __
# | | / _| BLOCK
# | |__ __ _ _ __| |_ APACHE
# | '_ \ / _` | '__| _| REQUEST
# | |_) | (_| | | | | FLOODS
# |_.__/ \__,_|_| |_| LoL:D
#
##############################################################################
##############################################################################
#
# Block an IP address if it issues x number of y requests
# to apache within z seconds. This script takes 4 options:
#
# example.com this is the domain to monitor
# -n <num> if this many requests
# -t <num> are made within this many seconds
# -s <req> for this string
# then the IP address issuing the requests will be blocked.
#
# Examples:
#
# Look for 3 requests within 10 seconds that match GET /index.php
# ./script example.com -n 3 -t 10 -s "GET /index.php"
#
# Look for 10 requests within 30 seconds that match GET / HTTP/1.1
# ./script example.com -n 10 -t 30 -s "GET / HTTP/1.1"
#
# This is the expected Apache log format, which is the default on cPanel servers:
# 1.2.3.4 - - [28/Jun/2009:16:43:05 -0400] "GET / HTTP/1.1" 404 - "-" "-"
#
##############################################################################
use strict;
use warnings;
use File::Tail;
use Getopt::Long;
if ( @ARGV ne 7 )
{
die "\nUsage:\n\t$0 example.com -n 3 -t 10 -s \"GET / HTTP/1.1\"\n\n";
}
my $site = shift; # domain name
my $domlog = '/usr/local/apache/domlogs/' . $site;
my %visitors = (); # 1.2.3.4 => 1246231315
my %hits = (); # 1.2.3.4 => 3
my $log_line;
-e $domlog or die "Unable to locate $domlog\n";
my ( $max_number_of_requests, $time_to_track, $request_string );
GetOptions (
"n=i" => \$max_number_of_requests,
"t=i" => \$time_to_track,
"s=s" => \$request_string,
);
my $file = File::Tail->new(
name => $domlog,
interval => 1,
maxinterval => 1,
resetafter => 1,
reset_tail => 0,
);
################################################################
#
# tail the domlog
#
################################################################
while ( defined ( $log_line = $file->read ) )
{
if ( $log_line =~ m{\A((\d{1,3}\.){3}\d{1,3})(\s-){2}(\s\S+){2}\s"$request_string} )
{
my $ipaddr = $1;
clean_hashes( $ipaddr );
check_visitors( $ipaddr );
check_for_block( $ipaddr );
}
}
################################################################
#
# Remove any IP addresses that have been seen longer than
# $time_to_track seconds ago.
#
################################################################
sub clean_hashes
{
my $ipaddr = shift;
if ( %visitors )
{
if($visitors{$ipaddr}) {
if ( ( time - $visitors{$ipaddr} ) > $time_to_track )
{
delete $visitors{$ipaddr};
delete $hits{$ipaddr};
}
}
}
}
################################################################
#
# Check to see if we're tracking the IP address already.
# If we aren't, update the %visitors hash.
#
################################################################
sub check_visitors
{
my $ipaddr = shift;
my $already_tracked = 0;
for my $key ( keys %visitors )
{
if ( $key eq $ipaddr )
{
$already_tracked = 1;
}
}
if ( $already_tracked == 0 )
{
$visitors{$ipaddr} = time;
}
}
################################################################
#
# Update the %hits hash. Check to see if the user specified
# number of hits has exceeded the user specified time period.
# If the threshold has been exceeded, then block the host and
# stop tracking it.
#
################################################################
sub check_for_block
{
my $ipaddr = shift;
$hits{$ipaddr}++;
if ( $hits{$ipaddr} >= $max_number_of_requests )
{
if ( ( time - $visitors{$ipaddr} ) <= $time_to_track )
{
print "blocking $ipaddr\n";
system '/usr/local/bin/csf', '-d', $ipaddr;
delete $visitors{$ipaddr};
delete $hits{$ipaddr};
}
}
}