З'єднання SOCKS і з'єднання TLS виконують різні завдання. Спочатку отримайте потік байтів до призначення через SOCKS. Потім запустіть TLS поверх цього потоку, ідентифікуючи цільовий сайт, а не проксі.

Для кінцевої точки TLS у стилі HTTPS схема може бути такою:

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.

Схожі статті