…and general pests, by IP address block
Introduction
Being fundamentally fed up with spam Referrers, I wanted a quick and easy way to ban entire blocks of IP addresses inside PhpWiki. My requirements were simple:
- No database tables (I’m not going to waste time doing a query for these clowns)
- Instantly editable with vim over SSH
- Short and efficient, so that it can be included from all my PHP code
- Support for IP network masks or ranges
- Support for custom messages indicating the reason of the ban
I soon gave up trying to match substrings inside URLs and trying to prevent access before the fact – it would be extremely slow and require far too much effort.
The Code
Without further ado, here it is:
// Check if a given IP address is inside a given subnet
function in_subnet($network, $mask, $ip) {
$ip_long=ip2long($ip);
$network_long=ip2long($network);
$mask_long=ip2long($mask);
if( ( $ip_long & $mask_long) == ($network_long & $mask_long)) {
return true;
} else {
return false;
}
}
// The bozos (in vim, just "/bozo" to get here)
$aBanned = array(
array( 'ip' => "69.57.152.89",
'mask' => "255.255.255.255",
'reason' => "Referral spamming with URLs to spam services and porn sites" ),
array( 'ip' => "193.55.220.0",
'mask' => "255.255.255.0",
'reason' => "Referral spamming with drug advertising" )
);
// inline code (this gets executed by whoever includes this file)
foreach( $aBanned as $aCheck ) {
if( in_subnet( $aCheck['ip'], $aCheck['mask'], $_SERVER['REMOTE_ADDR'] ) ) {
header( "HTTP/1.1 403 Access Denied" );
echo( "<H1>You Are Banned From Accessing This Site</H1>");
echo( "<p><b>Reason:</b> " . $aCheck['reason'] . "</p>" );
echo( "<p>I am in the process of reporting this abuse to your ISP or netblock owner" );
echo(" - on the Internet, nobody is really anonymous.</p>" );
// log this so we can grep it out of error_log
error_log( strftime("%d/%b/%Y:%H:%M:%S") . " [BANNED] " . $aCheck['ip'] . " " . $aCheck['reason'] );
exit;
}
}