VPN 트래픽용 규칙을 FORWARD 체인에 추가하고 같은 Linux 머신에서 요청을 실행해도 카운터는 제로에 머뭅니다. 규칙 자체는 아마 맞습니다. 패킷이 그 경로를 타지 않은 것은 머신 자체에서 생성된 요청을 그 체인이 전달하지 않기 때문입니다. 패킷의 일생을 소켓에서 케이블까지 따라가면 왜 그런지, 규칙이 어디에 있어야 하는지가 드러납니다.

패킷이 태어난 곳을 찾으십시오

Netfilter의 훅 순서는 세 가지 경우를 구분하며, 그중 하나만 FORWARD와 관련됩니다:

OriginPathHook that sees it
Local processOUTPUT then POSTROUTINGOUTPUT, POSTROUTING
Addressed to a local servicePREROUTING then INPUTPREROUTING, INPUT
Received for another hostPREROUTING, FORWARD, POSTROUTINGFORWARD

로컬 애플리케이션은 OUTPUT 경로에서 시작합니다. 커널이 이미 패킷이 여기서 생겨나며 전달 대상이 될 수 없다고 판단했기 때문이며, 터널을 만들어도 이 분류는 바뀌지 않습니다 — 터널은 패킷이 빠져나갈 수 있는 장치이지, 로컬 출력을 통과 트래픽으로 바꾸는 단계가 아닙니다.

패킷 두 개, 이야기 하나

터널이 올라오면 앱의 내부 패킷과 암호화된 외부 패킷은 서로 다른 객체입니다. 내부 패킷은 앱이 고른 목적지와 페이로드를 실어 나릅니다. 외부 패킷은 암호문을 피어의 주소와 포트로 보내며, 실제로 물리 인터페이스를 지나는 것은 이쪽입니다.

정책이 다루는 것은 둘 중 하나이며, 잘못된 쪽을 고르는 것이 규칙이 아무것도 하지 않는 것처럼 보이는 흔한 이유입니다. 피어의 외부 주소와 일치하는 규칙은 내부 앱이 무엇을 하든 모든 터널 패킷을 똑같이 봅니다. 내부 목적지와 일치하는 규칙은 필요한 트래픽을 보지만, 그 패킷이 규칙을 설치한 훅에 도달할 때만 동작합니다.

네임스페이스가 경계를 옮긴다

컨테이너는 원칙을 바꾸지 않으면서 이를 어렵게 만듭니다. 앱의 요청은 컨테이너의 네트워크 네임스페이스 안에서의 로컬 출력입니다. 호스트는 그 트래픽을 가상 Ethernet 인터페이스에서 받아 전달할 수 있으므로, 요청을 만든 프로세스가 호스트의 OUTPUT 체인을 전혀 건드리지 않았더라도 호스트의 FORWARD 규칙이 의미를 가질 수 있습니다.

훅을 고르기 전에 규칙 집합과 터널이 실제로 어디에 사는지 확인하십시오. 컨테이너 내부의 터널, 컨테이너를 그 터널로 라우팅한 호스트의 터널, 별도의 네임스페이스에 있는 터널은 각각 다른 세 가지 토폴로지와 세 가지 규칙 배치입니다. 기본 네임스페이스만이 아니라 장치를 소유한 네임스페이스 안에서 규칙을 읽으십시오.

마크가 정말 필요한지 물으십시오

목적이 하나의 목적지 프리픽스를 터널로 보내는 것이라면, 그 프리픽스에 대한 경로만으로 충분할 수 있습니다. 먼저 서버가 밀어 넣은 것까지 포함해 유효한 경로를 확인하십시오 — 리디렉션된 기본 경로는 생각했던 좁은 정책보다 훨씬 많은 트래픽을 VPN으로 보내며, 아무리 마크를 해도 결과가 의도와 일치하지 않습니다.

분류는 결정이 경로로 표현할 수 없는 무언가 — 출발지, 사용자, 프로세스 같은 것 — 에 달려 있을 때 필요합니다. 수신 트래픽이라면 PREROUTING에서의 마크가 작동합니다. 로컬 트래픽이라면 마크를 설정한 뒤 새로운 경로 조회를 일으킬 수 있는 출력 단계에서 마크해야 합니다. nftables에서는 출력 훅의 route 유형 체인이 그 역할을 하며, 보통의 출력 필터 체인은 값을 설정할 뿐 경로는 바꾸지 않습니다.

iptables에서는 같은 역할이 mangle OUTPUT 구성에 있으며 요구 사항도 같습니다. 마크가 존재한 뒤 라우팅 결정을 다시 검토해야 하고, 그다음 정책 규칙이 마크를 소비하고 쓸 만한 경로가 있는 테이블을 가리켜야 합니다. conntrack 마크 설정은 세 번째, 별개의 작업이며, 플로우에 값을 저장할 뿐 그 값을 현재 패킷에 실어 라우팅이 읽게 하지는 않습니다.

경로 조회와 카운터를 함께 확인하십시오

nft list ruleset
ip route get 198.51.100.25
ip route get 198.51.100.25 mark 0x1

주소와 마크는 예시일 뿐이며, 두 경로 질의는 서로 다른 질문에 답합니다. 두 번째는 패킷이 그 마크를 지녔다면 커널이 무엇을 할지 묻는 것이지, 규칙 집합이 마크를 부여한다는 것을 보여 주지 않습니다. 이것을 가설 검증으로 다루고, 정책이 작동한다는 증거로 보지 마십시오.

그다음 무해한 요청을 실행하면서 고른 훅의 카운터와 패킷이 실제로 택한 출구를 동시에 보십시오. 카운터가 움직이는데 패킷이 다른 곳으로 나간다면 마크나 테이블이 틀린 것입니다. 둘 다 움직이지 않는다면 패킷이 그 훅에 아예 도달하지 않는 것이며, 다음 질문은 네임스페이스나 경로입니다.

마지막으로 테스트 범위를 메커니즘이 표현할 수 있는 것으로 한정하십시오. 한 주소에 대한 한 경로가 주소가 바뀌는 서비스의 영구 정책이 되지는 않습니다. 먼저 패킷 범위를 정하고, 재접속 후에도 라우팅과 마크 설계가 그 범위를 유지할 수 있는지 확인하십시오.

관련 글