最近のSPAMの量は半端じゃありません。ほとんどDDoSレベルです。
こんなのをまともに処理してたら、CPU帯域がいくらあっても足りないので、Apacheレベルで拒否できるmod_access_rblを導入してみました。
参考記事 http://www.rbl.jp/bbstbspam.html
とりあえず、このサイトに仕掛けてみました。ProtectorのログとApacheのerrorログを付き合わせることで、どれくらい有効かがわかると思います。
そのmod_access_rblのオリジナルはここです。(Apache1.3用のパッチ)
http://www.blars.org/mod_access_rbl.html
…が、なぜか記事が消えてます。
私はあえてApache1.3を利用しているのですが、ネットを探しても見つかるのはこれをベースに、Apache2.0用に書き換えたものばかりです。
仕方がないので、そのApache2バージョンを元に、再度1.3用に書き換えてみました。
移植の再移植なので、質が落ちている可能性は大です。特に私自身、Cのプログラムを書くのが本当に久しぶりで、変数の頭に$をつけたり、文字列を代入しちゃったりで、コンパイルエラーでまくりでした
もしオリジナルのdiffが見つかったらそちらを利用するべきでしょう。
#Apache用のmodって実はけっこうコード量が少ないんですね。mod_xoops.c なんかも簡単に書けるのかもしれません。
*** mod_access.c.orig Thu Mar 14 06:05:33 2002
--- mod_access.c Fri Feb 9 06:29:57 2007
***************
*** 61,66 ****
--- 61,67 ----
*
* Module derived from code originally written by Rob McCool
*
+ * 'via' mods to handle RBL style dns lookup by blarson@blars.org
*/
#include "httpd.h"
***************
*** 74,79 ****
--- 75,81 ----
T_ALL,
T_IP,
T_HOST,
+ T_VIA,
T_FAIL
};
***************
*** 150,157 ****
allowdeny *a;
char *s;
! if (strcasecmp(from, "from"))
! return "allow and deny must be followed by 'from'";
a = (allowdeny *) ap_push_array(cmd->info ? d->allows : d->denys);
a->x.from = where;
--- 152,168 ----
allowdeny *a;
char *s;
! if (!strcasecmp(from, "via")) {
! if (strlen(where) > 80)
! return "'via' location limited to 80 characters";
! a = (allowdeny *) ap_push_array(cmd->info ? d->allows : d->denys);
! a->limited = cmd->limited;
! a->type = T_VIA;
! a->x.from = where;
! return NULL;
! }
! else if (strcasecmp(from, "from"))
! return "allow and deny must be followed by 'from' or 'via'";
a = (allowdeny *) ap_push_array(cmd->info ? d->allows : d->denys);
a->x.from = where;
***************
*** 292,297 ****
--- 303,350 ----
return 0;
}
+ static int check_via(request_rec *r, const char *via_list)
+ {
+ char hb[100];
+ char *ha, *s, *sb, *sc;
+ int ret = OK;
+
+ /* take the network address, convert to ascii, reverse the order of
+ * the numbers, tack on the rbl-style list to search, add a period
+ * at the end if there isn't one already, and see if it's listed */
+ /* perhaps caching results would be a good idea */
+
+ ha = r->connection->remote_ip;
+ s = ha + strlen(ha);
+ sb = hb;
+ while (--s != ha) {
+ if (*s == '.') {
+ sc = s;
+ while (*++sc != '.' && *sc) *sb++ = *sc;
+ *sb++ = '.';
+ }
+ }
+ sc = s;
+ while (*sc != '.' && *sc) *sb++ = *sc++;
+ *sb++ = '.';
+ sc = (char *)via_list;
+ while (*sb++ = *sc++) ;
+ if (sb[-2] != '.') {
+ sb[-1] = '.';
+ *sb = '\0';
+ }
+ if (gethostbyname(hb) != NULL)
+ ret = FORBIDDEN;
+ else
+ ret = OK;
+
+ if (ret == FORBIDDEN){
+ ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
+ "looking up %s\n", hb);
+ }
+ return ret;
+ }
+
static int find_allowdeny(request_rec *r, array_header *a, int method)
{
allowdeny *ap = (allowdeny *) a->elts;
***************
*** 337,342 ****
--- 390,400 ----
return 1;
break;
+ case T_VIA:
+ if (check_via(r, ap[i].x.from))
+ return 1;
+ break;
+
case T_FAIL:
/* do nothing? */
break;