Saturday, March 22, 2014, 04:18 - Hardware
Posted by ELIN
大昔に買ってそのまま何にも使用していなかったMicrosoftのLifeCam VX-1000というWebcamがあるのだが、思うところがあり動かしてみることにした

しかしこれはキワモノでも何でもない至って普通のデバイスなので、Windowsなマシンに挿そうものなら勝手にドライバをインストールし、何もしないまま普通に動いてしまう
当然このようなことは誰も望んでいないので、OpenWrtのWZR-HP-AG300Hに挿すことにする

さて、最初は正しいドライバを探すところから始まる
OpenWrtのリポジトリにはkmod-video-gspca-*なものが揃ってはいるが、PCIないしPCIeスロットに挿すような見ればわかるデバイスと異なり、USBデバイスは見ただけではドライバを判別するのが困難なのでこれを調べる必要がある
http://cateee.net/lkddb/web-lkddb/USB_GSPCA.htmlによると、VX-1000はkmod-video-gspca-sonixjであるらしいのでこれをインストール

次に動作確認としてOpenWrt上でWebcamからデータを取り出してみる
これはmjpg-streamerをインストールし
# mjpg_streamer -i "input_uvc.so -f 10 -d /dev/video0 -n" -o "output_http.so -w /www/webcam"
こう

ちなみに動かない場合は適当にパラメータを弄ると動いたりする
パラメータの詳細はここ

これでhttp://192.168.1.1とするとWebcamの映像を確認することができる

さて、対して苦労もせず動いてしまったので、次はUSB over IPを試してみる
これはどういうことかと言うと、WZR-HP-AG300Hに接続されたVX-1000をVM上のWindows XPから制御してみようというわけ

まずOpenWrtでusbip-serverをインストールし
# usbip list -l
Local USB devices
=================
- busid 2-1 (045e:00f7)
2-1:1.0 -> sonixj
2-1:1.1 -> unknown
2-1:1.2 -> unknown

# usbip bind -b 2-1
bind device on busid 2-1: complete
# usbipd -D

もしサーバサイドのログが必要なら
# usbipd -d

Windows側ではhttp://usbip.sourceforge.net/からusbip_windows_v0.2.0.0_signed.zipを入手する
そしてコントロールパネルのハードウェアの追加から落としてきたドライバを指定してデバイスを作成する

>usbip -l 192.168.1.1
とするとbindしたデバイスが見えるはずなのだが
- 192.168.1.1
usbip err: usbip_network.c: 121 (usbip_recv_op_common) recv op_common, -1
usbip err: usbip.c: 216 (query_exported_devices) recv op_common
usbip err: usbip.c: 288 (show_exported_devices) query

このような感じで見えない

サーバサイドでは
usbip: debug: usbip_network.c:149:[usbip_net_recv_op_common] version mismatch: 262 273
usbipd: debug: usbipd.c:230:[recv_pdu] could not receive opcode: 0

と出力され、バージョン不一致であることがわかる

usbip.exeのバイナリを書き換えてバージョンを誤魔化してみたりもしたが、パケットに載せるコマンド番号そのものが異なっているらしく動作しなかった
誰かわかってるやつがなんとかしてくれてないかなー、と探してみるとhttp://www.raspberrypi.org/forum/viewtopic.php?f=28&t=8858&start=25にそれっぽいバイナリを発見

結果
>usbip -l 192.168.1.1
usbip for windows ($Id$)

- 192.168.1.1
2-1: unknown vendor : unknown product (045e:00f7)
: /sys/devices/platform/ohci-platform/usb2/2-1
: (Defined at Interface level) (00/00/00)
: 0 - unknown class / unknown subclass / unknown protocol (ff/ff/ff)
: 1 - unknown class / unknown subclass / unknown protocol (01/01/00)
: 2 - unknown class / unknown subclass / unknown protocol (01/02/00)

と、出力を得る

そして接続
>usbip -a 192.168.1.1 2-1
これでデバイスマネージャにもVX-1000が見えて接続されていることがわかる

しかし何らかのデータは飛んできてはいるものの、Webcamの動作までは至っていない
真っ黒だったり、バグったjpegのようだったり、映像を正常に受け取ることができない状態だ

usbipではない別のプロダクトとしてhttps://www.virtualhere.com/もあるが、同じように動作しない
ただMicrosoft純正のアプリケーションでのみ正常に映った

恐らくだがWebcamが若干悪い気がしないでもないので、別のWebcamを入手したときに試してみることにする
ちなみにマウスなどは普通に動いてる
add comment ( 5566 views )
Wednesday, January 15, 2014, 18:13 - OS / Unix, *BSD, Solaris
Posted by ELIN
どうもDD-WRTでの需要も一定数ありそうなので、テスト環境が闇に葬られないうちに試すことにした

検証したFirmwareはr23320

DD-WRTはOpenWRTとは異なり、パッケージ管理システムは名残のようなものがあるものの、事実上存在しないと言える
従ってOpenWRTのように1パッケージとして組み込むことは不可能で、面倒な若干の手間が発生するし、綺麗に収まらない

