SOCKS 接続と TLS 接続は役割が異なります。まず SOCKS 経由で接続先へのバイトストリームを取得します。次にそのストリームの上で TLS を開始し、プロキシではなく接続先のウェブサイトを識別します。

HTTPS 形式の TLS エンドポイントの場合、構成は次のようになります。

use IO::Socket::Socks;
use IO::Socket::SSL;

my $target = 'example.com';
my $socket = IO::Socket::Socks->new(
    SocksVersion => 5,
    ProxyAddr => '127.0.0.1',
    ProxyPort => 1080,
    ConnectAddr => $target,
    ConnectPort => 443,
) or die $!;

IO::Socket::SSL->start_SSL(
    $socket,
    SSL_hostname => $target,
    SSL_verifycn_name => $target,
    SSL_verifycn_scheme => 'http',
    SSL_verify_mode => SSL_VERIFY_PEER,
) or die IO::Socket::SSL::errstr();

許可された公開プロキシ経路にある公開 HTTPS ターゲットには、SOCKS5 プロキシ一覧が ProxyAddr と ProxyPort の候補を提供します。この断片はトランスポート層を確立するだけであり、アプリケーションは接続先が期待するプロトコルを送信し、終了時にソケットを閉じる必要があります。

意図したピア名を保つ

プロキシのエンドポイントは最初の接続に属します。TLS SNI とホスト名検証が関係するのはexample.comです。その段階でプロキシのホスト名を使うと、誤った識別名を要求したり検証したりする可能性があります。

トラストストアの設定も独立した要件です。診断用の例からコピーした「すべてを信頼する」コールバックではなく、アプリケーションが意図する CA 設定を使用してください。

SOCKS の段階が失敗した場合、TLS パラメータを変えても直りません。SOCKS が成功して TLS が失敗した場合は、証明書とホスト名のエラーを証拠として保持し、一般的なプロキシ障害として扱わないでください。

モジュール名も重要です。IO::Socket::Socks と IO::Socket::SSL はコンストラクタもアップグレードの挙動も異なります。プロキシに到達しただけの生の TCP ソケットは、まだ SOCKS の接続先ネゴシエーションを完了していません。

関連記事