安全にWindows上でネットワーク越しに共有を読もうという、実用的なんだけどお馬鹿な試みに関する話です。
sshの使い方とかは省略。環境はWindows XP Professionalしか試してません。たぶんWindows 2000でも平気だと思いますが。ちなみに、TCP port 445に関してはポート445(ダイレクト・ホスティングSMBサービス)に注意辺りを参照のこと。
まず、単純にLAN上に非Windowsマシンがあれば、普通にsshのport forwardでport 139とか445でlistenすれば、そのマシンに繋ぐだけでできます。VMwareでもたぶん平気です。
問題は、Windowsマシン単体で実現する方法です。
最大の問題は、WindowsにささっているNICは、必ずport 137〜139,445が起動時に先にbindされてしまっているためあとからbindできないことです。(どうも正確にはbindできるくせに無効という感じ)ネットワークの設定で「Microsoftネットワーク用ファイルとプリンタ共有」を外しても解決されません。
さらに、explorerではUNC表記(「\\マシン名\共有名」のような書き方のことです)でport指定ができない上に、smb://な表記も受けつけません。
つまり、ローカルマシンの上で、port 139または445にbindするのが必須ということになります。でも、それはできない、と。
とりあえず、なんとかしてbindしないといけないので、NetBIOSをNICから外します。具体的にはレジストリをいじります。
ついでに、port foprward用のダミーのNICを用意して、ローカルでのNetBIOS共有に影響がでないようにします。port forwardでしかbindできなくなっちゃうのは困るので。
まず、Microsoft Loopback Adapter Driverをinstall。
固定でIPアドレスを振ります。default gatewayとかDNSは不要。
次に、どうにかしてMicrosoft Loopback Adapter DriverのデバイスID?を確認します。「{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}」みたいな奴です。
「HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\」の下を「Microsoft Loopback Adapter」で検索すると「NetCfgInstanceId」というパラメータがあるところが見つかると思うので、その中身を確認すればわかります。
もしインストールしていれば、etherealとかwindump -Dとかsnort -Wとかでもわかります。:)
「HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\NetBIOS\Linkage」と「HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\NetBT\Linkage」の両方の「Bind」、「Export」、「Route」の中から、判明したIDを消します。
一応、事前にレジストリ情報をexportしておくことをお勧めします。
壊れても知りません。:)
その後、たぶんrebootしないと駄目だと思います。
これで、Microsoft Loopback Adapter Driverのport 139や445が空いている状態になっているはずなので、「stone localhost:140 ダミーNICに振ったIP:139」とかします。振ったIPアドレスのport 139はlocalhostのport 140に転送されるようになります。
「plink -C -T -L 140:繋ぎたいサーバー:139 アカウント@sshするサーバー」もやります。cmd.exeが二つあがってることになりますが、まあこの辺は適当に。
これで、localhostのport 140が、sshで繋いだサーバーから繋がる「繋ぎたいサーバー」のport 139に転送されます。
explorerから「\\ダミーNICに振ったIP」とかいれると、stoneからplinkを経由して、繋ぎたいサーバーのSMB共有がみえるはずです。
あー、めんどくせー。:)
plinkがstoneのようにlocalhost以外のインターフェースにbindできるようになると、stoneはいらなくなるはずです。→できるようにしました。任意のインターフェースにbind可能なplinkを参照してください。
あとMicrosoft Loopback Adapter Driverが10Mとかでるのが気になります…。速度は全く計測していませんが、本当に10MしかでないならBフレッツだとボトルネックになりそうな気がします。っていうか、10Mもでるのかな…。昔、えらく遅かった記憶が。
ちなみに、対策せずにplinkでport 139や445にbindしようとするとできてしまいます。telnet 127.0.0.1 139するとたしかに有効になっているのが確認できます。接続先portをport 80とかにすると一発でわかります。
が。explorerで\\127.0.0.1に繋ぐと、なぜかローカルの共有を見ます。ちゃんとしろー。おそらくexplorerがlocalhost(127.0.0.1)を特例扱いしてるのでしょう。これがうまくいけばMicrosoft Loopback Adapter Driverなんていらないのに…。
なお、Zebedeeでよければたぶん受け側(サーバー)もWindowsでいけるし、clientは最初から個別インターフェースへのbind機能を持っています。(OpenSSHも持ってるわけだけど)ただし、僕はZebedeeは試してません。まあ、ZebedeeがFirewall越えられるかとかそういう問題になるわけで…。
というわけで任意のインターフェースにbind可能なplinkを作りました。
Release 0.53ベースです。かなり適当なのでbugってたらすみません。覚悟の上でどうぞ。
optionが二つ増えています。
一つは、port forward時に任意のインターフェースにbindできるようにするオプションです。(-local_bind_address アドレス)
もう一つは本家PuTTYのGUI版にある、他のホストからローカルのforward用ポートへの接続を許可する(Local ports accept connections from other hosts)オプションです。なぜかplinkでは指定できないのでoptionをでっち上げました。(-acceptall)
パッチとバイナリーです。バイナリーはplinkだけです。どうせ英語しか出ないので英語版へのpatchですが、hdk氏のパッチを当てたあとでも当たると思います。コンパイルはmingwでやりました。(なのでpatchを当てるとmingw用のmakefileも増えます)
コンパイル時には、-DLOCALBINDと-DACCEPTALLを付けてください。
ちなみに、plinkではなくputtyの-local_bind_addressは、GUIをいじるのがめんどうなので対応してません。
これで、stoneなしでいきなりport 139をbindできます。
「plink -v -T -C -local_bind_address ダミーNICに振ったIP -acceptall -L 139:向こうのNetworkのSMBサーバー:139 アカウント@sshサーバー」こんな感じです。
なお、plinkはそのままだとbindされているアドレス以外からのconnectionを弾くので、-acceptallは必須です。