そうなるとDD-WRTのバイナリを作成してしまうのが最もスマートだが、ここではまず力技でもなんでも動作させることを優先する

まずWebコンソールからAdministration/ManagementのJFFS2 Supportを有効にする
これはDD-WRTのシステムに書き換え可能な領域を確保するために必要で、/dev/mtdblock/3が/jffs以下に割り当てられ、ここへ書き込んだデータは再起動しても失われなくなる
これが無効だと何もできない

次にOpenWRTのリポジトリから必要になるパッケージを持ってきてインストール
# cd /tmp
# wget http://downloads.openwrt.org/attitude_adjustment/12.09/ar71xx/generic/packages/libc_0.9.33.2-1_ar71xx.ipk
# wget http://downloads.openwrt.org/attitude_adjustment/12.09/ar71xx/generic/packages/zlib_1.2.7-1_ar71xx.ipk
# wget http://downloads.openwrt.org/attitude_adjustment/12.09/ar71xx/generic/packages/libpthread_0.9.33.2-1_ar71xx.ipk
# wget http://downloads.openwrt.org/attitude_adjustment/12.09/ar71xx/generic/packages/librt_0.9.33.2-1_ar71xx.ipk
# wget http://downloads.openwrt.org/attitude_adjustment/12.09/ar71xx/generic/packages/libreadline_5.2-2_ar71xx.ipk
# wget http://downloads.openwrt.org/attitude_adjustment/12.09/ar71xx/generic/packages/libncurses_5.7-5_ar71xx.ipk
# wget http://downloads.openwrt.org/attitude_adjustment/12.09/ar71xx/generic/packages/libiconv-full_1.11.1-1_ar71xx.ipk
# ipkg install *.ipk;rm *.ipk

エラーが出るものの、何の問題もない
これらは/jffs以下に保存され、DD-WRTのシステムとは干渉しない

最後にOpenWRT用にmakeしたバイナリのインストール
# wget http://b.mikomoe.jp/download/1389215611/attach/libopenssl_1.0.1e-1_ar71xx.ipk
# wget http://b.mikomoe.jp/download/1389215570/attach/softethervpnserver_4.03-9408_ar71xx.ipk
# ipkg install *.ipk;rm *.ipk


またこの時点までの違う方法としてopkgを使用する方法もある
# cd /tmp
# wget http://downloads.openwrt.org/attitude_adjustment/12.09/ar71xx/generic/packages/opkg_618-3_ar71xx.ipk
# ipkg install *.ipk

