Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
158 changes: 71 additions & 87 deletions analyser.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,105 +2,89 @@
define('BASEPATH', __DIR__ . DIRECTORY_SEPARATOR);
require_once BASEPATH . 'config.php';
require_once BASEPATH . 'init.php';

main();

function main() {

register_shutdown_function('fatal_handler');

echo "\n\t---------------------------------\n
register_shutdown_function('fatal_handler');
echo "\n\t---------------------------------\n
\tXNOHAT DDoS FIREWALL\n
\tVersion: " . VERSION . "\n
\txnohat@gmail.com\n
-----------------------------------\n
";

$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

while (true) {

try {

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

$db = new SQLite3(DB_FILE);
//$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() - TIME_WINDOW) . '" 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'] . '/' . TIME_WINDOW . " seconds)\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'];
setupFirewall();
while (true) {
try {
$db = new SQLite3(DB_FILE);
$db->query('PRAGMA synchronous = OFF');
$db->query('PRAGMA journal_mode = MEMORY');
$db->query('PRAGMA busy_timeout = 300000');
$start = date("Y-m-d H:i:s", time() - TIME_WINDOW);
$end = date("Y-m-d H:i:s", time());
$query = '
SELECT remote_ip, COUNT(remote_ip) AS request_num
FROM accesslog
WHERE request_time BETWEEN "' . $start . '" AND "' . $end . '"
GROUP BY remote_ip
ORDER BY request_num DESC
';
$res_count_request = $db->query($query);
while ($row = $res_count_request->fetchArray(SQLITE3_ASSOC)) {
$ip = $row['remote_ip'];
$requestNum = (int)$row['request_num'];
if ($requestNum >= THRESHOLD && shouldBlockIp($ip)) {
blockIp($ip);
echo 'BLOCKED IP: ' . $ip . ' (REQ_NUM: ' . $requestNum . '/' . TIME_WINDOW . " seconds)\n";
file_put_contents('blockedip.log', $ip . '-' . $requestNum . "\n", FILE_APPEND);
file_put_contents('manualblockip.sh', 'ipset add XNOHAT_BLOCKED ' . escapeshellarg($ip) . " timeout 3600 -exist\n", FILE_APPEND);
}
}
$db->close();
echo 'SLEEP IN ' . SLEEP_TIME . " seconds\n";
sleep(SLEEP_TIME);
} catch (Exception $error) {
echo "ERROR: " . $error->getMessage() . "\n";
sleep(SLEEP_TIME);
}
}

removeDuplicateIptablesRules();

$db->close();

echo 'SLEEP IN ' . SLEEP_TIME . "seconds\n";
sleep(SLEEP_TIME);

}
catch (Exception $error) {
//do nothing
}
function setupFirewall() {
exec('ipset create XNOHAT_BLOCKED hash:ip timeout 3600 -exist');
exec('ipset create XNOHAT_WHITELIST hash:ip -exist');
exec('iptables -N XNOHAT 2>/dev/null');
exec('iptables -F XNOHAT');
exec('iptables -A XNOHAT -m set --match-set XNOHAT_WHITELIST src -j RETURN');
exec('iptables -A XNOHAT -m set --match-set XNOHAT_BLOCKED src -j LOG --log-prefix "xnohat-blocked " --log-level 4');
exec('iptables -A XNOHAT -m set --match-set XNOHAT_BLOCKED src -j DROP');
exec('iptables -A XNOHAT -j RETURN');
exec('iptables -C INPUT -j XNOHAT 2>/dev/null || iptables -I INPUT 1 -j XNOHAT');
}
function shouldBlockIp($ip) {
global $exclude_ips;
if (!filter_var($ip, FILTER_VALIDATE_IP)) {
return false;
}
if (in_array($ip, $exclude_ips)) {
return false;
}

}

$safeIp = escapeshellarg($ip);
exec("ipset test XNOHAT_WHITELIST $safeIp >/dev/null 2>&1", $out, $code);
if ($code === 0) {
return false;
}
return true;
}

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 strpos($v, '-A') !== FALSE) {
unset($arr_iptables_save_output[$kt]);
function blockIp($ip) {
if (!filter_var($ip, FILTER_VALIDATE_IP)) {
return;
}
}

$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";
$safeIp = escapeshellarg($ip);
exec("ipset add XNOHAT_BLOCKED $safeIp timeout 3600 -exist");
}

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

$error = error_get_last();

if (!is_null($error)) {
$errno = $error['type'];
$errfile = $error['file'];
$errline = $error['line'];
$errstr = $error['message'];

main();
}
$error = error_get_last();
if (!is_null($error)) {
echo "FATAL ERROR: {$error['message']} in {$error['file']} on line {$error['line']}\n";
exit(1);
}
}

?>
?>