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 的目标协商。

相关文章