Skip to content

Commit

Permalink
update algorithm and add remove duplicate rules
Browse files Browse the repository at this point in the history
  • Loading branch information
xnohat committed Nov 5, 2016
1 parent a73654d commit b09424a
Show file tree
Hide file tree
Showing 2 changed files with 171 additions and 92 deletions.
140 changes: 97 additions & 43 deletions analyser.php
Original file line number Diff line number Diff line change
@@ -1,62 +1,116 @@
<?php

echo "\n\t---------------------------------\n
\tXNOHAT DDoS FIREWALL\n
\tVersion: 1.1\n
\t[email protected]\n
-----------------------------------\n
";
register_shutdown_function( "fatal_handler" );

$serverip = '125.212.250.72';
$yourip = '1.53.194.96';
$exclude_ips = array($serverip,
$yourip,
main();

'1.53.194.96',
function main(){

);
echo "\n\t---------------------------------\n
\tXNOHAT DDoS FIREWALL\n
\tVersion: 1.1\n
\t[email protected]\n
-----------------------------------\n
";

$timewindow = 60; //unit: second - a splited interval time that requests are grouped in. For example one minute have 5000 requests
$threshold = 5000; //threshold requests number per $timewindow
$ipblocklist = array();
$serverip = '125.212.250.72';
$yourip = '1.53.194.96';
$exclude_ips = array($serverip,
$yourip,

while(true){
'1.53.194.96',

exec('iptables -F BLOCKEDIP'); //flush chain rules
exec("iptables-save | grep -v -- '-j BLOCKEDIP' | iptables-restore"); // delete all rules related to chain
exec('iptables -X BLOCKEDIP'); //delete chain
);

$timewindow = 60; //unit: second - a splited interval time that requests are grouped in. For example one minute have 5000 requests
$threshold = 100; //threshold requests number per $timewindow

$sleeptime = 10; //unit: second - sleep between log check

$ipblocklist = array();

//exec('iptables -F BLOCKEDIP'); //flush chain rules
//exec("iptables-save | grep -v -- '-j BLOCKEDIP' | iptables-restore"); // delete all rules related to chain
//exec('iptables -X BLOCKEDIP'); //delete chain
exec('iptables -N BLOCKEDIP'); //create chain
exec("iptables -A BLOCKEDIP -j LOG --log-level 4 --log-prefix 'blockedip'"); //LOG any packets go to this BLOCKEDIP chain
exec('iptables -A BLOCKEDIP -j DROP'); //DROP any packets go to this BLOCKEDIP chain

//copy('access_log.db','access_log_for_analysis.db');

$db = new SQLite3('access_log.db');
//$db = new SQLite3(':memory:');
$db->query("PRAGMA synchronous = OFF");
$db->query("PRAGMA journal_mode = MEMORY");
$db->query("PRAGMA busy_timeout = 300000");

//$res_count_request = $db->query('SELECT remote_ip, count(remote_ip) AS request_num FROM accesslog GROUP BY remote_ip ORDER BY request_num DESC'); //load all request in database is VERY SLOW
$res_count_request = $db->query('SELECT remote_ip, count(remote_ip) AS request_num FROM accesslog WHERE request_time BETWEEN "'.@date("Y-m-d H:i:s", time()-$timewindow).'" AND "'.@date("Y-m-d H:i:s", time()).'" GROUP BY remote_ip ORDER BY request_num DESC');
while ($row = $res_count_request->fetchArray()) {
//print_r($row);
if($row['request_num'] >= $threshold AND !in_array($row['remote_ip'],$exclude_ips)){

exec('iptables -A INPUT -s '.$row['remote_ip'].' -j BLOCKEDIP');

echo 'BLOCKED IP: '.$row['remote_ip'].' (REQ_NUM: '.$row['request_num'].")\n";
file_put_contents('blockedip.log',$row['remote_ip'].'-'.$row['request_num']."\n",FILE_APPEND);

$ipblocklist[] = $row['remote_ip'];
}
while(true){

try{

//copy('access_log.db','access_log_for_analysis.db');

$db = new SQLite3('access_log.db');
//$db = new SQLite3(':memory:');
$db->query("PRAGMA synchronous = OFF");
$db->query("PRAGMA journal_mode = MEMORY");
$db->query("PRAGMA busy_timeout = 300000");

//$res_count_request = $db->query('SELECT remote_ip, count(remote_ip) AS request_num FROM accesslog GROUP BY remote_ip ORDER BY request_num DESC'); //load all request in database is VERY SLOW
$res_count_request = $db->query('SELECT remote_ip, count(remote_ip) AS request_num FROM accesslog WHERE request_time BETWEEN "'.@date("Y-m-d H:i:s", time()-$timewindow).'" AND "'.@date("Y-m-d H:i:s", time()).'" GROUP BY remote_ip ORDER BY request_num DESC');
while ($row = $res_count_request->fetchArray()) {
//print_r($row);
if($row['request_num'] >= $threshold AND !in_array($row['remote_ip'],$exclude_ips)){

exec('iptables -A INPUT -s '.$row['remote_ip'].' -j BLOCKEDIP');

echo 'BLOCKED IP: '.$row['remote_ip'].' (REQ_NUM: '.$row['request_num'].")\n";
file_put_contents('blockedip.log',$row['remote_ip'].'-'.$row['request_num']."\n",FILE_APPEND);
file_put_contents('manualblockip.sh','iptables -A INPUT -s '.$row['remote_ip'].' -j BLOCKEDIP'."\n",FILE_APPEND);

$ipblocklist[] = $row['remote_ip'];
}
}

removeDuplicateIptablesRules();

$db->close();

echo "SLEEP IN $sleeptime seconds\n";
sleep($sleeptime);

} catch(Exception $error) {
//do nothing
}

}

}

function removeDuplicateIptablesRules(){
exec('iptables-save',$arr_iptables_save_output);
foreach($arr_iptables_save_output as $k=>$v) {
if( ($kt=array_search($v,$arr_iptables_save_output)) !== FALSE AND $k!=$kt AND strstr($v,'-A') !== FALSE ){
unset($arr_iptables_save_output[$kt]);
}
}

$db->close();
$removed_duplicate_iptables_rules = implode("\n", $arr_iptables_save_output);
file_put_contents('removed_duplicate_iptables_rules.txt', $removed_duplicate_iptables_rules);
exec('iptables -F'); // Clear all rules
exec('iptables-restore < removed_duplicate_iptables_rules.txt');
echo "Removed Duplicate Rules from IPTables\n";
}

//function for fatal error case
function fatal_handler() {
$errfile = "unknown file";
$errstr = "shutdown";
$errno = E_CORE_ERROR;
$errline = 0;

$error = error_get_last();

echo "SLEEP IN $timewindow seconds\n";
sleep($timewindow);
if( $error !== NULL) {
$errno = $error["type"];
$errfile = $error["file"];
$errline = $error["line"];
$errstr = $error["message"];

main();
}
}

?>
123 changes: 74 additions & 49 deletions logparser.php
Original file line number Diff line number Diff line change
@@ -1,63 +1,88 @@
<?php

$logfile = '/var/log/nginx/access.log';

unlink('access_log.db');

$db = new SQLite3('access_log.db');
//$db = new SQLite3(':memory:');
$db->query("PRAGMA synchronous = OFF");
$db->query("PRAGMA journal_mode = MEMORY");
$db->query("PRAGMA busy_timeout = 300000");

//Check log table exist or not
$res_check_table_exist = $db->query("SELECT * FROM sqlite_master WHERE name = 'accesslog' and type='table' ");
if(!$res_check_table_exist->fetchArray()){ // Not have table accesslog
//echo "Table Not exist";
//Create Table accesslog
$db->exec('CREATE TABLE accesslog (remote_ip varchar(255), request_time NUMERIC)');
$db->exec("CREATE INDEX accesslog_index ON accesslog(remote_ip,request_time)");
echo "Table accesslog has been created \r\n";
}
register_shutdown_function( "fatal_handler" );

main();

function main(){
$logfile = '/var/log/nginx/access.log';

unlink('access_log.db');

//Follow Log
$size = filesize($logfile); //set to current file size to move disk read cursor to end of file
while (true) {
clearstatcache();
$currentSize = filesize($logfile);
if ($size == $currentSize) {
usleep(100);
continue;
$db = new SQLite3('access_log.db');
//$db = new SQLite3(':memory:');
$db->query("PRAGMA synchronous = OFF");
$db->query("PRAGMA journal_mode = MEMORY");
$db->query("PRAGMA busy_timeout = 300000");

//Check log table exist or not
$res_check_table_exist = $db->query("SELECT * FROM sqlite_master WHERE name = 'accesslog' and type='table' ");
if(!$res_check_table_exist->fetchArray()){ // Not have table accesslog
//echo "Table Not exist";
//Create Table accesslog
$db->exec('CREATE TABLE accesslog (remote_ip varchar(255), request_time NUMERIC)');
$db->exec("CREATE INDEX accesslog_index ON accesslog(remote_ip,request_time)");
echo "Table accesslog has been created \r\n";
}

$fh = fopen($logfile, "r");
fseek($fh, $size);

while ($line = fgets($fh)) {

// process the line read.
if($line <> ''){
//-----Clear wasted character-----
$clear_char = array('[',']');
$line = str_replace($clear_char,'',$line); //strip special chars

//-----Parse Log Line-----
$arr_log_line = explode(' ',$line);
//var_dump($arr_log_line);continue;
$remote_ip = $arr_log_line[0];
$request_time = @date("Y-m-d H:i:s", @strtotime(str_replace('/', '-', substr_replace($arr_log_line[3], ' ', -9,1)))); //original nginx time look like 05/Nov/2016:01:35:24 , remember change for apache , SQLite format must look like 2016-11-05 01:35:24
$db->exec('INSERT INTO accesslog (remote_ip, request_time) VALUES ("'.$remote_ip.'","'.$request_time.'")'); //insert request to DB
//echo $remote_ip.' - '.$request_time."\r\n";
echo $line;
//Follow Log
$size = filesize($logfile); //set to current file size to move disk read cursor to end of file

while (true) {

clearstatcache();
$currentSize = filesize($logfile);
if ($size == $currentSize) {
usleep(100);
continue;
}

$fh = fopen($logfile, "r");
fseek($fh, $size);

while ($line = fgets($fh)) {

// process the line read.
if($line <> ''){
//-----Clear wasted character-----
$clear_char = array('[',']');
$line = str_replace($clear_char,'',$line); //strip special chars

//-----Parse Log Line-----
$arr_log_line = explode(' ',$line);
//var_dump($arr_log_line);continue;
$remote_ip = $arr_log_line[0];
$request_time = @date("Y-m-d H:i:s", @strtotime(str_replace('/', '-', substr_replace($arr_log_line[3], ' ', -9,1)))); //original nginx time look like 05/Nov/2016:01:35:24 , remember change for apache , SQLite format must look like 2016-11-05 01:35:24
$db->exec('INSERT INTO accesslog (remote_ip, request_time) VALUES ("'.$remote_ip.'","'.$request_time.'")'); //insert request to DB
//echo $remote_ip.' - '.$request_time."\r\n";
echo $line;
}

}

fclose($fh);
$size = $currentSize;
}

fclose($fh);
$size = $currentSize;
$db->close();
}
//function for fatal error case
function fatal_handler() {
$errfile = "unknown file";
$errstr = "shutdown";
$errno = E_CORE_ERROR;
$errline = 0;

$error = error_get_last();

$db->close();
if( $error !== NULL) {
$errno = $error["type"];
$errfile = $error["file"];
$errline = $error["line"];
$errstr = $error["message"];

main();
}
}

?>

0 comments on commit b09424a

Please sign in to comment.