Skip to content

Instantly share code, notes, and snippets.

@thequux
Created October 19, 2015 11:25
Show Gist options
  • Save thequux/d09cc433b28b3383be5a to your computer and use it in GitHub Desktop.
Save thequux/d09cc433b28b3383be5a to your computer and use it in GitHub Desktop.
<?php
// This is designed to be used with the IP list from
// https://rules.emergingthreats.net/fwrules/emerging-Block-IPs.txt
//
// To use:
// $ipset = new IPSet("emerging-Block-IPs.txt");
// if ($ipset->check_ip($_SERVER['REMOTE_ADDR'])) {
// // Block the request
// }
class IPSet {
private $blacklist = null;
# We don't know whether we're working with 32-bit or 64-bit
# integers, so we instead *always* sign-extend from 32-bits.
function __construct($blacklist_file) {
$this->blacklist = array();
try {
$file = fopen($blacklist_file, "r");
if ($file === false) {
error_log("Blacklist file not found");
return;
}
// Read the lines
while (($line = fgets($file)) !== false) {
// Strip comments and newline
$commentStart = strpos($line, '#');
if ($commentStart !== false) {
$line = substr($line, 0, $commentStart);
}
$line = trim($line);
if ($line !== "") {
$parsed = $this->parse_ip($line);
if ($parsed !== false) {
//printf("%20s %016x/%08x\n", $line, $parsed[0], $parsed[1]);
$this->blacklist []= $parsed;
}
}
}
} finally {
fclose($file);
}
}
private function parse_ip($cidr) {
$slashPos = strpos($cidr, "/");
if ($slashPos === false) {
$mask = -1;
$ipS = $cidr;
} else {
// This won't work with a subnet of 0 on 32-bit machines,
// but that's fine, because this is intended for use as a
// *blacklist*, and blocking a /0 would block everything
$mask = -1 << (32 - substr($cidr, $slashPos + 1));
$ipS = substr($cidr, 0, $slashPos);
}
// Now, parse the IP. First, this will involve breaking it
// into octets
$octets = explode(".", $ipS);
if (count($octets) != 4) {
// WTF? This shouldn't happen.
// TODO: Throw an error
return false;
}
$ip = $octets[0] - 0;
if ($ip >= 128) {
$ip -= 256; // treat as signed byte so that it works on
// 32-bit PHPs.
}
// Add the rest of the octets
for ($i = 1; $i < 4; $i++) {
$ip = ($ip << 8) + $octets[$i];
}
return array($ip & $mask, $mask);
}
public function check_ip($ip) {
// returns true if the IP is in the blacklist.
list($ip, $ipmask) = $this->parse_ip($ip);
foreach ($this->blacklist as $probe) {
list($probeIp, $probeMask) = $probe;
if (($ip & $probeMask) == $probeIp) {
return true;
}
}
return false;
}
}
@thequux
Copy link
Author

thequux commented Oct 19, 2015

BTW, this is licensed under your choice of ISC, BSD 2-clause, or MIT licenses. If, for some reason, none of those are acceptable, contact me for a custom license.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment