서버가 새 주소로 옮겨졌는데 클라이언트는 여전히 연결되고, 그들이 보낸 것은 어느 것도 인터넷에 도달하지 않는다. 바로 이 분리가 단서다. 대기 소켓과 포트 포워딩은 이전을 견뎠으므로 터널은 올라오지만, 전달된 패킷에 적용되는 소스 변환 은 여전히 호스트가 더 이상 갖지 않은 주소를 가리킨다. 다시 쓰인 그 패킷에 대한 응답은 더 이상 존재하지 않는 기계로 간다.

연결과 전달은 서로 다른 곳에서 실패한다

연결 성립은 클라이언트가 이미 아는 종단점에 달려 있다. 공인 주소, 그 앞의 포트 포워딩, 안쪽의 리스너다. 전달되는 트래픽은 패킷이 터널로 들어간 뒤 내려지는 두 번째 결정에 달려 있다. 호스트가 소스를 다시 써서 응답이 돌아올 길을 찾게 하는 것이다.

주소 변경은 두 번째 결정만 깨뜨리므로, 증상은 "연결은 되지만 인터넷이 안 된다"로 읽힌다. 이것은 클라이언트 쪽의 평소 점검이 멀쩡해 보이는 이유이기도 하다. 핸드셰이크가 끝나고 클라이언트가 주소를 받으며, 서버의 터널 주소로 보낸 ping조차 응답할 수 있다. 고장은 반대편에 있는데 클라이언트에서 몇 시간을 쓰게 되므로, 규칙 표가 가장 먼저 볼 곳이다.

편집하기 전에 규칙과 그 카운터를 읽어라

카운터와 함께 변환 규칙을 나열하고, 설정된 소스를 호스트가 실제로 가진 주소와 비교하라. 죽은 주소로 다시 쓰인 규칙은 보통 들어오는 경로에 트래픽을 보여 준다. 패킷이 거기에 도달해 변환되기 때문이다. 돌아오는 경로에는 아무것도 보이지 않는다.

sudo iptables -t nat -L POSTROUTING -n -v --line-numbers
ip -4 addr show

그곳에 있는 동안 세 가지 항목을 확인하라. 소스 일치의 풀, 규칙이 지정했다면 출구 인터페이스, 그리고 터널 간 트래픽이 다시 쓰이지 않게 하는 제외다. 이 제외는 편집 중에 잃기 쉽고, 잃으면 피어 간 트래픽이 동작하는 것처럼 보이지만 그 응답은 이상한 경로를 탄다.

카운터가 영에 멈춰 있으면 패킷이 이 규칙에 도달하지 않으며 주소는 지금의 문제가 아니다. 체인에서 더 앞선 경쟁 규칙을 찾아라. 원본을 편집하지 않고 대체 규칙을 추가했을 때 생긴다. 일 분 전에 적어 둔 출력과 규칙 번호를 비교하라. 순서는 설정의 일부이지 겉모양의 세부가 아니다.

소스를 바꾸거나, 아예 지정하지 마라

호스트에 고정 주소가 있으면 하나를 더 붙이지 말고 규칙을 제자리에서 바꿔라. 규칙 번호로 바꾸면 체인의 나머지가 의존하는 순서가 유지된다.

sudo iptables -t nat -R POSTROUTING 1 -s 10.8.0.0/24 ! -d 10.8.0.0/24 -j SNAT --to-source 10.151.0.40

주소가 동적으로 할당되면 소스를 전혀 지정하지 말고 커널이 출구 인터페이스에서 현재 것을 고르게 하라. 이 형태는 다음 이전을 편집 없이 견딘다. 어떤 주소가 쓰였는지 감추는 대가가 따른다.

sudo iptables -t nat -R POSTROUTING 1 -s 10.8.0.0/24 ! -d 10.8.0.0/24 -o eth0 -j MASQUERADE

IPv4 포워딩이 관리되는 설정을 통해 여전히 켜져 있는지 확인하고, 그다음 배포판 자체의 방식으로 규칙을 영구화하라. 실행 중인 커널에서만 바꾼 변경은 다음 재부팅 때 되돌아간다. 대개 아무도 변경과 연결 짓지 않는 유지보수 시간대에 일어난다.

대체를 잘못하는 두 가지 방법

풀을 서버의 LAN 주소가 아니라 터널 주소로 변환하면 응답이 곧바로 터널로 돌아가, 요청한 적 없는 클라이언트 쪽으로 라우팅된다. 연결은 라우팅 루프처럼 멈춘다. 실제로 루프이기 때문이다.

예전 변환 위에 두 번째를 쌓는 것이 또 다른 실수다. 먼저 일치하는 규칙이 이기므로 오래된 항목은 삭제될 때까지 패킷을 계속 처리하고, 새 규칙의 카운터는 영에 머무는 동안 모두가 대체를 탓한다. 새로 무엇이든 추가하기 전에 중복을 삭제하라. 그런 다음 목록을 한 번 더 읽고, 풀과 일치하는 변환이 정확히 하나인지 확인하라.

터널이 IPv6도 나른다면 다른 스택에서 전체 검토를 반복하라. 변환도 없고 라우팅된 프리픽스도 없는 IPv6 기본 경로는 똑같이 조용히 실패하며, 그 위의 모든 것이 똑같아 보이므로 잊기 쉽다.

인바운드 서비스에는 반대 방향 변환이 필요하다

외부에서 접근할 수 있어야 하는 VPN 클라이언트의 서비스에는 소스 변환이 아니라 목적지 변환이 필요하다. 공인 포트는 들어오기 전에 클라이언트의 터널 주소로 다시 쓰인다. 그다음 전달 경로에는 그 트래픽을 허용하는 명시적 규칙이 필요하다.

sudo iptables -t nat -A PREROUTING -p tcp --dport 8080 -j DNAT --to-destination 10.9.8.2:8080

터널 자체를 나르는 포트는 절대 변환하지 마라. 그 다시 쓰기는 서비스를 접근 가능하게 유지하는 연결을 끊는다. 터널 포트는 목적지 규칙에서 완전히 빼 두어라. 마지막으로 양쪽 끝에서 검증하라. 새 규칙의 카운터, 터널 장치에서의 짧은 캡처, 그리고 공인 주소를 시도하기 전에 터널 내부 주소로의 요청 하나다.

관련 글