포트 1080에서 SOCKS 리스너가 도는 호스트로 VPN 클라이언트 트래픽을 보내는 정책 경로를 추가했습니다. 패킷은 도착하지만 리스너는 아무것도 기록하지 않고 연결은 매달려 있습니다. 경로에는 아무 문제가 없습니다: 다음 홉은 패킷이 어디로 갈지 고르고, SOCKS는 클라이언트가 시작해야 하는 대화입니다. 사람들이 프록시를 통해 트래픽을 보낸다고 할 때 흔히 뜻하는 세 가지 구조를 비교하면 설정에서 어떤 조각이 빠졌는지 분명해집니다.

라우팅, DNAT, SOCKS는 서로 다른 것을 바꿉니다

정책 경로는 3계층 결정을 다시 씁니다. 클라이언트 하나의 트래픽을 선택한 다음 홉으로 보내는 데는 두 줄이면 충분합니다:

ip route add default via 10.50.0.2 table 101
ip rule add from 10.77.0.2 lookup 101

그 뒤 커널은 패킷을 10.50.0.2에 넘기고 원래 목적지는 여전히 IP 헤더에 남아 있습니다. 10.50.0.2가 라우터라면 패킷을 전달하고, 1080에서 SOCKS 데몬이 도는 호스트라면 패킷은 그것을 받아들일 수 있는 어떤 것에도 주소가 지정되지 않았고, 포트 1080으로의 DNAT도 도움이 되지 않습니다. 변환된 패킷은 여전히 SOCKS 인사 대신 원래 애플리케이션 페이로드를 실어 나르기 때문입니다.

SOCKS5 버전 바이트, 메서드 목록, 인증 교환, 목적지를 지명하는 요청으로 시작합니다. 그것은 애플리케이션 데이터입니다. 라우팅 항목도 netfilter 대상도 그것을 만들지 않으며, 한 줄로 말하면 이렇습니다: 라우팅은 경로를 고르고, SOCKS는 서버에 두 번째 연결을 만들라고 요청합니다.

첫 번째 경우: 애플리케이션이 스스로 SOCKS를 말할 수 있다

프로그램에 프록시 설정이 있으면 이것이 가장 짧은 길이고 커널 변경이 필요 없습니다. 리스너를 가리키고, 서버가 요구하면 자격 증명을 제공하고, 이름을 로컬에서 해석할지 프록시로 넘길지 정하십시오. curl에서는 서로 다른 플래그이고, 목적지가 프록시 쪽에서만 해석될 때 그 차이가 중요합니다:

curl --socks5 10.50.0.2:1080 https://docs.example.com
curl --socks5-hostname 10.50.0.2:1080 https://internal.example.com

프록시 환경 변수를 무시하거나 원시 소켓을 여는 애플리케이션은 이 방법으로 도울 수 없습니다. 브라우저와 대부분의 HTTP 도구는 괜찮지만 게임 클라이언트, 메일 데몬, 임의의 공급업체 바이너리는 보통 그렇지 않습니다. 경계는 애플리케이션마다, 프로토콜마다 있으므로 이 선택지는 테스트에 탁월하고 전체 VPN에 대한 답으로는 약합니다.

두 번째 경우: IP 흐름을 프록시 세션으로 변환하는 어댑터

SOCKS를 말할 수 없는 프로그램의 경우, 변환은 IP 트래픽을 종료하고 그들을 대신해 프록시 세션을 여는 무언가에서 일어나야 합니다. 그 구성 요소는 터널 인터페이스를 소유하고, 정책 라우팅이 선택한 흐름을 받아들이고, 각각에 대해 SOCKS 핸드셰이크를 수행하며 응답을 다시 만듭니다. 경로가 트래픽을 그쪽으로 보내고, 세션을 만드는 것은 어댑터입니다.

전체 서브넷을 맡기기 전에 문서를 읽으십시오. 많은 어댑터가 TCP는 잘 나르지만 UDP는 SOCKS5 UDP 연합을 통해서만 처리하며, 어느 것도 ICMP를 프록시 트래픽으로 바꾸지 않으므로 성공한 ping은 프록시 경로에 대해 아무것도 말해 주지 않습니다. DNS가 또 다른 함정입니다: 어댑터가 이름을 로컬에서 해석하면 내부 전용 레코드는 잘못된 답으로, 또는 아무것도 아닌 것으로 해석됩니다.

루프 방지가 실제로 아픈 운영 세부 사항입니다. 어댑터 자체의 SOCKS 서버 연결은 다시 어댑터로 라우팅되어서는 안 되므로 그 트래픽에는 규칙의 예외나 전용 소스 주소가 필요합니다. 이것을 잘못하면 프록시 세션이 스스로를 프록시하려 듭니다.

세 번째 경우: 호스트가 사실은 라우팅된 게이트웨이다

때로 동작하는 설정에는 SOCKS가 전혀 없습니다. 원격 호스트가 패킷을 전달하거나 NAT를 수행하고, 소스 기반 규칙이 그것을 출구로 고를 뿐입니다. 그 설계는 정당하며, 복사한 구성이 한 네트워크에서는 되고 다른 곳에서는 실패하는 이유를 설명합니다: 규칙은 같고, 빠진 조각은 반대편의 전달 서비스입니다.

세 경우는 빠르게 갈라집니다. 실제로 무엇이 듣고 있는지 확인하고, 다음으로 호스트에 도달하는 첫 바이트를 보십시오:

ss -ltnp 'sport = :1080'
tcpdump -ni eth0 -X 'tcp port 1080'

진짜 SOCKS 클라이언트의 첫 페이로드 바이트는 0x05, 인사에 담긴 버전입니다. 캡처가 대신 원래 애플리케이션 데이터를 보여 준다면 협상이 시작되지 않았으므로 어떤 SOCKS 데몬도 응답하지 않습니다. 1080에서 아무것도 듣고 있지 않다면 호스트는 게이트웨이이고, 질문은 그것이 전달하는지와 돌아오는 경로가 있는지가 됩니다.

네 가지 질문으로 계층을 고르십시오

프로그램에 프록시 설정이 있습니까? 있으면 쓰고 거기서 멈추십시오. 트래픽에 살아남아야 할 UDP나 ICMP가 포함됩니까? ICMP는 라우팅된 게이트웨이나 NAT 게이트웨이만 나르고, UDP는 양쪽 끝이 지원하는 SOCKS5 연합이 필요합니다. 구성할 수 없는 것을 포함해 기계의 모든 프로세스를 덮어야 합니까? 그렇다면 인터페이스를 소유하고 흐름을 종료하는 어댑터가 필요합니다. 그 어댑터의 라우팅, DNS, 루프 방지 예외까지 맡을 수 있습니까? 아니라면 단순 게이트웨이가 운영 비용이 더 적습니다.

한 가지 구분은 곧게 유지할 가치가 있습니다. VPN 클라이언트 자체의 socks-proxy 옵션은 바깥 터널 연결이 자기 서버에 어떻게 도달하는지를 설명하고, 안쪽 클라이언트 흐름의 변환에 대해서는 아무것도 말하지 않습니다. 이 둘은 같은 티켓에서 늘 혼동됩니다. 경로를 건드리기 전에 어느 관계가 필요한지 정하십시오.

관련 글