목적지의 주소 체계에 속한 주소가 없어도, 경로 어딘가가 중계할 의사만 있다면 도달할 수 있다. 애플리케이션은 프록시에 연결하고, 프록시는 목적지로 두 번째 연결을 연다. 이들은 서로 독립된 주소 체계를 가진 두 소켓이며, 어느 프로토콜도 이들이 일치해야 한다고 요구하지 않는다. 이것은 애플리케이션 수준의 중계이지 기본 IPv4 경로가 아니며, 이 구분이 무엇이 되고 무엇이 안 되는지를 결정한다. 둘을 혼동하는 것이 바로 노트북이 프록시만 갖고 있으면서도 IPv4 연결성을 가진 것으로 묘사되는 이유다.

두 소켓, 두 주소 체계

SOCKS5 요청은 목적지를 세 가지 형태 중 하나로 지정한다: 리터럴 v4 주소, 리터럴 v6 주소, 또는 프록시가 해석할 이름이다. 요청은 프록시가 어디에 연결해야 하는지를 설명하지, 클라이언트-프록시 연결이 어떻게 생겼는지를 설명하지 않는다.

이 주소 유형들을 하나의 메시지 안에 있는 세 가지 독립적 선택으로 읽어라. IPv6로 도달 가능한 프록시는 동작하는 IPv4 출구가 있고 정책이 요청을 허용할 때마다 IPv4 목적지 소켓을 열 수 있다. SOCKS5 명세는 클라이언트의 전송에 전혀 언급하지 않고 이들을 정의한다.

통제된 SSH 예시

사용 권한이 있는 SSH 호스트를 고르라. 이 호스트는 IPv6로 응답하고, 스스로 v4에만 존재하는 HTTPS 서비스에 도달할 수 있다. OpenSSH의 동적 포워딩은 로그인 세션이 v6를 통해 실행되는 동안 로컬 SOCKS 리스너를 당신의 머신에 둔다.

ssh -6 -N -D 127.0.0.1:1081 -o ExitOnForwardFailure=yes [email protected]

위의 호스트와 계정은 예시이며, 루프백 바인딩은 리스너를 이 컴퓨터에 유지한다. 사무실이 인증 없는 프록시를 공유할 수 있도록 와일드카드 바인딩으로 바꾸지 마라. ExitOnForwardFailure=yes은 포워딩이 실패했을 때 세션을 끝내고 백그라운드에서 조용히 명령이 계속 실행되지 않도록 하기 위해 존재한다.

세션이 실행 중일 때 요청은 이렇게 보인다:

curl --proxy socks5h://127.0.0.1:1081 https://v4-only.example/

루프백 연결은 IPv4 인터넷 경로가 아니다. 당신의 머신을 떠나는 것은 v6를 통한 로그인 세션이며, 목적지 소켓을 여는 것은 먼 쪽이다. socks5h 형태는 이름 해석도 그쪽에 위임하므로, 클라이언트에 자체 IPv4 리졸버 경로가 없을 때 중요하다.

목적지가 실제로 보는 것

목적지는 중계자의 출구 주소를 본다. 당신의 노트북에 속한 어떤 주소도 거기에 나타나지 않는다. 그 서비스의 출처 허용 목록에는 중계자를 명시해야 한다. 그 로그도 트래픽을 중계자에게 귀속시킬 것이다. 감사 전에 변경 기록에 이것을 적어라. 클라이언트 주소를 중심으로 만든 허용 목록은 첫 요청에서 실패하기 때문이다.

중계자는 대화의 두 절반이 보이는 곳이기도 하며, 이는 진단 중에는 유용한 속성이고 중계자가 정책 없이 공유되면 부담이다.

이것은 DNS64도 NAT64도 아니다

DNS64는 v4 목적지를 대신하는 합성 레코드로 응답하고, NAT64는 구성된 경로를 따라 패킷을 다시 쓴다. 어느 것도 여기서 일어나는 일을 설명하지 않는다. 하나의 전송 대화가 끝나고 다른 대화가 시작되며, 어떤 합성 주소도 결과를 설명하지 못한다. 따라서 성공한 요청은 당신의 공급자가 어떤 변환 서비스를 운영하는지에 대해 아무것도 말하지 않으며, 프록시는 자체 출구에서 평범한 NAT를 실행할 수 있다.

두 메커니즘 모두 같은 네트워크에 존재할 수 있으므로, 가장 비슷하게 들리는 것이 아니라 실제로 검증한 것을 설명하라.

약속하기 전에 범위를 알라

OpenSSH의 동적 포워딩은 TCP 연결을 운반하지 임의의 IP 트래픽을 운반하지 않으므로, UDP, ICMP 및 프록시를 무시하는 모든 프로토콜은 다른 지원 설계가 필요하다. SSH 호스트 키 검증, 서버의 포워딩 제한, HTTPS 인증서 검증을 유지하라. 프록시는 추가적인 신뢰 참여자이지 신원 확인을 약화할 이유가 아니다. 목표가 VPN의 외부 전송을 프록시를 통해 운반하는 것이라면, 어떤 SOCKS 리스너든 중계할 수 있다고 가정하지 말고 양쪽 끝이 그 전송을 지원하는지 검증하라.

이 중 어느 것도 클라이언트를 이중 스택으로 만들지 않으며, 그럴 필요도 없다. 하나의 애플리케이션이 하나의 중계를 통해 하나의 서비스에 도달하게 할 뿐이며, 이는 더 작은 주장이고 검증하기 훨씬 쉽다.

관련 글