SocksClient.createConnection은 요청한 대상에 연결된 스트림을 반환합니다. HTTPS에서는 그 스트림이 HTTP 요청을 실어 나르기 전에 여전히 TLS 핸드셰이크가 필요합니다.

import { SocksClient } from 'socks';
import tls from 'node:tls';

const targetHost = 'service.example';
const info = await SocksClient.createConnection({
  proxy: { host: 'proxy.example', port: 1080, type: 5 },
  command: 'connect',
  destination: { host: targetHost, port: 443 },
  timeout: 10000,
});
const secure = tls.connect({
  socket: info.socket,
  servername: targetHost,
});
secure.on('error', onTransportError);
secure.on('data', onResponseBytes);
secure.once('secureConnect', () => {
  secure.write(
    `GET /data HTTP/1.1\r\nHost: ${targetHost}\r\nConnection: close\r\n\r\n`
  );
});

SOCKS5 프록시 목록 프록시 호스트와 포트의 후보를 제공합니다. onTransportError와 onResponseBytes는 기존 애플리케이션에 속하며, 후자는 HTTP 응답 스트림을 파싱해야 합니다. TLS 데이터 조각은 그 자체로 완전한 HTTP 메시지가 아닙니다.

servername은 대상의 DNS 이름입니다. Node의 저수준 tls.connect는 기본적으로 SNI를 켜지 않으며, 프록시 호스트 이름은 웹사이트의 인증서 신원이 아닙니다.

인증서 검증은 켜 둡니다. 연결된 소켓을 넘기면 웹사이트로 별도의 직접 연결을 열지 않으면서 TLS 신원을 유지할 수 있습니다.

SOCKS 타임아웃은 그 협상을 제한합니다. 이후의 TLS와 애플리케이션 교환에는 호출자가 의도한 타임아웃, 취소, 정리 정책이 여전히 필요합니다.

관련 글