클라이언트가 연결되고 인증한 뒤, 머신의 유일한 기본 경로가 게이트웨이 자신의 것이라서 트래픽이 잘못된 업링크로 빠져나갑니다. 그 기본 경로를 바꾸면 머신 자체의 업데이트와 관리 접근이 깨지므로, 선택은 «모든 트래픽»보다 좁아야 합니다. 실행 가능한 형태는 클라이언트 풀의 내부 출발지 주소를 키로 삼아 대체 WAN을 소유한 두 번째 라우팅 테이블을 가리키는 정책 규칙입니다. 그다음부터 점검 목록은 규칙 자체가 아니라 완전성과 실패 동작에 관한 것입니다.

출발지 주소가 라우팅 결정까지 살아남는지 확인하십시오

출발지 범위와 일치하는 정책 규칙은 조회 시점에 패킷이 아직 그 출발지를 지니고 있을 때만 발동합니다. 전달된 클라이언트 트래픽은 라우팅 전에 상위에서 다시 쓰이지 않았다면 그 조건을 만족합니다. 게이트웨이가 스스로 만든 트래픽은 그렇지 않으며, 바로 그래서 게이트웨이 자신의 기본 경로가 제자리에 남을 수 있습니다.

여기서 로컬 테스트가 오해를 부릅니다. 게이트웨이에서 실행한 curl은 게이트웨이 주소를 가진 로컬 생성 흐름이므로 기본 테이블을 사용하고 클라이언트 경로에 대해 아무것도 증명하지 않습니다. 연결된 클라이언트에서 시험하거나, 풀에 실제로 속한 출발지로 트래픽을 만들어 보십시오.

먼저 풀 프리픽스, 그것을 나르는 터널 인터페이스, 두 번째 WAN의 주소와 다음 홉, 사용하려는 테이블 번호를 적으십시오. 그리고 서로 다른 우선순위의 중복 규칙이 무작위로 보이는 장애를 만들기 때문에, 새 규칙을 추가하기 전에 이전 시도의 오래된 규칙을 지우십시오.

완전한 선택 테이블을 만드십시오

테이블은 친구를 둔 기본 경로가 아닙니다. 모든 조회가 그 안에서 해결될 만큼 충분한 경로가 필요하며, 다음 홉에 도달하도록 WAN 서브넷의 연결 경로도 포함됩니다. tun1의 10.77.0.0/24 풀, 다음 홉 203.0.113.1을 가진 WAN 주소 203.0.113.20/24, 그리고 테이블 600의 경우:

ip -4 route replace 203.0.113.0/24 dev usb0 src 203.0.113.20 table 600
ip -4 route replace 10.77.0.0/24 dev tun1 table 600
ip -4 route replace default via 203.0.113.1 dev usb0 table 600
ip -4 rule add priority 1500 from 10.77.0.0/24 lookup 600

규칙은 기존의 모든 것을 잡는 규칙보다 낮은 우선순위에 놓이므로, 일치하는 클라이언트는 먼저 테이블 600에 도달하고 나머지는 모두 기본 테이블로 떨어집니다. ip-rule 참조가 순서 있는 조회 모델과 선택자 문법을 자세히 설명합니다.

그다음 테이블에 없는 것을 생각하십시오. 기본 테이블에만 경로가 있는 목적지, 예컨대 eth0로 도달하는 관리 서브넷은 테이블 600에서 찾을 수 없고, 거기에 기본 경로가 생기면 다시 기본으로 돌아가지도 않습니다. 그 경로가 중요하다면 선택 테이블에 명시적으로 추가하는 것이 VPN 출구 테이블의 정답입니다.

리스너 자체의 트래픽을 정책 밖에 두십시오

OpenVPN 리스너는 자체 외부 연결을 가지며, 클라이언트가 도달한 업링크로 전달됩니다. 그 트래픽은 도착한 반환 경로를 유지해야 하고, 서버의 공인 주소나 터널 인터페이스 전체를 덮는 넓은 규칙은 그것을 대체 테이블로 끌어들일 수 있습니다. 규칙은 내부 풀로만 한정하십시오.

역방향 경로 필터링도 같은 이유로 살펴볼 만합니다. 클라이언트로 가는 응답이 usb0로 나가는 동안 요청이 다른 링크로 도착했다면, 엄격한 rp_filter 설정은 라우팅 정책이 유효하다고 보는 패킷을 버릴 수 있습니다. 규칙이 실패했다고 결론내리기 전에 두 인터페이스의 유효한 sysctl 값을 확인하십시오.

순서는 머신의 다른 모든 것과의 관계에서도 중요합니다. Docker 브리지, 두 번째 VPN, 공급자 이미지에서 이미 존재하는 모든 규칙이 우선순위를 더하므로, 우선순위 100이 혼자라고 가정하지 말고 규칙 목록 전체를 읽으십시오.

포워딩과 변환이 경로와 일치하게 하십시오

라우팅은 업링크를 선택할 뿐 포워딩 권한을 주지 않습니다. 커널에서 IPv4 포워딩이 켜져 있어야 하고, 방화벽이 클라이언트에서 WAN 방향과 반환 트래픽을 허용해야 합니다. 흐름을 버리는 FORWARD 체인을 가진 올바른 테이블은 경로가 없을 때와 같은 증상을 내므로, 둘을 같은 단계에서 확인합니다.

두 번째 WAN이 사설 풀을 다시 돌려보내지 않는다면 그 출구에서 출발지를 변환하십시오. 동적 주소 인터페이스에는 풀과 인터페이스로 한정한 좁은 masquerade 규칙이 일반적인 선택입니다:

iptables -t nat -A POSTROUTING -s 10.77.0.0/24 -o usb0 -j MASQUERADE

여기서는 대상보다 범위가 중요합니다. 어떤 아웃바운드 인터페이스에든 일치하는 masquerade 규칙은 eth0로 올바르게 나가는 트래픽까지 다시 쓰므로, 라우팅 실수를 고치는 대신 숨깁니다. 변환은 라우팅 결정 뒤에 실행되므로 잘못된 업링크로 보낸 패킷을 결코 고칠 수 없습니다.

경로가 달라지면 터널 오버헤드도 주의가 필요합니다. 클라이언트가 큰 TCP MSS를 협상하고 대체 WAN의 MTU가 더 낮거나 내부에 터널이 있으면, 큰 세그먼트는 멈추고 작은 것은 동작합니다. 포워딩 경로에서 MSS를 클램프하면 간헐적 멈춤 대신 예측 가능한 동작이 됩니다.

usb0가 사라질 때 무슨 일이 일어나는지 정하십시오

빈 테이블은 실패 시 닫히는 상태가 아닙니다. 일치하는 경로가 사라지면 조회는 다음 규칙으로 이어지고, 기본 테이블에 도달해 eth0 기본 경로를 택합니다. 두 번째 WAN으로 나가야 했던 트래픽이 조용히 첫 번째로 나가며, 정책 라우팅 배포에서 이는 보통 가장 원하지 않는 결과입니다.

그 폴백이 용납될 수 없는 곳에서는 테이블 600에 명시적 종단 경로를 추가하거나, 인터페이스가 내려가 있는 동안 방화벽에서 풀을 버리십시오. 둘 중 어느 쪽이든 기록할 수 있는 결정이며, 침묵은 그렇지 않습니다.

지속성은 마지막 항목입니다. 두 링크를 소유한 주체가 네트워크 관리자든 디스패처 스크립트든 연결 수명 주기든, 재연결마다 중복을 덧붙이지 않고 경로와 규칙을 다시 만들어야 합니다. 실제 클라이언트의 요청과 게이트웨이에서의 별도 요청으로 검증하고, 둘 다에서 관측된 출구를 확인한 다음 두 번째 WAN을 뽑아 설계한 두 결과 중 어느 쪽이 실제로 일어나는지 보십시오. IPv6는 자체 테이블과 규칙과 변환이 필요하며, 위의 IPv4 규칙은 그것에 대해 아무 말도 하지 않습니다.

관련 글