SOCKS5 のフロントエンドは、HTTP プロキシを後続の転送手段として使えます。クライアントに対しては SOCKS サーバーとして、親に対しては HTTP CONNECT クライアントとして振る舞います。二つの制御交換はアプリケーションのストリームが始まる前に終わります。

SOCKS CONNECT 要求はすでに宛先のホストまたはアドレスとポートを提供しています。説明のための HTTP/1.1 の親との交換は次のとおりです。

client → adapter: SOCKS5 CONNECT service.example.net:443
adapter → parent:
    CONNECT service.example.net:443 HTTP/1.1
    Host: service.example.net:443

parent → adapter: HTTP/1.1 200 Connection Established
                 [end of headers]
adapter → client: SOCKS5 success reply

client ↔ adapter ↔ parent ↔ service: application bytes

境界で結果を変換する

アダプターは親に必要な認証をすべて済ませ、CONNECT の結果を待ちます。成功した 2xx 応答が親へのトンネルを確立します。その後にだけ、対応する SOCKS の成功応答を下流のクライアントへ返すべきです。

親が操作を拒否した場合は、定められた SOCKS の失敗応答を送り、その後すぐにクライアントの接続を終了します。SOCKS5 は、失敗を検出してから十秒以内にその終了を行うことを求めています。親の HTTP ステータスはアダプターの診断情報として保持してください。そのステータス行をアプリケーションデータとして転送すると、クライアントが SOCKS のフレーミングを期待しているストリームに HTTP の制御メッセージを入れてしまいます。

CONNECT が成功する前は、親はまだ HTTP を話しており、チャレンジやエラーの応答のフレーミングも含まれます。成功した結果のヘッダー区切りの後、接続はトンネルになります。先に消費すべき HTTP 応答の本文はありません。

ヘッダーの後のバイトを保持する

一回の読み取りに、親のヘッダーの終わりと宛先からのバイトが同時に含まれることがあります。その余分なバイトを下流のアプリケーションのために保持します。サーバーが先に話すプロトコルは、接続が開いた直後に挨拶を送ることがあります。

SOCKS の成功応答を送った後は、アプリケーションのストリームを両方向に中継します。アダプターはクライアントのメッセージとサーバーのメッセージを交互に扱う必要はなく、TLS レコードを理解して転送する必要もありません。そのプロトコル上の仕事は、二つのトンネル交渉を確立して変換することでした。

関連記事