SSHとHTTPを同一ポートで待ち受けるプロキシ(ゲートウェイ? どっちだ?

今日もしょうもないことに時間使った...

SSHdApacheが両方 localhost で上がってると仮定して,

$ ./sshHttpProxy.py 0.0.0.0 10080 localhost 22 localhost 80

と動かすと,以下の両方がきちんと(?)動くのを確認した.

$ ssh -p 10080 localhost
$ wget http://localhost:10080/ -O-

まずSSH2プロトコル仕様はここのリンクから大体読める.今回はその0.1 %も読まないが.

SSH2の上り・下りそれぞれの最初のパケットは自己紹介で, "SSH-2.0-ほげほげ" という文字列が交わされる (RFC 4253 SSH Transport Layer Protocol > 4.2. Protocol Version Exchange).ここはまだ暗号化されてないし 「長さ + ペイロード」形式にも従わない,SSH2で最も単純な部分.だからクライアントからの通信とこれの文字列マッチが成功したら裏で22番に転送,違ったら80番... 最初は単にシンプルにそう考えた.
ところがOpenSSHのクライアントはサーバから先に "SSH-2.0-ほげほげ" を送ってくるまで待ち続けるのな.(どっちが先かは決められてない.)しょうが無いのでタイムアウト 0.5 秒を設けてタイムアウトしたらSSHと判断することにした.HTTPならハンドシェイク確立直後に GET か何かがクライアントから来るはずだから, 0.5 秒も開くとか現実的にはあり得ない(HTTPでは最初はクライアント側からと決まっている.)特にLANならね.タイムアウトしなかったら,つまりはクライアント側からパケットが来てるので,さっき言ったやり方でマッチングを見る.
これだとSSHの接続開始時だけ 0.5 秒のラグを余分に導入することになるが,まぁ誰も気にせんよな.CPUを消費するでもなし.
未だに SHUT_WR とかの本当に適切な使い方をあんまり理解してない... あ,サーバ側からTCP FINで切られたときの対処を全くしていないな. socket.error(32, 'Broken pipe') をキャッチしないと.