mod_rpaf のかわりに mod_extract_forwarded なるものがあるらしい

今作っているウェブアプリでは

-+(A) Apache 2.2 + mod_proxy (画像等のスタティックコンテンツ向け)
 +(B) Apache 2.2 + mod_perl  (アプリサイド)

という環境を同一ホストで動かしています。
ただ,このようにリバースプロキシを導入すると,(B) のログファイルではアクセスもとがすべて 127.0.0.1 になってしまいますし,アクセスされる IP によってアプリ上で制限を掛けたい場合,X-Forwarded-For ヘッダを自分でみて判断しなくてはいけなくなってしまい,面倒です。
このようなときに楽に対処できるのが mod_rpaf です(参考: リバースプロキシを導入する際はmod_rpaf - drk7jp)。このモジュールを使うと,Apache の Connection レコードの内容を改変してくれるので,ログには大元のアドレスが記録されますし,アプリ側から REMOTE_ADDR($r->connection->remote_addr)を参照した場合もクライアントのアドレスを取得することができます。

しかし,(B) でmod_access によってアクセス制限をかけるとうまくいかないそうです。今まで (A) でアクセス制限つけていたんで気づきませんでした。このアクセス制御もうまくやってくれるのが mod_extract_forwarded for Apache 2 だそうです(参考: http://mizzy.org/linux/mod_rpaf.html)。

ちなみに上記参考 URL で,


また、 apache 2.2 では mod_access ではなく mod_authz_host ですが、フックしているところは mod_access と全く同じなので、たぶん 2.2 でも同じことでしょう。
と書いてありますが,Apache 2.2 での mod_proxy の scheme_handler のフック API がちょっと変更になっているので,Apache 2.2 ではおそらく動きません。

--- mod_extract_forwarded.c.orig	2004-03-09 00:27:36.000000000 +0900
+++ mod_extract_forwarded.c	2007-04-18 10:27:08.945045803 +0900
@@ -758,7 +758,7 @@
     {
         if (conf->debug == MEF_DEBUG_ON) 
         {
-            fprintf(stderr,"MEF: phase:%s, $s not acceptabler proxy, %s\n", 
+            fprintf(stderr,"MEF: phase:%s, %s not acceptabler proxy, %s\n", 
                     phase, conn->remote_ip, r->unparsed_uri);
             fflush(stderr);
         }
@@ -925,6 +925,9 @@
  * spoof one) is added to the X-Forwarded-For header.
  */
 static int mef_before_proxy_http(request_rec *r, 
+#if AP_SERVER_MINORVERSION_NUMBER >= 2
+                                 proxy_worker *worker,
+#endif
                                  proxy_server_conf *pconf,
                                  char *url, const char *proxyname, 
                                  apr_port_t proxyport)

このようなパッチを当てて対処しています(ついでに critical じゃないバグもつぶしてあります)。これで mod_rpaf のように動くことは確認済ですが,何を隠そう前述したように (A) の側で mod_access ベースのアクセス制限をかけているんで,一番重要なアクセス制御まわりの機能がうまく動くかは謎です。

もひとつ注意点としては↑にからむ話ですが,(B) の側で mod_proxy を(スタティックにしろ DSO にしろ)組み込んで「いない場合」,ソースを書き換えなくてはいけません。

#define USING_proxy_http_module 1 

となっているところを(0 にするのではなく)「コメントアウト」してください。って大元のサイトにも書いてありますが。
また逆に mod_proxy も一緒に組み込んでいる場合,mod_extract_forwarded より先に mod_proxy を LoadModule するように設定ファイルを書く必要があります。このへんあんまりスマートじゃないなぁという印象です(Win32 の GetProcAddress() のようなコーディング方法ってないんでしょうか)。


設定ファイルの書き方ですが,上記の例で mod_rpaf の場合,

RPAFenable On
RPAFsethostname Off
RPAFproxy_ips 127.0.0.1

としてたところを

MEForder refuse,accept
MEFrefuse all
MEFaccept 127.0.0.1

のように書きます。って,あ,RPAFsethostname On のような機能はないわけか。そういう機能が欲しい場合は,プロキシ側で対処する(例: http://blog.woremacx.com/2006/02/proxypreservehost.html)必要がありますね。