5 # This include() script implements anti-leech and anti-bot functionality,
6 # and can probably be used with any web site, and is especially not tied
7 # to ewiki. Its approach isn't proxy friendly, and therefore will likely
8 # knock out AOL users and the like.
9 # This script can be used concurrently on a shared webserver (common for
10 # nowadays web space providers), because the the version numbers protect
11 # from broken lock data - and after all sharing the data only can benefit
12 # this protection system.
14 # You can knock out a user (if you detect unwanted behaviour) by just
15 # calling site_prot(+1); from anywhere in yoursite.
18 function site_prot($bad_behaviour_detected=0) {
21 $max_hits = 1000; # absolute hit-limit per IP
22 $rm_stale_locks = 120; # seconds, after which lock files invalidate
23 $delay = 3; # request slow down time (bot brake)
24 $a_ratio = 5/1; # max allowed accesses per second
25 $ignore_humans = 1; # humans may perform all requests
26 $friends="/|127.0.0.1|216.239.*.*|64.68.*.*|204.123.*.*|204.152.*.*|128.177.*.*||";
28 #-- bots rarely send Cookies, and also avoid the POST request method
29 $not_a_bot = count($_COOKIE)
30 || ($_SERVER["REQUEST_METHOD"] == "POST");
32 #-- this allows us to ignore non-ewiki-page-requests
33 $ignore_hit = (@$_REQUEST["binary"]) // image and _BINARY database entries
34 || (@$_REQUEST["q"]) // PowerSearch
35 || (@$_REQUEST["**************"]);
40 #-- directory for lock files
41 (defined("EWIKI_TEMP") and ($tmp=EWIKI_TEMP))
42 or ($tmp = @$_SERVER["TEMP"]) or ($tmp = @$_SERVER["TEMP_DIR"])
44 $tmp .= "/site_prot/";
45 if (!file_exists($tmp)) {
50 ($ip = $_SERVER["REMOTE_ADDR"])
51 or ($ip = $_SERVER["X_FORWARDED_FOR"]); # or even start traceroute here?
52 $half_ip = substr($ip, 0, @strpos($ip, ".", 4)); # (incorrect, but works for the default $friends list)
53 if (strpos($friends, "|$ip|") || strpos($friends, "|$half_ip.*.*|")) {
58 $lockfile = $tmp . strtr($ip, ":", "+");
61 time(), // last_modified
62 time(), // creation_time
66 $data[3] |= ((int)$bad_behaviour_detected);
67 $data[4] |= ($not_a_bot?1:0);
69 #-- read info about guest
70 if (file_exists($lockfile)) {
71 $last_access = filemtime($lockfile);
72 $first_access = filectime($lockfile);
74 #-- remove old lockfile
75 if (($ignore_humans && $not_a_bot) || (@$_REQUEST["site_prot_unlock"])
76 || ($last_access + $rm_stale_locks < time())) {
81 #-- read-in and update data
82 if ($f = fopen($lockfile, "r+")) {
83 if ($data = unserialize(fread($f, 65536))) {
86 $data[4] |= ($not_a_bot?1:0);
88 fwrite($f, serialize($data));
93 #-- keep annoying the bad guys
95 site_prot_trap($delay << 1);
98 #-- check for too many requests,
99 # lockfile usually were already deleted after that many requests
100 # (this is the proxy trap)
101 if ($data[0] >= $max_hits) {
102 site_prot_trap($delay);
105 #-- ignore following checks for humans
106 if ($ignore_humans && $data[4]) {
110 #-- too many requests per time,
111 # measured according to the time slice the current lockfile exists
112 if ($data[0] > ($data[1]-$data[2]) / $a_ratio) {
113 site_prot_trap($delay);
119 if ($f = fopen($lockfile, "w")) {
120 fwrite($f, serialize($data));
131 #-- called if we want to stop the client
132 function site_prot_trap($delay=3) {
134 #-- we want to slow down the bot, but not ourselfes
135 ignore_user_abort(0);
138 #-- disable any establish output buffering
139 if (function_exists("ob_end_clean")) {
140 while (function_exists("ob_get_level") && ob_get_level() || ob_get_length()) {
145 #-- send out a warning message for humans (to also allow for lock removal)
147 <!--[site_prot_trap()]-->
149 Your <a href="http://google.com/search?q=IP+address">IP</a>
150 has been locked and you cannot make further<br>
151 requests to this site.<br>
153 <form action="{$_SERVER[REQUEST_URI]}" method="POST" enctype="application/x-www-form-urlencoded">
154 <input type="checkbox" name="site_prot_unlock" value="true"> No, please
155 <input type="submit" name="site_prot_unlock_button" value="unlock me!!">
160 #-- should we flood our syslog here?
165 #-- slow down the bot, and exit the script