-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathhttpblock.pl
More file actions
executable file
·129 lines (103 loc) · 2.42 KB
/
httpblock.pl
File metadata and controls
executable file
·129 lines (103 loc) · 2.42 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#!/usr/bin/perl -w
use Cwd 'abs_path';
use File::Basename;
use Getopt::Std;
use Date::Simple;
my $options = ();
getopts("v", \%options);
&_verbose("Starting...");
chdir dirname(abs_path($0));
my %cfg = do('settings');
my @allowed = &_read_list('allow');
my @footprints = &_read_list('footprints');
$logs = '/var/log/httpd/www*access_log';
$grep = '/bin/grep';
$banCmd = '/sbin/iptables -A HTTPD -s %s -j DROP';
$findCmd = '/sbin/iptables -L HTTPD -n';
my %deny = ();
my @existing = `$findCmd`;
foreach my $fp (@footprints) {
my @found = `$grep $fp $logs`;
foreach my $r (@found) {
chomp($r);
my ($vhost) = $r =~ /httpd\/(.*?)-access_log/;
my ($ip) = $r =~ /:(\d+\.\d+\.\d+\.\d+)\s-/;
if (!$ip) {
&_verbose("NO IP Found: $r");
next;
}
if (!&_allowIp($ip)) {
$deny{$ip}{$vhost}{$fp}++;
}
else {
&_verbose("IP: $ip is allowed on '$fp'.");
}
}
}
foreach my $ip (keys %deny) {
if (!&_alreadyDenied($ip)) {
my $fwCmd = sprintf($banCmd, $ip);
my $hostCount = scalar(keys %{$deny{$ip}});
my $attackCount = 0;
foreach my $host (keys %{ $deny{$ip} }) {
foreach my $app (keys %{ $deny{$ip}{$host} }) {
$attackCount += $deny{$ip}{$host}{$app};
}
}
my $response = "IGNORED";
if ($hostCount >= $cfg{'trigger'}{'minHosts'} || $attackCount >= $cfg{'trigger'}{'minAttacks'}) {
`$fwCmd`;
$response = "BANNED";
}
&_scan_log("$ip attacked $hostCount vhost(s) with $attackCount queries... $response");
}
else {
&_verbose("$ip is already blocked, but found it in logs...");
}
}
sub _allowIp($) {
my ($ip) = @_;
foreach (@allowed) {
if ($ip =~ /$_/) {
return 1;
}
}
return 0;
}
sub _alreadyDenied($) {
my ($ip) = @_;
$found = grep /$ip/, @existing;
return $found;
}
sub _timestamp {
my $date = Date::Simple->new;
my ($hr,$mn,$sc) = (localtime)[2,1,0];
return ($date->year, $date->month, $date->day, $hr, $mn, $sc);
}
sub _scan_log($) {
my ($msg) = @_;
my @ts = &_timestamp();
my $date = sprintf("%02d/%02d/%d", $ts[1], $ts[2], $ts[0]);
my $time = sprintf("%02d:%02d:%02d", $ts[3], $ts[4], $ts[5]);
print "$date - $time - $msg\n";
}
sub _verbose($) {
my ($msg) = @_;
if ($options{v}) {
&_scan_log($msg);
}
}
sub _read_list($) {
my ($file) = @_;
open(IN, "< $file") || die "Can't read config: " . $file;
my @in = <IN>;
close(IN);
my @r = ();
foreach my $i (@in) {
chomp($i);
next if $i =~ /^#/;
push @r, $i;
}
return @r;
}
&_verbose("Finished");