用mod_limitipconn模組控管http連線
Tue, 30 Oct 2007 12:41:55 +0800最近在思考如何控管httpd伺服器,來減少spam機器人灌水的效率,結果找到了一個叫做mod_limitipconn的模組。這個模組支援apache httpd-2.0以及httpd-2.2,透過修改一下httpd的原始碼,還可以讓他偵測X-Forwarded-For檔頭中的ip資訊,以分辨透過同一個ip當作proxy過來的不同連線。
套件的網址:http://dominia.org/djao/limitipconn2.html,裡面有簡單的說明、與下載的連結等,也有預先編譯好的win32模組。
透過他內建的diff檔案來patch過httpd以後重新編譯,很順利。接著只要依照mod_limitipconn中的說明,編譯安裝,修改httpd.conf設定,就可以使用。
根據說明,mod_limitipconn支援幾個設定:
- MaxConnPerIP這是每個ip最大可同時連接的數量
- NoIPLimit指定要排除限制的內容種類(mime type)
- OnlyIPLimit指定只要限制的內容種類(mime type)
要注意的是,他只能以per location的方式做設定,所以至少要有:
<Location /> MaxConnPerIP 1 </Location>
類似的設定才會發生作用。
寫了一個小程式測試一下:
<html> <body> <script> var errlink=0; var successlink=0; var starttime = 0; function test() { try { errlink=0; successlink=0; var count = document.getElementById('testn').value; starttime = (new Date()).getTime(); for (var i=0; i<count; i++) { (new ajax('test.php')).run(); } }catch(e){alert(e);} } function xmlhttp() { try{return new XMLHttpRequest();} catch(e){} try{return new ActiveXObject("Msxml2.XMLHTTP");} catch(e){} try{return new ActiveXObject("Microsoft.XMLHTTP");} catch(e){} alert("XMLHttpRequest Object not existed!!"); return null; } function ajax (url) { this.url = url; this.xmlhttp = xmlhttp(); var ajaxinst = this; this.xmlhttp.onreadystatechange = function () { try { if (ajaxinst.xmlhttp.readyState == 4) { if (ajaxinst.xmlhttp.status == 200) { successlink += 1; } else { errlink += 1; } } var obj = document.getElementById("panel"); obj.innerHTML = "successlink: " + successlink + "
errlink: " + errlink + "
time: " + ((new Date()).getTime() - starttime)/1000; }catch(e){alert(e);} }; this.run = function () { this.xmlhttp.open("POST",this.url,true); this.xmlhttp.send(""); } } </script> <input type="text" id="testn" name="testn"><input type="button" value="linking" onclick="test();"> <div id="panel"></div> </body> </html>
果然,在沒啟用mod_limitipconn模組前,都可以順利連線,但是開啟限制後,就會有錯誤出現。(ie7為了提昇速度,如果用GET方法,預設會直接取cache的資料,所以測不出結果。後來改成POST就可以看到效果了。Firefox沒有這個問題。另外,ie7也支援了原生的XMLHttpRequest,不再依賴msxml了。)
考慮到一般的spam comment,應該會用post的方式把資料送到伺服器(伺服器的php應該也會這樣設計),所以接著想在mod_limitipconn加上只攔阻POST而不攔阻GET的功能試試看。
在mod_limitipconn.c的程式原始碼裡面,有用到很多request_rec這個資料結構,找了一下httpd的原始碼,在include/httpd.h裡面找到了定義。在這個資料結構裡面,有一個叫做method_number的成員(型別為int)。嗯嗯,就拿來用用看。
接著在mod_limitipconn.c裡面找到
static int limitipconn_handler(request_rec *r)
if (cfg->limit == 0) { return OK; }
if (r->method_number == M_GET) { return OK; }
重新編譯模組後,再用剛剛的程式測試一下。果然可以:)。用GET方法就不會發生錯誤。如果用POST方法,他依舊會限制連線數。不過說限制,也只是減緩他的速度,並不是把他的spam comment真的擋掉:(
mod_limitipconn這個模組有一個問題,就是只能偵測位於proxy(而且必須帶有X-Forwarded-For檔頭)之後的機器,在NAT之後的機器沒辦法,都會被當成同一個ip擋下來。也許透過mod_usertrack模組,利用cookie的方式可以做限制?有機會再來試試。