java.exe -Djava.security.policy=StreamRelay.policy -jar StreamRelay.jar
⇔
StreamRelay.bat
「-Proxy」オプションにある「WebSocket」スキームを指定する事で、「Remote」と呼称する側の相手をWebSocket-APIとする事ができる
相手
WebSocketでリモートシェルを作ったので、それを相手とする
ws://192.0.2.1:9999/shellでWebSocket-APIが待機しているものとする
WebSocket へのアップグレード
「-Proxy」オプションの「WebSocket」スキームを使う事で、「Remote」と呼称する相手に対して、WebSocketへのアップグレードを依頼するHTTPリクエスト・メッセージを送ることができる
java.exe -Djava.security.policy=StreamRelay.policy -jar StreamRelay.jar -LocalPort 0 -RemotePort 9999 -RemoteHost 192.0.2.1 -Proxy WebSocket://192.0.2.1:9999/shell?Origin=http://192.0.2.1:9999/,Sec-WebSocket-Key=AAAAAAAAAAAA
こんな感じで、「Local」と呼称する側(コンソール)と、「Remote」と呼称する側(ws://192.0.2.1:9999/shell)とWebSocketプロトコルで会話する事ができる。
ただし、これでは、WebSocketへのアップグレードだけで、WebSocketプロトコル内部で用いるWebSocketデータグラム(リクエストはマスクする等)は、自分で作る必要がある。
WebSocketデータグラムも符号化
次は、
java.exe -Djava.security.policy=StreamRelay.policy -jar StreamRelay.jar -LocalPort 0 -RemotePort 9999 -RemoteHost 192.0.2.1 -Proxy WebSocket://192.0.2.1:9999/shell?Origin=http://192.0.2.1:9999/,Sec-WebSocket-Key=AAAAAAAAAAAA -RemoteRequestWebSocket=text,mask -RemoteResponseWebSocket
とすると、WebSocketプロトコルへアップグレード後、WebSocketデータグラムの符号化(送信時は、テキストモード、マスクを実施)と、符号化解除(受信時はテキストモード)を実施する。
下記の文字コードの話を考えると、textモードより、binモードの方が適切かもしれない。
WebSocketの文字コード
WebSocket-APIが、特に何もしていなければ、シェル側とコンソール側で同じ文字コードを使っていれば、上記で問題はない。
しかし、WebSocketは文字コードが UTF-8なので、WebSocket-APIが文字コードをUTF-8に変換しているなどの場合、そして、コンソールの文字コードがUTF-8でない場合、文字コード変換が必要になってくる。
java.exe -Djava.security.policy=StreamRelay.policy -jar StreamRelay.jar -LocalPort 0 -RemotePort 9999 -RemoteHost 192.0.2.1 -Proxy WebSocket://192.0.2.1:9999/shell?Origin=http://192.0.2.1:9999/,Sec-WebSocket-Key=AAAAAAAAAAAA -RemoteRequestWebSocket=text,mask -RemoteResponseWebSocket -LocalCharset shift_jis -RemoteCharset utf-8
とすると、「Local」と呼称する側の文字コードは「Shift-JIS」で、「Remote」と呼称する側のWebSocket-APIに対しては文字コードUTF-8に変換する。という事ができる。
Sec-WebSocket-Key
「Sec-WebSocket-Key=AAAAAAAAAAAA」を「Sec-WebSocket-Key-Auto」にする事で、Sec-WebSocket-Keyを適当な乱数にする事ができる