VPN 클라이언트 풀 하나에 자체 공인 주소를 주려던 NAT 규칙이 영 패킷에 머물러 있는데, 같은 풀은 계속 잘못된 출발지로 나가고 있다. 보통 규칙은 주소를 틀리지 않고 인터페이스를 틀린다. -o eth0:0 존재하지 않는 장치를 가리키는데, 왜냐하면 eth0:0 주소에 붙은 레이블이고 그 주소의 장치는 여전히 eth0이기 때문이다. 카운터를 보는 것이 이를 확인하는 가장 빠른 방법이고, 수정은 조사가 시사하는 것보다 작다.

커널이 그 장치를 무엇이라 부르는지 확인한다

무엇이든 바꾸기 전에 두 화면을 따로 읽는다:

ip link show
ip address show dev eth0
ip route get 203.0.113.20

링크 목록은 인터페이스를 보여 준다. 주소 목록은 다음 레이블을 단 두 번째 IPv4 주소를 보여 줄 수 있다 eth0:0, 그 주소의 장치는 여전히 eth0다. iproute2 주소 설명서는 레이블을 주소의 이름으로 취급하며 두 번째 링크로 보지 않으며, 문제 전체가 바로 이 구분에 달려 있다.

역사가 혼란을 설명한다. 옛 ifconfig eth0:0 문법은 정말 새 인터페이스처럼 보였고, 그 시절 스크립트는 지금도 그렇게 언급한다. 현재 시스템에서 별칭은 주소에 붙은 레이블이며, 라우팅이나 netfilter 경로에서 그것을 별도 출구 지점으로 취급하는 것은 없다.

규칙이 실제로 무엇과 일치했는지 확인한다

카운터는 기억이 아니라 규칙 목록과 함께 읽는다:

iptables -t nat -L POSTROUTING -v -n --line-numbers

일치하는 트래픽이 흐르는 동안 패킷 카운터가 영에 머무는 규칙은 평가되지 않는다. 출력 인터페이스 조건이 eth0:0 를 지정하는 것이 흔한 원인이고, 라우트가 고른 출력 장치는 eth0이므로, 다른 이름을 찾는 조건은 커널이 어떤 출발지 주소를 골랐든 결코 참이 되지 않는다.

조건을 실제 장치로 바꾸고 레이블은 그 밖에 둔다. 그 장치를 공유하는 두 클라이언트 풀을 구분해야 한다면 출발지 접두사로 구분하고, 존재할 수 없는 인터페이스 이름으로 구분하지 않는다. 겹치지 않는 -s 일치를 가진 규칙 두 개는 읽고 시험할 수 있지만, 가상의 장치를 가진 규칙 하나는 둘 다 아니다. 접두사만으로는 반년 뒤에 왜 그 규칙이 있는지 아무도 알 수 없으므로, 각 규칙에 풀 이름을 적은 주석을 달아 둔다.

장치를 고른 라우트를 확인한다

포스트라우팅 NAT는 라우트가 이미 출력 인터페이스를 고른 뒤에 실행되므로 규칙의 인터페이스는 라우트가 고른 것과 같아야 한다. 커널에 직접 물으려면 ip route get 를 써서 대표적인 클라이언트 주소에 대해, 보고하는 장치와 출발지를 모두 읽는다.

답이 eth0를 가리키면 규칙의 인터페이스 부분은 정해진 것이다. 터널 장치를 가리키면 패킷은 편집 중인 규칙에 결코 닿지 않고, 탐색은 라우팅 표와 그 우선순위로 옮겨 간다. 패킷이 다른 곳으로 나가서 결코 일치하지 않는 규칙은 장치 이름을 잘못 적은 규칙과 카운터 출력에서 똑같이 보인다. 두 번째 경우는 텍스트가 아니라 라우팅을 바꿔야 하므로, 무엇을 편집하기 전에 어느 쪽인지 확인한다.

변환 출발지를 의도적으로 고른다

장치가 맞으면 출발지 주소는 별개의 결정이다. 여기서는 설명용 IPv4 풀과 예시 주소일 뿐이다:

iptables -t nat -A POSTROUTING -s 10.8.1.0/24 -o eth0 \
  -j SNAT --to-source 203.0.113.20

주소를 --to-source 에 적는다고 해서 누군가 그 주소로 당신에게 되돌려 라우팅해 주지는 않는다. 상위 제공자나 주소 소유자가 그 주소의 응답을 이 호스트로 전달해야 하고, 그 주소는 당신이 사용할 권한이 있는 것이어야 한다. 그렇지 않으면 규칙은 일치하고 변환하지만 응답은 여전히 다른 곳으로 간다.

출발지 주소를 바꾸는 것은 상위 링크를 바꾸는 것과 같지 않다. 진짜 요구가 다른 물리 경로라면 라우팅 정책이 먼저 그 경로를 골라야 하고, 그다음 SNAT가 정책이 고른 장치에서 출발지를 다시 쓴다. 레이블을 더 붙여도 eth0 경로도 권한도 주지 않는다.

방금 연 연결로 확인한다

기존 연결을 재사용하지 말고 새 클라이언트 연결을 연다. 연결 추적은 흐름이 시작될 때 기록한 변환을 유지하므로, 오래된 세션은 이전 출발지 주소를 계속 써서 올바른 새 규칙이 고장 난 것처럼 보이게 할 수 있다. 카운터가 오르는 것을 보고, 그다음 변환된 출발지를 회선이나 반대편에서 관찰한다.

하나의 인터페이스를 공유하는 여러 풀에는 각각 명시적인 출발지 일치와 자체 변환 주소를 주고, 방화벽의 관리 구성에 두고, 평가되는 순서를 적어 둔다. 그런 다음 확인한 것을 기록한다: ip route get에서 얻은 장치, 움직인 카운터, 반대편이 본 출발지다. 그 기록은 레이블 혼란을 되풀이하지 않고 다음 보고에 답한다.

관련 글