Skip to content

Commit

Permalink
Release v1.1
Browse files Browse the repository at this point in the history
  • Loading branch information
xnohat committed Nov 5, 2016
0 parents commit a73654d
Show file tree
Hide file tree
Showing 4 changed files with 197 additions and 0 deletions.
64 changes: 64 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
---------------------------------

XNOHAT DDoS FIREWALL

Version: 1.1

xnohat@gmail.com

-----------------------------------

INSTRUCTION

Notes:

For CentOS only, modify yourself for other distros

/!\ Must do: Stop all Web/HTTPD Services and Database Services for free resources first

[!] Recommend:
+ Using this firewall script on your reverse proxy
+ Block all traffic to your main (upstream) server except traffic from Reverse Proxy
+ Implement DNS Round robin with multiple reverse proxies to reduce DDoS load first
+ Contact ISP to upgrade your server BANDWIDTH, RAM, CPU, HDD to maximum of your budget first. I suggest: 4-8 Cores CPU, 16-32 GB RAM, 50 GB SSD, Port 1Gbps NIC Bandwidth

Step-by-step

$ yum install epel-release

$ yum install nload tmux

$ yum install php php-pdo

[+] Setting $logfile variable in logparser.php to path to your access.log

[+] Modify logparser.php to match your access log format ( we need parse "ip of request" and "time of request" ), especially time of request must change to match SQLite time format look like 2016-11-05 01:35:24
Example log line from nginx:
180.93.103.169 - - [05/Nov/2016:03:19:12 +0700] "GET / HTTP/1.0" 200 148608 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US)" "-"

[+] Modify analyser.php, setting $threshold as number of request per $timewindow , any ip over this threshold will be
block by iptables

To get right Threshold for DDoS attacking you, do step below

+ Use tcpdump to get packets attacking you $ tcpdump -vvvv -i <your_interface> -w <file_name.pcap>
+ Open .pcap file in Wireshark:
+ go to Edit -> Preference set:
* "Show burst count for item rather than rate" set Enabled (check mark in the box)
* set Burst rate resolution = Burst rate window size = 60000 miliseconds (1 min)
+ Go Statistic -> ipv4 -> all addresses: burst rate is number of packets per minute, use average numbers (just guess!) to Threshold

---------

$ chmod +x ./xnohatddosfirewall/runddosfirewall.sh

$ chmod 777 ./xnohatddosfirewall

Run script with sudo or root privilege: sudo ./runddosfirewall.sh
follow guide on screen

Press "Ctrl-b d" : to detach tmux

Re-attach tmux by command $ tmux attach -t 0

Start all your services again
62 changes: 62 additions & 0 deletions analyser.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?php

echo "\n\t---------------------------------\n
\tXNOHAT DDoS FIREWALL\n
\tVersion: 1.1\n
\txnohat@gmail.com\n
-----------------------------------\n
";

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

'1.53.194.96',

);

$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();

while(true){

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'];
}
}

$db->close();

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

}

?>
63 changes: 63 additions & 0 deletions logparser.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<?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";
}

//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;
}

$db->close();


?>
8 changes: 8 additions & 0 deletions runddosfirewall.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/bin/sh
tmux new-session -n 'xnohatDDoSFirewall' -d 'echo -e "Press Ctrl-b LEFT to move Cursor to this panel\nRun Command: php analyser.php"; bash -i' #create window with 1st panel
tmux split-window -h -p 50 'nload; bash -i' #split window horizon to 50%
tmux split-window -v -p 70 'top; bash -i' #split 'new created previous panel' to 2 panel with new create panel is 60% of previous panel
tmux split-window -v -p 40 'php logparser.php; bash -i' #split previous created panel to 2 panel with new create panel is 30% of previous panel
#tmux select-pane -t +1 #move focus to 1st panel
#tmux send-keys 'top; bash -i' Enter #run some command in 1st panel
tmux -2 attach-session -d

0 comments on commit a73654d

Please sign in to comment.