在 Perl 打开 SOCKS 连接后叠加 TLS
在 IO::Socket::Socks 连接之上叠加 IO::Socket::SSL,并校验目标主机名。
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 的目标协商。