用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支援幾個設定:

  1. MaxConnPerIP這是每個ip最大可同時連接的數量
  2. NoIPLimit指定要排除限制的內容種類(mime type)
  3. 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的方式可以做限制?有機會再來試試。