Execute every 3 seconds cron job PHP script
<?php
$banlog = file("bans.t开发者_运维百科xt");
foreach($banlog as $ip) {
exec("iptables -I INPUT -s $ip -j DROP");
}
$fp = fopen("bans.txt", "w");
fwrite($fp,"");
fclose($fp);
?>
With .htaccess I don't like how users only get the access denied when they are "deny from $ip"
I like using iptables but I don't want to login my server everytime to block someone from connecting. So my php script above I want to execute it every 3 seconds instead of the limited 1 minute cron tab. To do so I need to create a controlled loop to execute every 3 seconds, 20 times.
What would the best way to do this? My script runs in milliseconds.
Use RewriteMap directive from Apache's mod_rewrite (RewriteModule) to achieve a dynamic file based IP blacklisting/white listing.
Examples here:
https://wiki.koumbit.net/ApacheBlacklisting
http://www.debian-administration.org/articles/283
Using your cron, just update the blacklist text file. No need to call iptable. (Please note, you DO NOT need to restart Apache for using RewriteMap based black/white listing)
Reading a file with potentially hundreds or thousands of lines and running an iptable command on every one of them every three seconds is insane - it's bound to put unbearable strain on your server, and cause unpredictable behaviour if two of the three-second jobs interfere with each other while reading the file.
Why not call iptables
once every time you actually add something to the bans.txt
file?
Maybe you should come at this from a different direction - why are they being banned? Is there something like fail2ban you should be using instead?
However, this is also bad - anyone visiting your site from behind a company firewall will all share the same IP, so you'll be banning an entire company not just an individual.
Solution 1; Your code has a race condition where two threads could read and write to the same file simultaneously, which would be bad since it could corrupt your IPTABLES setup. If you insist on doing this, exclusive-lock the the bans.txt file before processing the entries.
$banlogFp = fopen("bans.txt","a+"); // open for r+w
$tnow = time();
//loop until have lock, or 2 seconds elapsed
//(since will be invoked again after 3 sec)
while (!flock("bans.txt") && (time() - $tnow < 2) {
$banlogTxt = fread($handle, filesize($filename));
$banlogTxt = preg_replace('/\.\\r\\n/m', '@\n', $s); //any CRLF to LF
$banlog = explode("\n", $banlogTxt); //Convert to array, splittng on LF
foreach($banlog as $ip) {
//validate $ip is numeric - don't want malicious hacker to break IPTABLES
if (preg_match("/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/",$ip+)) {
exec("iptables -I INPUT -s $ip -j DROP");
}
}
ftruncate($banlogFp, 0);
fclose($banlogFp);
}
Solution 2; You don't need to use the "Deny from aaa.bbb.ccc.ddd" command in .htaccess, instead you can use a rewrite rule to point them to any page of your choosing. Much safer than modifying IPTABLES, but still has the big-stick problem of banning other individuals sharing the IP address. E.g.
SetEnvIf REMOTE_ADDR 192.12.131.1 REDIR="redir"
SetEnvIf REMOTE_ADDR 192.12.131.2 REDIR="redir"
SetEnvIf REMOTE_ADDR 192.12.131.3 REDIR="redir"
RewriteCond %{REDIR} redir
RewriteRule ^/$ /you_are_banned.html
Solution 3 (best!); Don't allow anyone to post to your site unless they've registered a username + password, then just ban the username, not the IP address. Use a database like MySQL to store users and passwords, and a flag to say if they're banned.
精彩评论