<?php
/**
* HostBlock statistics calculation and output class
*
* @author Rolands Kusiņš
* @license GPL
*
*/
class Stats{
// Path to file with IP info
public $suspiciousIpsPath = "";
// Object for writing to log files
public $log = null;
// How many matches must an IP have to be in blacklist
public $suspiciousEntryMatchCount = 5;
// For how long time to keep IP in blacklist
public $blacklistTime = 0;
// Array with IP information
public $ipInfo = array();
// Array with statistics data
private $data = array();
// Permanent blacklist file
public $permanentBlacklistFile = "";
// Permanent whitelist file
public $permanentWhitelistFile = "";
// IPs from blacklist file
private $include = array();
// IPs from whitelist file
private $exclude = array();
// Datetime format
public $dateTimeFormat = "Y-m-d H:i:s";
/**
* Load IP addresses that we need to perminately include or exclude from blacklist
*/
public function loadBlacklist(){
// Clear blacklist/whitelist arrays
$this->include = array();
$this->exclude = array();
// Read blacklist
if(!is_null($this->permanentBlacklistFile)){
$f = @fopen($this->permanentBlacklistFile,"r");
if($f){
while(!feof($f)){
$line = trim(fgets($f,4096));
if(ip2long($line) !== false){
if(!in_array($line,$this->include)){
$this->include[] = $line;
} else{
$this->log->write("Duplicate IP address ".$line." in permanent blacklist file!");
}
}
}
@fclose($f);
}
}
// Read whitelist
if(!is_null($this->permanentWhitelistFile)){
$f = @fopen($this->permanentWhitelistFile,"r");
if($f){
while(!feof($f)){
$line = trim(fgets($f,4096));
if(ip2long($line) !== false){
if(!in_array($line,$this->exclude)){
$this->exclude[] = $line;
} else{
$this->log->write("Duplicate IP address ".$line." in permanent whitelist file!");
}
}
}
@fclose($f);
}
}
}
/**
* Load data about suspicious IP addresses
*/
public function load(){
// Read IP data
$data = @file_get_contents($this->suspiciousIpsPath);
if($data != false){
$this->ipInfo = unserialize($data);
} else{
$this->log->write("Unable to load IP data!","error");
}
}
/**
* Calculate statistics
*/
public function calculate(){
$this->data = array();
$currentTime = time();
if(count($this->ipInfo) > 0){
// Init array
$this->data['blacklisted_ip_count'] = count($this->include);
$this->data['top5'] = array();
$this->data['top5']['ip'] = array();
$this->data['top5']['count'] = array();
$this->data['top5']['refused'] = array();
$this->data['top5']['lastactivity'] = array();
$this->data['last5'] = array();
$this->data['last5']['ip'] = array();
$this->data['last5']['count'] = array();
$this->data['last5']['refused'] = array();
$this->data['last5']['lastactivity'] = array();
// Loop through all IP addresses
foreach($this->ipInfo as $k => $v){
if(!isset($v['refused'])) $v['refused'] = 0;
// Blacklisted IP address count
if($v['count'] >= $this->suspiciousEntryMatchCount && (($currentTime - $v['lastactivity']) <= $this->blacklistTime || $this->blacklistTime == 0) && !in_array($k,$this->exclude)){
$this->data['blacklisted_ip_count']++;
}
// Last 5 IP addresses
if(isset($v['lastactivity'])){
if(count($this->data['last5']['ip']) < 5){
// First we fill up last5 array
$this->data['last5']['ip'][] = $k;
$this->data['last5']['count'][] = $v['count'];
$this->data['last5']['refused'][] = $v['refused'];
$this->data['last5']['lastactivity'][] = $v['lastactivity'];
} else{
// Then we update with IP addresses that have more recent activity
$keys = array_keys($this->data['last5']['lastactivity'],min($this->data['last5']['lastactivity']));
if(count($keys) > 0){
if($this->data['last5']['lastactivity'][$keys[0]] < $v['lastactivity']){
$this->data['last5']['ip'][$keys[0]] = $k;
$this->data['last5']['count'][$keys[0]] = $v['count'];
$this->data['last5']['refused'][$keys[0]] = $v['refused'];
$this->data['last5']['lastactivity'][$keys[0]] = $v['lastactivity'];
}
}
}
}
// Get top 5 IP addresses by count
if(count($this->data['top5']['ip']) < 5){
// First we fill up top5 array
$this->data['top5']['ip'][] = $k;
$this->data['top5']['count'][] = $v['count'];
$this->data['top5']['refused'][] = $v['refused'];
$this->data['top5']['lastactivity'][] = $v['lastactivity'];
} else{
// Then we update with IP addresses that have more suspicious activity
$keys = array_keys($this->data['top5']['count'],min($this->data['top5']['count']));
if(count($keys) > 0){
if($this->data['top5']['count'][$keys[0]] < $v['count']){
$this->data['top5']['ip'][$keys[0]] = $k;
$this->data['top5']['count'][$keys[0]] = $v['count'];
$this->data['top5']['refused'][$keys[0]] = $v['refused'];
$this->data['top5']['lastactivity'][$keys[0]] = $v['lastactivity'];
}
}
}
}
// Sort top 5 array
array_multisort($this->data['top5']['count'], SORT_DESC, $this->data['top5']['ip'], $this->data['top5']['lastactivity'], $this->data['top5']['refused']);
// Sort last 5 array
array_multisort($this->data['last5']['lastactivity'], SORT_DESC, $this->data['last5']['ip'], $this->data['last5']['count'], $this->data['last5']['refused']);
}
}
/**
* Echo statistics
*/
public function output(){
if(count($this->ipInfo) > 0){
echo "\n";
echo "Total suspicious IP address count: ".count($this->ipInfo)."\n";
echo "Blacklisted IP address count: ".$this->data['blacklisted_ip_count']."\n";
echo "\n";
echo "Top 5 most active IP addresses:\n";
$countPadLength = strlen($this->data['top5']['count'][0]);
if($countPadLength < 5) $countPadLength = 5;
$refusedPadLength = 7;
$dateTimePadLength = 13;
foreach($this->data['top5']['refused'] as $k => $v){
if(strlen($v) > $refusedPadLength) $refusedPadLength = strlen($v);
if(strlen(date($this->dateTimeFormat, $this->data['top5']['lastactivity'][$k])) > $dateTimePadLength) $dateTimePadLength = strlen(date($this->dateTimeFormat, $this->data['top5']['lastactivity'][$k]));
}
echo "-------------------".str_repeat("-", $countPadLength).str_repeat("-", $refusedPadLength).str_repeat("-", $dateTimePadLength)."-------\n";
echo " IP | ".str_pad("Count",$countPadLength," ",STR_PAD_BOTH)." | ".str_pad("Refused",$refusedPadLength," ",STR_PAD_BOTH)." | ".str_pad("Last activity",$dateTimePadLength," ",STR_PAD_BOTH)."\n";
echo "-------------------".str_repeat("-", $countPadLength).str_repeat("-", $refusedPadLength).str_repeat("-", $dateTimePadLength)."-------\n";
foreach($this->data['top5']['ip'] as $k => $v){
echo " ".str_pad($v,15," ")." | ".str_pad($this->data['top5']['count'][$k],$countPadLength," ",STR_PAD_BOTH)." | ".str_pad($this->data['top5']['refused'][$k],$refusedPadLength," ",STR_PAD_BOTH)." | ".str_pad(date($this->dateTimeFormat, $this->data['top5']['lastactivity'][$k]),$dateTimePadLength," ")."\n";
}
echo "-------------------".str_repeat("-", $countPadLength).str_repeat("-", $refusedPadLength).str_repeat("-", $dateTimePadLength)."-------\n";
echo "\n";
echo "Last activity:\n";
$countPadLength = strlen($this->data['last5']['count'][0]);
if($countPadLength < 5) $countPadLength = 5;
$refusedPadLength = 7;
$dateTimePadLength = 13;
foreach($this->data['last5']['refused'] as $k => $v){
if(strlen($v) > $refusedPadLength) $refusedPadLength = strlen($v);
if(strlen(date($this->dateTimeFormat, $this->data['last5']['lastactivity'][$k])) > $dateTimePadLength) $dateTimePadLength = strlen(date($this->dateTimeFormat, $this->data['last5']['lastactivity'][$k]));
}
echo "-------------------".str_repeat("-", $countPadLength).str_repeat("-", $refusedPadLength).str_repeat("-", $dateTimePadLength)."-------\n";
echo " IP | ".str_pad("Count",$countPadLength," ",STR_PAD_BOTH)." | ".str_pad("Refused",$refusedPadLength," ",STR_PAD_BOTH)." | ".str_pad("Last activity",$dateTimePadLength," ",STR_PAD_BOTH)."\n";
echo "-------------------".str_repeat("-", $countPadLength).str_repeat("-", $refusedPadLength).str_repeat("-", $dateTimePadLength)."-------\n";
foreach($this->data['last5']['ip'] as $k => $v){
echo " ".str_pad($v,15," ")." | ".str_pad($this->data['last5']['count'][$k],$countPadLength," ",STR_PAD_BOTH)." | ".str_pad($this->data['last5']['refused'][$k],$refusedPadLength," ",STR_PAD_BOTH)." | ".str_pad(date($this->dateTimeFormat, $this->data['last5']['lastactivity'][$k]),$dateTimePadLength," ")."\n";
}
echo "-------------------".str_repeat("-", $countPadLength).str_repeat("-", $refusedPadLength).str_repeat("-", $dateTimePadLength)."-------\n";
echo "\n";
} else{
echo "No data!\n";
}
}
/**
* Echo all blacklisted IP addresses
*/
public function outputBlacklist($count = false, $time = false){
$currentTime = time();
if(count($this->ipInfo) == 0 && count($this->include) == 0){
echo "No data!\n";
return;
}
// All automatically blacklisted IP addresses
if(count($this->ipInfo) > 0){
// Find max count value
$maxCount = 0;
$maxRefused = 0;
foreach($this->ipInfo as &$ip){
if($ip['count'] > $maxCount) $maxCount = $ip['count'];
if(isset($ip['refused']) && $ip['refused'] > $maxRefused) $maxRefused = $ip['refused'];
}
$countPadLength = strlen($maxCount);
$refusedPadLength = strlen($maxRefused);
// Loop through all suspicious IP addresses
foreach($this->ipInfo as $k => $v){
if($v['count'] >= $this->suspiciousEntryMatchCount && (($currentTime - $v['lastactivity']) <= $this->blacklistTime || $this->blacklistTime == 0) && !in_array($k,$this->exclude)){
if(in_array($k,$this->include)){
$this->log->write("IP address ".$k." is blacklisted by hostblock and is also included in permanent blacklist! Consider removing duplicate from permanent blacklist!");
continue;
}
echo "a ";
echo str_pad($k,15);
if($count == true){
echo " ".str_pad($v['count'],$countPadLength," ");
if(isset($v['refused'])) echo " ".str_pad($v['refused'],$refusedPadLength," ");
else echo " ".str_pad("0",$refusedPadLength," ");
}
if($time == true){
echo " ".date($this->dateTimeFormat, $v['lastactivity']);
}
echo "\n";
}
}
}
// All manually blacklisted IP addresses
if(count($this->include) > 0){
foreach($this->include as &$ip){
echo "m ";
echo str_pad($ip,15);
if($count == true){
if(isset($this->ipInfo[$ip])){
echo " ".str_pad($this->ipInfo[$ip]['count'],$countPadLength," ");
if(isset($this->ipInfo[$ip]['refused'])) echo " ".str_pad($this->ipInfo[$ip]['refused'],$refusedPadLength," ");
else echo " ".str_pad("0",$refusedPadLength," ");
} else{
echo " ".str_pad("0",$countPadLength," ");
echo " ".str_pad("0",$refusedPadLength," ");
}
}
if($time == true){
if(isset($this->ipInfo[$ip])){
echo " ".date($this->dateTimeFormat, $this->ipInfo[$ip]['lastactivity']);
}
}
echo "\n";
}
}
}
/**
* Get blacklisted IP addresses
*
* @return array
*/
public function getBlacklistedIps(){
$currentTime = time();
$result = array();
if(count($this->ipInfo) > 0){
foreach($this->ipInfo as $k => $v){
if($v['count'] >= $this->suspiciousEntryMatchCount && (($currentTime - $v['lastactivity']) <= $this->blacklistTime || $this->blacklistTime == 0) && !in_array($k,$this->exclude)){
if(in_array($k,$this->include)){
$this->log->write("IP address ".$k." is blacklisted by hostblock and is also included in permanent blacklist! Consider removing duplicate from permanent blacklist!");
continue;
}
$result[] = $k;
}
}
}
foreach($this->include as $ip){
$result[] = $ip;
}
return $result;
}
/**
* Get blacklisted IP address count
*
* @return number
*/
public function getBlacklistedIpCount(){
$currentTime = time();
$count = count($this->include);
if(count($this->ipInfo) > 0){
foreach($this->ipInfo as $k => $v){
if($v['count'] >= $this->suspiciousEntryMatchCount && (($currentTime - $v['lastactivity']) <= $this->blacklistTime || $this->blacklistTime == 0) && !in_array($k,$this->exclude)){
if(in_array($k,$this->include)){
$this->log->write("IP address ".$k." is blacklisted by hostblock and is also included in permanent blacklist! Consider removing duplicate from permanent blacklist!");
continue;
}
$count++;
}
}
}
return $count;
}
/**
* Get total refused connect count
*
* @return number
*/
public function getTotalRefusedConnectCount(){
$count = 0;
if(count($this->ipInfo) > 0){
foreach($this->ipInfo as $ip){
if(isset($ip['refused'])){
$count += $ip['refused'];
}
}
}
return $count;
}
}
?>
|