もしかしたらこの時点で後述するlibcが必要になる状況が発生するかもしれない
(参考:http://arouter.blogspot.jp/2011/07/software-installation-on-dd-wrt.html)

opkg.confを環境にあわせて変更し
# sed -i 's/ \(\(\/[[:alnum:]-]*\)\+\)$/ \/jffs\1/' /jffs/etc/opkg.conf
実行に必要になるディレクトリの作成
# mkdir -p /jffs//var/lock/

以降のインストールはlibc依存で引っかかるが、libcはなぜかPackages.gzに含まれていないため、手動でインストールする必要がある
# opkg -f /jffs/etc/opkg.conf install http://downloads.openwrt.org/attitude_adjustment/12.09/ar71xx/generic/packages/libc_0.9.33.2-1_ar71xx.ipk

あとはOpenWRTでシェルから作業する場合と同一
# opkg -f /jffs/etc/opkg.conf update
# opkg -f /jffs/etc/opkg.conf install zlib libpthread librt libreadline libncurses libiconv-full
# rm /jffs/var/opkg-lists/*
# opkg -f /jffs/etc/opkg.conf install http://b.mikomoe.jp/download/1389215570/attach/softethervpnserver_4.03-9408_ar71xx.ipk
# opkg -f /jffs/etc/opkg.conf install http://b.mikomoe.jp/download/1389215611/attach/libopenssl_1.0.1e-1_ar71xx.ipk


そしてLD_LIBRARY_PATHを与えて実行する
LD_LIBRARY_PATHを与えない場合、/usr/lib/libssl.so.1.0.0を読みに行ってしまい、これはOpenWRTと同様にno-sha0でmakeされているため動かない
# env LD_LIBRARY_PATH=/jffs/lib:/jffs/usr/lib vpnserver start
これで正常に動作する(ように見える)

しかし動作はするものの、このままだと起動時毎回シェルからコマンドを発行しなければならないので、自動で実行できるよう設定する必要がある

WebコンソールのAdministration/Commandで
env LD_LIBRARY_PATH=/jffs/lib:/jffs/usr/lib vpnserver start
としてSave Startup
env LD_LIBRARY_PATH=/jffs/lib:/jffs/usr/lib vpnserver stop
としてSave Shutdown

これで起動時に自動的に実行され、煩わしくなくなる
1 comment ( 2325 views )
Tuesday, January 14, 2014, 17:51 - OS / Misc
Posted by ELIN
実はOpenWRTでSoftEther VPNを動かすを書いている途中に4.03.9411がリリースされてしまい、その時点で再検証を行ってはいたのだが、その内容が不穏なので別のエントリに分割することになった

さて、9411は9408のように普通にmakeできない
その原因として9408はhamcore.se2をバイナリのまま提供していたが、9411以降はこれのソースが同梱され
1. hamcorebuilderのmake
2. hamcorebuilderでhamcore.se2の作成
3. 本体のmake
という手順になった
しかしこれはhamcorebuilderもOpenWRT用にmakeされてしまい、当然2の時点でザコることになる

この問題を回避すべく色々と思案したが、結局力技で通すことにした
つまり
1. x86でmake
2. hamcore.se2の作成
3. 再度OpenWRT用のmake
とmake make clean makeというあってはいけないようなMakefileになってしまった (参照)

いつの日かhamcore.se2が爆発しそうで怖い

softethervpnserver_4.03-9411_ar71xx.ipk
softethervpnclient_4.03-9411_ar71xx.ipk
softethervpnbridge_4.03-9411_ar71xx.ipk
softethervpncmd_4.03-9411_ar71xx.ipk
1 comment ( 970 views )
Wednesday, January 8, 2014, 10:15 - OS / Misc
Posted by ELIN
先日SoftEther VPNのソースコードがようやく公開されたので早速やる

まずOpenWRTのSDK環境を用意する
OSはLinuxなら何でも良さそうだが、こういう用途は(私の中で)Debianと相場が決まっているので、DebianのVMを用意するところから始める
……が、インストールすら面倒なのでDebianベースのTurnKey Coreを使うことにした

最初に最低限度必要になるものをインストール
# apt-get install -y subversion make gcc g++ libncurses5-dev libghc-zlib-dev gawk bzip2 patch

次にSDKだが、以前横着した結果、どうでもいい地雷を踏んでしまったので、今回は最初からsvnを使う
# svn co svn://svn.openwrt.org/openwrt/tags/attitude_adjustment_12.09
# cd attitude_adjustment_12.09

このままではiconv-fullが含まれていないので
# svn export svn://svn.openwrt.org/openwrt/packages/libs/libiconv-full@29638 package/libiconv-full

さて、SoftEther VPNをmakeするときに起きる問題はUT-VPNのときと同様の問題で、大まかに
1. SoftEther VPNのmakefileがCCFLAGS/LDFLAGSを渡さない
2. Mayaqua.hのiconvに関わる部分がザコってる
3. libopensslのコンパイルオプションにno-sha0が付いている
の3点
1と2に関してはパッチで対応し、3は手動で書き換える必要がある

先に3の問題を修正する
# sed -i 's/no-sha0//' package/openssl/Makefile
次にSoftEther VPNの用意だが、UT-VPNのときと同様にSDKでパッケージできるmakefileを書いたので、特別な理由がなければそれを使えばよい
# git clone https://github.com/el1n/OpenWRT-package-softether.git package/softethervpn

そしてSDKの設定
ちなみにrootで実行しようとすると警告が出て走らない
一見FORCE=1で動きそうだが、defconfig/menuconfigは通っても後述するmakeは通らないので一般ユーザへsuする必要がある
chownも忘れずに
$ make defconfig
$ make menuconfig

設定画面でTarget Systemを必要なら変更し、Network/VPN以下のSoftEther VPNで必要なものにチェックを入れる

最後にmakeする
今回はあくまでSoftEther VPNのパッケージ化なので、OpenWRTのイメージをもmakeする必要はない
従って
$ make prepare
$ make package/softethervpn/compile V=99

と、する
それにしても時間は(本当に)相当かかる

正常に終了すれば
# find bin
bin
bin/ar71xx
bin/ar71xx/packages
bin/ar71xx/packages/terminfo_5.7-5_ar71xx.ipk
bin/ar71xx/packages/libgcc_4.6-linaro-1_ar71xx.ipk
bin/ar71xx/packages/zlib_1.2.7-1_ar71xx.ipk
bin/ar71xx/packages/libncurses_5.7-5_ar71xx.ipk
bin/ar71xx/packages/libreadline_5.2-2_ar71xx.ipk
bin/ar71xx/packages/librt_0.9.33.2-1_ar71xx.ipk
bin/ar71xx/packages/softethervpnbridge_4.03-9408_ar71xx.ipk
bin/ar71xx/packages/softethervpnserver_4.03-9408_ar71xx.ipk
bin/ar71xx/packages/libpthread_0.9.33.2-1_ar71xx.ipk
bin/ar71xx/packages/softethervpnclient_4.03-9408_ar71xx.ipk
bin/ar71xx/packages/libopenssl_1.0.1e-1_ar71xx.ipk
bin/ar71xx/packages/libc_0.9.33.2-1_ar71xx.ipk
bin/ar71xx/packages/libiconv-full_1.11.1-1_ar71xx.ipk
bin/ar71xx/packages/softethervpncmd_4.03-9408_ar71xx.ipk

このように.ipkが生成される

できたのがこちら
softethervpnserver_4.03-9408_ar71xx.ipk
softethervpnclient_4.03-9408_ar71xx.ipk
softethervpnbridge_4.03-9408_ar71xx.ipk
softethervpncmd_4.03-9408_ar71xx.ipk
libopenssl_1.0.1e-1_ar71xx.ipk
OpenWRT 12.09 ar71xx用

あとはOpenWRTへのインストールを残すのみだが、まず必要となるパッケージ
zlib
libpthread
librt
libreadline
libncurses
libiconv-full
をインストールする

そして先程makeしたlibopensslのパッケージをインストールするのだが、これがmd5sum mismatchで弾かれてしまう
これを回避するためにはシェルで
# rm /var/opkg-lists/attitude_adjustment
と、パッケージリストを一度削除し、インストールする必要がある

その後にSoftEther VPNをインストールして完了
1 comment ( 11464 views )
Tuesday, December 31, 2013, 18:04 - Misc
Posted by ELIN
Webサーバを新しく下記のような設定で組み直すことにした
<VirtualHost *:80>
DocumentRoot /var/www

RewriteEngine On
RewriteCond %{DOCUMENT_ROOT}/%{HTTP_HOST} -d
RewriteRule . %{DOCUMENT_ROOT}/%{HTTP_HOST}%{REQUEST_URI} [L]
RewriteRule . https://www.google.co.jp/search?q=%{HTTP_HOST}%{REQUEST_URI}
</VirtualHost>

要するにこれはディレクトリを掘るだけで擬似的にバーチャルホストとして運用できるようにするもので、これ自体は検索すればすぐに見つかる程度の安易な方法ではあるが、ともかくずぼらな私には好ましい方法である

しかしこれはmod_rewriteの深い闇を見る

この時点での挙動は
(2) init rewrite engine with requested uri /foo.html
(3) applying pattern '.' to uri '/foo.html'
(4) RewriteCond: input='/var/www/www.test1.com' pattern='-d' => matched
(2) rewrite '/foo.html' -> '/var/www/www.test1.com/foo.html'
(2) local path result: /var/www/www.test1.com/foo.html
(1) go-ahead with /var/www/www.test1.com/foo.html [OK]

と、何の問題もなく、期待通りの挙動をしている

しかしこの方法はhttpd.confへmod_rewriteへの設定を書けないため、特定ホストでのみ運用したいルールは.htaccessで賄う必要がある
そこで.htaccessへ下記のような設定を追加すると
RewriteEngine On
RewriteRule foo/(.*) bar/$1 [L]

(2) init rewrite engine with requested uri /foo/index.html
(3) applying pattern '.' to uri '/foo/index.html'
(4) RewriteCond: input='/var/www/www.test1.com' pattern='-d' => matched
(2) rewrite '/foo/index.html' -> '/var/www/www.test1.com/foo/index.html'
(2) local path result: /var/www/www.test1.com/foo/index.html
(1) go-ahead with /var/www/www.test1.com/foo/index.html [OK]
(3) [perdir /var/www/www.test1.com/] strip per-dir prefix: /var/www/www.test1.com/foo/index.html -> foo/index.html
(3) [perdir /var/www/www.test1.com/] applying pattern 'foo/(.*)' to uri 'foo/index.html'
(2) [perdir /var/www/www.test1.com/] rewrite 'foo/index.html' -> 'bar/index.html'
(3) [perdir /var/www/www.test1.com/] add per-dir prefix: bar/index.html -> /var/www/www.test1.com/bar/index.html
(2) [perdir /var/www/www.test1.com/] strip document_root prefix: /var/www/www.test1.com/bar/index.html -> /www.test1.com/bar/index.html
(1) [perdir /var/www/www.test1.com/] internal redirect with /www.test1.com/bar/index.html [INTERNAL REDIRECT]
(2) init rewrite engine with requested uri /www.test1.com/bar/index.html
(3) applying pattern '.' to uri '/www.test1.com/bar/index.html'
(4) RewriteCond: input='/var/www/www.test1.com' pattern='-d' => matched
(2) rewrite '/www.test1.com/bar/index.html' -> '/var/www/www.test1.com/www.test1.com/bar/index.html'
(2) local path result: /var/www/www.test1.com/www.test1.com/bar/index.html
(1) go-ahead with /var/www/www.test1.com/www.test1.com/bar/index.html [OK]
(3) [perdir /var/www/www.test1.com/] add path info postfix: /var/www/www.test1.com/www.test1.com -> /var/www/www.test1.com/www.test1.com/bar/index.html
(3) [perdir /var/www/www.test1.com/] strip per-dir prefix: /var/www/www.test1.com/www.test1.com/bar/index.html -> www.test1.com/bar/index.html
(3) [perdir /var/www/www.test1.com/] applying pattern 'foo/(.*)' to uri 'www.test1.com/bar/index.html'
(1) [perdir /var/www/www.test1.com/] pass through /var/www/www.test1.com/www.test1.com

となり、結果404が返されることになる
internal redirectによって再度httpd.confのルールが評価されるために、この問題は発生する

またこのinternal redirectによる問題は似たような別の問題も引き起こす
(2) init rewrite engine with requested uri /foo/!"#$%&'().txt
(3) applying pattern '.' to uri '/foo/!"#$%&'().txt'
(4) RewriteCond: input='/var/www/www.test1.com' pattern='-d' => matched
(2) rewrite '/foo/!"#$%&'().txt' -> '/var/www/www.test1.com/foo/!"#$%&'().txt'
(2) local path result: /var/www/www.test1.com/foo/!"#$%&'().txt
(1) go-ahead with /var/www/www.test1.com/foo/!"#$%&'().txt [OK]
(3) [perdir /var/www/www.test1.com/] strip per-dir prefix: /var/www/www.test1.com/foo/!"#$%&'().txt -> foo/!"#$%&'().txt
(3) [perdir /var/www/www.test1.com/] applying pattern 'foo/(.*)' to uri 'foo/!"#$%&'().txt'
(2) [perdir /var/www/www.test1.com/] rewrite 'foo/!"#$%&'().txt' -> 'bar/!"#$%&'().txt'
(3) [perdir /var/www/www.test1.com/] add per-dir prefix: bar/!"#$%&'().txt -> /var/www/www.test1.com/bar/!"#$%&'().txt
(2) [perdir /var/www/www.test1.com/] strip document_root prefix: /var/www/www.test1.com/bar/!"#$%&'().txt -> /www.test1.com/bar/!"#$%&'().txt
(1) [perdir /var/www/www.test1.com/] internal redirect with /www.test1.com/bar/!"#$%&'().txt [INTERNAL REDIRECT]
(2) init rewrite engine with requested uri /www.test1.com/bar/!"
(3) applying pattern '.' to uri '/www.test1.com/bar/!"'
(4) RewriteCond: input='/var/www/www.test1.com' pattern='-d' => matched
(2) rewrite '/www.test1.com/bar/!"' -> '/var/www/www.test1.com/www.test1.com/bar/!"'
(2) local path result: /var/www/www.test1.com/www.test1.com/bar/!"
(1) go-ahead with /var/www/www.test1.com/www.test1.com/bar/!" [OK]
(3) [perdir /var/www/www.test1.com/] add path info postfix: /var/www/www.test1.com/www.test1.com -> /var/www/www.test1.com/www.test1.com/bar/!"
(3) [perdir /var/www/www.test1.com/] strip per-dir prefix: /var/www/www.test1.com/www.test1.com/bar/!" -> www.test1.com/bar/!"
(3) [perdir /var/www/www.test1.com/] applying pattern 'foo/(.*)' to uri 'www.test1.com/bar/!"'
(1) [perdir /var/www/www.test1.com/] pass through /var/www/www.test1.com/www.test1.com

特定の記号を含むファイル名へのリクエストはアンエスケープされ記号へ戻るが、internal redirectの際に再度エスケープされないまま渡されるため、0x23(#)以降は不要と判断され、完全に抜け落ちている

この問題を解決するために.htaccessへ
RewriteRule ^(.*)#(.*)$ $1\%23$2 [N]
と、邪悪で安易な方法だがともかく、追記してやりたいところだがこれは非常にマズい
internal redirectの際に抜け落ちこそしなくなるものの、再度このルールが評価されるため、ループしてしまうことになる

そしてこれと同等の現象だが、このような設定をすると
RewriteRule ^((?!foo/).*) foo/$1 [L]
(2) init rewrite engine with requested uri /index.html
(3) applying pattern '.' to uri '/index.html'
(4) RewriteCond: input='/var/www/www.test1.com' pattern='-d' => matched
(2) rewrite '/index.html' -> '/var/www/www.test1.com/index.html'
(2) local path result: /var/www/www.test1.com/index.html
(1) go-ahead with /var/www/www.test1.com/index.html [OK]
(3) [perdir /var/www/www.test1.com/] strip per-dir prefix: /var/www/www.test1.com/index.html -> index.html
(3) [perdir /var/www/www.test1.com/] applying pattern '^((?!foo/).*)' to uri 'index.html'
(2) [perdir /var/www/www.test1.com/] rewrite 'index.html' -> 'foo/index.html'
(3) [perdir /var/www/www.test1.com/] add per-dir prefix: foo/index.html -> /var/www/www.test1.com/foo/index.html
(2) [perdir /var/www/www.test1.com/] strip document_root prefix: /var/www/www.test1.com/foo/index.html -> /www.test1.com/foo/index.html
(1) [perdir /var/www/www.test1.com/] internal redirect with /www.test1.com/foo/index.html [INTERNAL REDIRECT]
(2) init rewrite engine with requested uri /www.test1.com/foo/index.html
(3) applying pattern '.' to uri '/www.test1.com/foo/index.html'
(4) RewriteCond: input='/var/www/www.test1.com' pattern='-d' => matched
(2) rewrite '/www.test1.com/foo/index.html' -> '/var/www/www.test1.com/www.test1.com/foo/index.html'
(2) local path result: /var/www/www.test1.com/www.test1.com/foo/index.html
(1) go-ahead with /var/www/www.test1.com/www.test1.com/foo/index.html [OK]
(3) [perdir /var/www/www.test1.com/] add path info postfix: /var/www/www.test1.com/www.test1.com -> /var/www/www.test1.com/www.test1.com/foo/index.html
(3) [perdir /var/www/www.test1.com/] strip per-dir prefix: /var/www/www.test1.com/www.test1.com/foo/index.html -> www.test1.com/foo/index.html
(3) [perdir /var/www/www.test1.com/] applying pattern '^((?!foo/).*)' to uri 'www.test1.com/foo/index.html'
(2) [perdir /var/www/www.test1.com/] rewrite 'www.test1.com/foo/index.html' -> 'foo/www.test1.com/foo/index.html'
(3) [perdir /var/www/www.test1.com/] add per-dir prefix: foo/www.test1.com/foo/index.html -> /var/www/www.test1.com/foo/www.test1.com/foo/index.html
(2) [perdir /var/www/www.test1.com/] strip document_root prefix: /var/www/www.test1.com/foo/www.test1.com/foo/index.html -> /www.test1.com/foo/www.test1.com/foo/index.html
(1) [perdir /var/www/www.test1.com/] internal redirect with /www.test1.com/foo/www.test1.com/foo/index.html [INTERNAL REDIRECT]
(2) init rewrite engine with requested uri /www.test1.com/foo/www.test1.com/foo/index.html
(3) applying pattern '.' to uri '/www.test1.com/foo/www.test1.com/foo/index.html'
(4) RewriteCond: input='/var/www/www.test1.com' pattern='-d' => matched
(2) rewrite '/www.test1.com/foo/www.test1.com/foo/index.html' -> '/var/www/www.test1.com/www.test1.com/foo/www.test1.com/foo/index.html'
(2) local path result: /var/www/www.test1.com/www.test1.com/foo/www.test1.com/foo/index.html
...

と、同様の理由から意図しないループが発生する

さて、これらの現象が発生する悪の根源はinternal redirectにあるが、仕様上どうしてもこれを回避することはできない
従って当然internal redirectを発生させるべきではなく、間違っても.htaccess(やDirectoryディレクティブ内)でmod_rewriteを走らせないのが最善策ということで落ち着くだろう

ただよく調べてみるとこの問題を回避する方法がないわけではないらしいので、もうちょっと粘ることにした

まず書いてあるようにREDIRECT_STATUSを見ればいいらしいので
<VirtualHost *:80>
DocumentRoot /var/www

RewriteEngine On
RewriteCond %{ENV:REDIRECT_STATUS} 200
RewriteRule . - [S=100]
RewriteCond %{DOCUMENT_ROOT}/%{HTTP_HOST} -d
RewriteRule . %{DOCUMENT_ROOT}/%{HTTP_HOST}%{REQUEST_URI} [L]
RewriteRule . https://www.google.co.jp/search?q=%{HTTP_HOST}%{REQUEST_URI}
</VirtualHost>

と、した上で.htaccessは
RewriteEngine On
RewriteRule ^((?!foo/).*) foo/$1 [L]

と、する

このときの動作は
(2) init rewrite engine with requested uri /foo.html
(3) applying pattern '.' to uri '/foo.html'
(4) RewriteCond: input='' pattern='200' => not-matched
(3) applying pattern '.' to uri '/foo.html'
(4) RewriteCond: input='/var/www/www.test1.com' pattern='-d' => matched
(2) rewrite '/foo.html' -> '/var/www/www.test1.com/foo.html'
(2) local path result: /var/www/www.test1.com/foo.html
(1) go-ahead with /var/www/www.test1.com/foo.html [OK]
(3) [perdir /var/www/www.test1.com/] strip per-dir prefix: /var/www/www.test1.com/foo.html -> foo.html
(3) [perdir /var/www/www.test1.com/] applying pattern '^((?!foo/).*)' to uri 'foo.html'
(2) [perdir /var/www/www.test1.com/] rewrite 'foo.html' -> 'foo/foo.html'
(3) [perdir /var/www/www.test1.com/] add per-dir prefix: foo/foo.html -> /var/www/www.test1.com/foo/foo.html
(2) [perdir /var/www/www.test1.com/] strip document_root prefix: /var/www/www.test1.com/foo/foo.html -> /www.test1.com/foo/foo.html
(1) [perdir /var/www/www.test1.com/] internal redirect with /www.test1.com/foo/foo.html [INTERNAL REDIRECT]
(2) init rewrite engine with requested uri /www.test1.com/foo/foo.html
(3) applying pattern '.' to uri '/www.test1.com/foo/foo.html'
(4) RewriteCond: input='200' pattern='200' => matched
(1) pass through /www.test1.com/foo/foo.html
(3) [perdir /var/www/www.test1.com/] strip per-dir prefix: /var/www/www.test1.com/foo/foo.html -> foo/foo.html
(3) [perdir /var/www/www.test1.com/] applying pattern '^((?!foo/).*)' to uri 'foo/foo.html'
(1) [perdir /var/www/www.test1.com/] pass through /var/www/www.test1.com/foo/foo.html

このような結果となり、意図した挙動を示す
internal-redirectは発生してはいるものの、問題は回避されている

0x23(#)以降が抜け落ちる問題は以前解決していないものの、.htaccessにも
RewriteCond %{ENV:REDIRECT_STATUS} 200
RewriteRule . - [S=100]
RewriteRule ^(.*)#(.*)$ $1\%23$2 [N]

と、加えることでループを回避しつつ問題を解決できる
ただこれは0x23(#)の話でしかない

と、いうのは
(2) init rewrite engine with requested uri /!"#$%&'().txt
(3) applying pattern '.' to uri '/!"#$%&'().txt'
(4) RewriteCond: input='' pattern='200' => not-matched
(3) applying pattern '.' to uri '/!"#$%&'().txt'
(4) RewriteCond: input='/var/www/www.test1.com' pattern='-d' => matched
(2) rewrite '/!"#$%&'().txt' -> '/var/www/www.test1.com/!"#$%&'().txt'
(2) local path result: /var/www/www.test1.com/!"#$%&'().txt
(1) go-ahead with /var/www/www.test1.com/!"#$%&'().txt [OK]
(3) [perdir /var/www/www.test1.com/] strip per-dir prefix: /var/www/www.test1.com/!"#$%&'().txt -> !"#$%&'().txt
(3) [perdir /var/www/www.test1.com/] applying pattern '.' to uri '!"#$%&'().txt'
(4) [perdir /var/www/www.test1.com/] RewriteCond: input='' pattern='200' => not-matched
(3) [perdir /var/www/www.test1.com/] strip per-dir prefix: /var/www/www.test1.com/!"#$%&'().txt -> !"#$%&'().txt
(3) [perdir /var/www/www.test1.com/] applying pattern '^(.*)#(.*)$' to uri '!"#$%&'().txt'
(2) [perdir /var/www/www.test1.com/] rewrite '!"#$%&'().txt' -> '!"%23$%&'().txt'
(3) [perdir /var/www/www.test1.com/] add per-dir prefix: !"%23$%&'().txt -> /var/www/www.test1.com/!"%23$%&'().txt
(3) [perdir /var/www/www.test1.com/] strip per-dir prefix: /var/www/www.test1.com/!"%23$%&'().txt -> !"%23$%&'().txt
(3) [perdir /var/www/www.test1.com/] applying pattern '.' to uri '!"%23$%&'().txt'
(4) [perdir /var/www/www.test1.com/] RewriteCond: input='' pattern='200' => not-matched
(3) [perdir /var/www/www.test1.com/] strip per-dir prefix: /var/www/www.test1.com/!"%23$%&'().txt -> !"%23$%&'().txt
(3) [perdir /var/www/www.test1.com/] applying pattern '^(.*)#(.*)$' to uri '!"%23$%&'().txt'
(3) [perdir /var/www/www.test1.com/] strip per-dir prefix: /var/www/www.test1.com/!"%23$%&'().txt -> !"%23$%&'().txt
(3) [perdir /var/www/www.test1.com/] applying pattern '^((?!foo/).*)' to uri '!"%23$%&'().txt'
(2) [perdir /var/www/www.test1.com/] rewrite '!"%23$%&'().txt' -> 'foo/!"%23$%&'().txt'
(3) [perdir /var/www/www.test1.com/] add per-dir prefix: foo/!"%23$%&'().txt -> /var/www/www.test1.com/foo/!"%23$%&'().txt
(2) [perdir /var/www/www.test1.com/] strip document_root prefix: /var/www/www.test1.com/foo/!"%23$%&'().txt -> /www.test1.com/foo/!"%23$%&'().txt
(1) [perdir /var/www/www.test1.com/] internal redirect with /www.test1.com/foo/!"%23$%&'().txt [INTERNAL REDIRECT]

で、400が返されログの出力はここで止まる
これは今まで抜け落ちていた0x25(%)が起因となるもので、0x26(&)が続く0x25(%)が不正と判断されて発生している

この問題はhttpd.confへ
RewriteMap escape int:escape
と、した上で.htaccessへ
RewriteRule ^(.*)$ ${escape:$1}
と、することで回避できる

余談だがこの内容を書くにあたって2日要しており、ここまでは昨日の話

実は記号問題は重要視していなかった
これは真面目に調べていなかったということと同意義で、実はこんな面倒なことは必要ない
と、いうのも前述したとおり、そもそも.htaccessでmod_rewrite使うべきではない、ということで結論が出てしまっていた(し、それで運用することにした)からだ

ところが調べてみるとBフラグというものが存在していて、これは
RewriteRule ^(.*)$ $1 [B]
と、するだけでよく
(2) init rewrite engine with requested uri /!"#$%&'().txt
(3) applying pattern '.' to uri '/!"#$%&'().txt'
(4) RewriteCond: input='' pattern='200' => not-matched
(3) applying pattern '.' to uri '/!"#$%&'().txt'
(4) RewriteCond: input='/var/www/www.test1.com' pattern='-d' => matched
(2) rewrite '/!"#$%&'().txt' -> '/var/www/www.test1.com/!"#$%&'().txt'
(2) local path result: /var/www/www.test1.com/!"#$%&'().txt
(1) go-ahead with /var/www/www.test1.com/!"#$%&'().txt [OK]
(3) [perdir /var/www/www.test1.com/] strip per-dir prefix: /var/www/www.test1.com/!"#$%&'().txt -> !"#$%&'().txt
(3) [perdir /var/www/www.test1.com/] applying pattern '.' to uri '!"#$%&'().txt'
(4) [perdir /var/www/www.test1.com/] RewriteCond: input='' pattern='200' => not-matched
(3) [perdir /var/www/www.test1.com/] strip per-dir prefix: /var/www/www.test1.com/!"#$%&'().txt -> !"#$%&'().txt
(3) [perdir /var/www/www.test1.com/] applying pattern '^(.*)$' to uri '!"#$%&'().txt'
(5) [perdir /var/www/www.test1.com/] escaping backreference '!"#$%&'().txt' to '%21%22%23%24%25%26%27%28%29%2etxt'
(2) [perdir /var/www/www.test1.com/] rewrite '!"#$%&'().txt' -> '%21%22%23%24%25%26%27%28%29%2etxt'
(3) [perdir /var/www/www.test1.com/] add per-dir prefix: %21%22%23%24%25%26%27%28%29%2etxt -> /var/www/www.test1.com/%21%22%23%24%25%26%27%28%29%2etxt
(3) [perdir /var/www/www.test1.com/] strip per-dir prefix: /var/www/www.test1.com/%21%22%23%24%25%26%27%28%29%2etxt -> %21%22%23%24%25%26%27%28%29%2etxt
(3) [perdir /var/www/www.test1.com/] applying pattern '^((?!foo/).*)' to uri '%21%22%23%24%25%26%27%28%29%2etxt'
(2) [perdir /var/www/www.test1.com/] rewrite '%21%22%23%24%25%26%27%28%29%2etxt' -> 'foo/%21%22%23%24%25%26%27%28%29%2etxt'
(3) [perdir /var/www/www.test1.com/] add per-dir prefix: foo/%21%22%23%24%25%26%27%28%29%2etxt -> /var/www/www.test1.com/foo/%21%22%23%24%25%26%27%28%29%2etxt
(2) [perdir /var/www/www.test1.com/] strip document_root prefix: /var/www/www.test1.com/foo/%21%22%23%24%25%26%27%28%29%2etxt -> /www.test1.com/foo/%21%22%23%24%25%26%27%28%29%2etxt
(1) [perdir /var/www/www.test1.com/] internal redirect with /www.test1.com/foo/%21%22%23%24%25%26%27%28%29%2etxt [INTERNAL REDIRECT]
(2) init rewrite engine with requested uri /www.test1.com/foo/!"#$%&'().txt
(3) applying pattern '.' to uri '/www.test1.com/foo/!"#$%&'().txt'
(4) RewriteCond: input='200' pattern='200' => matched
(1) pass through /www.test1.com/foo/!"#$%&'().txt
(3) [perdir /var/www/www.test1.com/] strip per-dir prefix: /var/www/www.test1.com/foo/!"#$%&'().txt -> foo/!"#$%&'().txt
(3) [perdir /var/www/www.test1.com/] applying pattern '.' to uri 'foo/!"#$%&'().txt'
(4) [perdir /var/www/www.test1.com/] RewriteCond: input='200' pattern='200' => matched
(1) [perdir /var/www/www.test1.com/] pass through /var/www/www.test1.com/foo/!"#$%&'().txt

このように問題を回避できる

さて、この内容を書くための検証環境は最終的に
RewriteEngine On
RewriteCond %{ENV:REDIRECT_STATUS} 200
RewriteRule . - [S=100]
RewriteCond %{DOCUMENT_ROOT}/%{HTTP_HOST} -d
RewriteRule . %{DOCUMENT_ROOT}/%{HTTP_HOST}%{REQUEST_URI} [L]
RewriteRule . https://www.google.co.jp/search?q=%{HTTP_HOST}%{REQUEST_URI}


RewriteEngine On
RewriteCond %{ENV:REDIRECT_STATUS} 200
RewriteRule . - [S=100]
RewriteRule ^(.*)$ $1 [B]
RewriteRule ^((?!foo/).*) foo/$1 [L]

このような設定で動作している

運用上障害になり得る問題は解決しているが、実は1つ踏んだままの地雷がある
それはmod_autoindexを使った場合で、/へのリクエストを/www.test1.com/foo/だと勘違いしてしまう
確かにmod_rewriteによって/へのリクエストは/www.test1.com/foo/になるのだが、mod_autoindexで生成されたページでIndex of /www.test1.com/fooと表示されることを期待はしていないし、Parent Directoryのリンクが見えて、そのリンク先が/www.test1.com/になるのは困る

これは解決できていない
しいて言えば前述しているように.htaccessでmod_rewriteを使わなければ再現しない
add comment ( 3424 views )

<<First <Back | 1 | 2 | 3 | 4 | Next> Last>>