mod_limitipconnの制限内容の落とし穴

かなり有名なmod_limitipconnですが、色々制限方法の記事をみていると、きっちりとその性能を説明できていないものが多い気がする。

あるディレクトリ以下又はファイルに対する同一IPからの同時接続数を制限するというのが、このモジュールの役目なんだが、大事なところが説明されていない。

例えば、よくある以下のような制限を行ったとする。

<Location /hoge>
    MaxConnPerIP 3
</Location>

多くの情報ではこの設定だと、

[warning]

http://example.jp/hoge/index.cgi等、hoge/以下へのアクセスに対して、同一IPからの同時接続数を3に制限する。

[/warning]

とかかれていることが多い。

しかし、ここには大きな落とし穴がある。

実際にモジュールのソースをみると実装方法は、apacheのscoreboardを利用していて、server_limit(×thread_limit)分の全プロセスが処理しているrequestを全て調べ、そのrequestのclientのIPを調べて数え上げることで、同一IPからのrequestを制限している。

ソースでは、ap_hook_access_checkerのfook関数内で、以下のように実装されている。

   /* Count up the number of connections we are handling right now from
    * this IP address */
   for (i = 0; i < server_limit; ++i) {
     for (j = 0; j < thread_limit; ++j) {
        ws_record = ap_get_scoreboard_worker(i, j);
        switch (ws_record->status) {
           case SERVER_BUSY_READ:
           case SERVER_BUSY_WRITE:
           case SERVER_BUSY_KEEPALIVE:
           case SERVER_BUSY_LOG:
           case SERVER_BUSY_DNS:
           case SERVER_CLOSING:
           case SERVER_GRACEFUL:
               if (strcmp(address, ws_record->client) == 0)
                   ip_count++;
               break;
           default:
               break;
       }
     }
   }

ここで、scoreboard内に保存されている、現在のrequestの処理全てに対する、client(ソースIP)を調べている。
そして、アクセスしているIPとscoreboard内のclientがマッチした場合、IPカウントをインクリメントする。

     ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
           "mod_limitipconn: vhost: %s  uri: %s  current: %d  limit: %d",
           r->server->server_hostname, r->uri, ip_count, cfg->limit);

   if (ip_count > cfg->limit) {
     ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
                   "Rejected, too many connections from this host.");
     /* set an environment variable */
     apr_table_setn(r->subprocess_env, "LIMITIP", "1");
     /* return 503 */
     return HTTP_SERVICE_UNAVAILABLE;
   } else {
       ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
                    "mod_limitipconn: OK: Passed all checks");
       return DECLINED;
   }

最終的には、IPカウントと制限設定値(cfg->limit)を比較し、超えていれば503を返す。

つまり、ここに大きな落とし穴があり、limitipconnは、上記の設定だと、

[important]

/hoge以下にアクセスした場合は、/以下の全てのアクセスを含め、同一IPから同時に3リクエストまで処理を行う

[/important]

という制限になるのだ。

例えば、/hogeとは関係ない/fugaにある動画を3本ダウンロードしており、その状態で/hogeにアクセスすると、1アクセスすらできないのである。

上記のような実装の説明をした記事がなかなかなかったため、この記事で説明しておくこととする。

「mod_limitipconnの制限内容の落とし穴」への1件のフィードバック

コメントは受け付けていません。