ジャンル不定の日記です。

socatでwebsocketサーバーができなかった件

socatでwebsocketサーバーを作ろうとしてうまく行かなかったが、わかった。
socatに-vオプションつけてターミナルに出力してみたが、なんかバイナリぽいのが出力された。

socatから実行するシェルスクリプトではreadで1行ずつ読んでたが、readじゃバイナリが読めずに変数に空文字が入ってた感じぽい。

今回はクライアントから"test"をsendしてたんだが、
readではなくcatでファイルに出力してバイナリエディタで見てみたが、
"8184E4F2CFA39097BCD7"
↑こんなデータだった。

WebSocketの仕様について調べたが、ハンドシェイクのあとはデータは特殊なフレーム化されて送られるのね。
仕様によると、

1bit目: FIN
最後のフレームの場合1で、続きがある場合は0

byteじゃなくてbitなのね。
今回の"8184E4F2CFA39097BCD7"を2進に変換すると、
"10000001100001001110010011110010110011111010001110010000100101111011110011010111"
1bit目は1なんで1フレームで終わり。

2bit目からの3bitは予約bitで、仕様を拡張するのに使うようで、そんなものはないので今回は"000"。

5bit目からの4bitはデータの種別を表すようで、テキストデータの場合は"0001"

9bit目はマスクの有無
クライアントから送るデータはマスク必須で、サーバーから送るデータはマスク不可。
というわけで"1"

10bit目からの7bitがデータの長さで単位はbyteなんだが、値が126の場合は続く2byteがデータ長。127の場合は続く8byteがデータ長。
125以下の場合は続かずその値がデータ帳となる。
今回は"test"と4byteをsendしたんで、"0000100"(4)

ここまでbit単位になっているが、合計すると16bitで2byteになる。
残りのデータはbyte単位。

3byte目からの4byteはマスク用keyで、7byte目から残り全部はペイロードデータ。
ペイロードデータは、拡張データとアプリデータを連結したもので、予約bitが"000"で何も拡張されてなければ拡張データは存在しないので、ペイロードデータ=アプリデータになる。

アプリデータは単なる平文ではなく、
マスク用keyと元のデータをXORしたものになっている。
マスク用keyは4byteだが、データが5byte以上ある場合はループして5byte目はマスク用keyの1byte目とXORされる感じ。

今回のマスク用keyは2進で
"11100100 11110010 11001111 10100011"
になってる。

アプリデータは
"10010000 10010111 10111100 11010111"

元のデータにマスク用keyをXORしてアプリデータになったわけだが、XOR演算は再度XORすれば元のデータに戻る。
というわけで、XORしてみたが、
"01110100 01100101 01110011 01110100"
ASCIIコードの"test"ですね。