Code tagged with log

Apache Bandwidth Limiter

Posted by Martin Stabenfeldt over 2 years ago
#!/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;
Language Perl / Tagged with apache, bandwidth, tail, log