#!/usr/bin/perl
#
# Description:
# Tails a custom Apache log and defaces the sites that reaches their daily limit.
#
# Append this to httpd.conf:
# LogFormat "%f:%b" bytecount
# CustomLog /var/log/apache bytecount
# Include conf.d/abuse/*.conf
#
#
# AUTHOR
# Martin Stabenfeldt
#
#$DEBUG=1;
$LIMIT = "500000000"; # In bytes
$PIDFILE = "/var/run/bofh.pid";
$LOGFILE = "/var/log/httpd/bytecount.log";
$CONFDIR = "/etc/httpd/conf.d/abuse";
$NOTIFY = "drift\@hosting.com";
$BOFHLOG = "/var/log/httpd/bofh.log";
$apachectl = "/usr/sbin/apachectl";
$machine = "www3";
($min, $hour, $day, $month, $year) = (localtime)[1,2,3,4,5];
$date = sprintf("%04d-%02d-%02d %02d:%02d\n", $year+1900, $month+1, $day, $hour, $min);
# Check that we're running from the right host and
# kill other bofh.pl prosesses running!
$hostname = `hostname`;
chomp($hostname);
die "I'll only run on $machine! Quiting...\n" if $hostname !~ "$machine\.";
if (-e $PIDFILE) {
open(PIDFILE, "<", $PIDFILE)
or die "Can't read from $PIDFILE: $!\n";
$OLDPID = ;
close PIDFILE;
chomp $OLDPID;
# Check that $OLDPID only contains digits.
die "PIDFILE shall only contain digits! ($OLDPID)\n"
if $OLDPID !~ /\d+/;
print "Sending prosess id $OLDPID the TERM signal...\n" if $DEBUG;
kill 'TERM', $OLDPID
unless $OLDPID <= 2; # Perhaps this should be 100, we dont want to kill systemcritical processes.
}
setpriority 0, 0, getpriority(0, 0) + 20; # Behave!
open(PIDFILE, ">", $PIDFILE)
or die "Can't open $PIDFILE: $!\n";
print PIDFILE "$$\n";
print "New PID: $$\n" if$DEBUG;
close PIDFILE;
open(LOGFILE, "<", $LOGFILE)
or die "Couldn't read $LOGFILE: $!\n";
open(BOFHLOG, ">>", $BOFHLOG)
or die "Couldn't write to $BOFHLOG: $!\n";
print "\$LIMIT is $LIMIT bytes\n" if $DEBUG;
for (;;) {
while () {
m{/home/p/pt/pt-home/freehost.com/(\w+)/.+:(\d+)};
$username = $1;
$username =~ tr/[A-Z]/[a-z]/;
$usage{$username} += $2;
$count++;
if ($count >= 2000) {
$count = undef;
foreach $user (keys %usage) {
# Simpel whitelisting..
next if $user =~ john;
next if $user =~ jane;
if ($usage{$user} >= $LIMIT) {
print "$user has exceeded the current limit ($LIMIT): $usage{$user}\n" if $DEBUG;
if (!-e "$CONFDIR/$user.conf") {
$usage{$user} = undef;
deface($user);
#mailadmin($user, $usage{$user});
bofhlog($user);
system("$apachectl graceful >/dev/null");
}
}
}
}
}
sleep 3;
seek(FH, 0, 1);
}
sub bofhlog {
$user = shift;
($min, $hour, $day, $month, $year) = (localtime)[1,2,3,4,5];
$date = sprintf("%04d-%02d-%02d %02d:%02d\n", $year+1900, $month+1, $day, $hour, $min);
print BOFHLOG "$user\t$date";
}
sub deface {
$user = shift;
open(DEFACE, ">", "$CONFDIR/$user\.conf")
or die "Error appending $user to $CONFDIR/$user: $!\n";
print DEFACE "RedirectMatch 302 ^/$user/ http://www.hosting.com/quota.html\n";
close DEFACE;
# 302 Found
#
# The requested resource resides temporarily under a different URI. Since the redirection might be altered on
# occasion, the client SHOULD continue to use the Request-URI for future requests. This response is only cacheable
# if indicated by a Cache-Control or Expires header field.
}
sub mailadmin {
$user = shift;
$usage = shift;
open(MAIL, "| mail -s \"Transfer quota exceeded for $user\" $NOTIFY");
print MAIL "http://home.hosting.com/$user\n";
close MAIL;
}
close LOGFILE;
close BOFHLOG;