앱 기반과 목적지 기반 스플릿 터널링은 같은 작업을 위한 두 가지 설정이 아닙니다. 하나는 어느 프로세스가 패킷을 보내는지 묻고, 다른 하나는 그 패킷이 어디로 가는지 묻습니다. 첫 질문을 위해 만든 규칙은 트래픽이 도우미 프로세스에서 올 때 조용히 실패하고, 두 번째를 위해 만든 규칙은 호스트 이름이 목록에 없는 주소로 해석될 때 실패합니다. 요구 사항에 맞는 대상을 고르고, 두 개의 시험 패킷으로 증명하십시오. 하나는 터널을 써야 하고 다른 하나는 쓰면 안 됩니다.

두 규칙은 서로 다른 계층에서 일치한다

앱 규칙은 네트워크 계층 위에서 운영 체제가 발신자에게 부여하는 신원에 대해 적용됩니다. Android에서는 패키지 뒤의 UID이며, VPN 서비스는 UID별로 트래픽이 터널로 들어갈지 결정합니다. 목적지에 대해서는 아무것도 묻지 않으므로 선택한 앱은 무엇이든 닿을 수 있고 다른 앱은 내부 네트워크에 닿을 수 없습니다.

목적지 규칙은 패킷 자체에 적용됩니다. 터널 인터페이스는 일련의 프리픽스를 소유하고, 라우팅 테이블이 일치하는 트래픽을 그리로 보내며, 보내는 프로세스는 무관합니다. 그래서 목적지 규칙은 아무도 목록에 넣는 것을 잊은 서비스, 프린터, 배치 작업까지 포괄하며, 클라이언트가 프로세스를 보지 않는 플랫폼에서는 이것만 이 프로그램이라고 표현할 수 없습니다.

앱 규칙은 모바일 클라이언트와 관리형 에이전트에 맞는다

Android는 선택지를 직접 노출합니다. VpnService.Builder.addAllowedApplication() 과 addDisallowedApplication() 은 패키지 이름을 받아 UID별로 결정을 적용하며, Android의 VPN 개발자 가이드에 설명된 대로입니다. iOS에도 번들 식별자를 키로 하는 앱별 VPN 규칙으로 같은 기능이 있으며, 보통 손으로 입력하지 않고 MDM 프로필로 배포됩니다.

데스크톱 클라이언트가 약점입니다. 대부분의 Windows와 macOS VPN 클라이언트는 목적지로 라우팅하며 프로세스별 선택기를 아예 제공하지 않습니다. 터널 드라이버가 보는 것은 패킷이지 프로세스가 아니기 때문입니다. 노트북에서 앱 하나만 터널링하는 계획이라면 그에 맞춰 설계하기 전에 클라이언트의 실제 기능을 확인하십시오. 목적지 목록과 두 번째 머신 중 하나를 고르는 상황일 수 있습니다.

사람들이 놓치는 귀결: 그 플랫폼에서는 경로로 앱 규칙을 흉내 낼 수 없습니다. 앱의 서버에 호스트 경로를 추가하면 브라우저와 업데이터를 포함한 모든 사람의 트래픽이 그 서버로 터널링됩니다.

목적지 규칙은 서브넷 목록과 사이트 도달성에 맞는다

WireGuard는 모델을 명시적으로 만듭니다. AllowedIPs 은 암호 키 라우팅입니다. 목적지가 피어 목록 안에 들어가는 내부 패킷은 그 피어로 암호화되고, 나머지는 일반 경로로 암호화 없이 나갑니다. 이름 붙일 프로세스도, 무엇이 포함되는지에 대한 모호함도 없습니다.

OpenVPN 은 밀어 넣은 라우팅 테이블로 같은 지점에 도달합니다. route-nopull 은 서버가 경로를 지시하지 못하게 하고, 그다음 클라이언트 측 route 10.20.0.0 255.255.0.0 vpn_gateway 이 사무실 프리픽스만 정확히 덮습니다. IPv6는 이 클라이언트들 각각에서 별도 문장이며, 그것을 잊는 것이 올바르게 보이는 IPv4 분할 주위로 새는 가장 흔한 방법입니다.

호스트 이름은 경로가 아닙니다. 프로필에 도메인 필드가 있다면 클라이언트가 한 번 해석하는 이름으로 다루고 영구 주소 범위로 보지 마십시오. CDN과 로드 밸런서는 내일 다른 주소를 내놓습니다.

두 모델이 깨지는 곳: 도우미, 공유 서비스, 리졸버

도우미 프로세스는 앱 규칙을 깨뜨립니다. 그 양상은 서버 장애처럼 보입니다. 브라우저의 업데이터, 크래시 리포터, SYSTEM으로 실행되는 동기화 서비스, 다른 패키지에 내장된 WebView는 모두 별개의 신원이므로 브라우저를 터널링해도 실제 요청은 터널 밖에 남을 수 있습니다. 반대도 똑같이 혼란스럽습니다. 터널링된 프로세스 안의 공유 라이브러리를 호출하는 제외된 앱도 트래픽은 여전히 터널을 지납니다.

목적지 규칙은 공유 서비스와 이름에서 깨집니다. 파일 공유, 프린터, 내부 DNS, 라이선스 서버는 모두 주소에 존재하므로, 앱 하나짜리 터널은 브라우저에 접근을 주지만 매핑된 드라이브는 죽은 채로 남습니다. 이 적용 범위 차이는 어느 모델의 버그도 아니지만, 앱 하나짜리 터널이 VPN은 켜져 있는데 공유가 사라졌다를 자주 만드는 이유입니다.

리졸버는 둘 다 가로지릅니다. 클라이언트가 내부 DNS 서버를 설정했는데 운영 체제가 공용 리졸버로 DNS over HTTPS를 쓰면, 응답은 터널 밖에서 오고 목적지 규칙은 끝내 맞지 않을 수 있습니다. 규칙이 틀렸다고 결론 내리기 전에 어느 리졸버가 실제로 응답했는지 확인하고, 클라이언트 쪽에서 터널 리졸버를 설치했는지도 확인하십시오. DNS를 터널 밖에 두는 분할은 라우팅 테이블에서는 완벽해 보이지만 모든 내부 이름에서 실패합니다.

런북: 고르고, 적용하고, 검증한다

메뉴가 아니라 요구 사항에서 시작하십시오. 목표가 이 앱만 터널을 쓸 수 있다면 앱 규칙과 이를 지원하는 플랫폼이 필요합니다. 목표가 이 네트워크에 터널로 닿는 것이라면 프리픽스가 필요합니다. 답이 둘 다라면 두 개의 별도 제어로 구현하고 어느 쪽이 어떤 실패를 책임지는지 적어 두십시오.

표현할 수 있는 가장 좁은 형태를 적용하고, 클라이언트의 상태 아이콘이 아니라 라우팅 테이블에 물어 검증하십시오.

ip route get 10.20.30.40
ip -6 route get 2001:db8:10::40
wg show wg0 allowed-ips
Get-NetRoute -DestinationPrefix 10.20.0.0/16
Find-NetRoute -RemoteIPAddress 10.20.30.40

처음 두 줄은 실제 목적지가 쓸 인터페이스를 지목합니다. wg show 은 설정된 프리픽스 목록을 출력하고, Windows에서는 Find-NetRoute 이 패킷이 전송될 때 스택이 답할 것과 같은 질문에 답합니다. 인터페이스가 터널이라면 규칙이 맞은 것입니다.

다음으로 제외되어야 할 두 번째 패킷을 다른 애플리케이션에서 같은 목적지로 시험하십시오. 티켓에 클라이언트 버전, 규칙 유형, 프리픽스 또는 패키지 목록, 관찰된 두 결과를 기록하십시오. 그 결과 쌍이 다음 엔지니어에게 정책이 잘못 구성된 것인지 아니면 그 트래픽이 애초에 해당하지 않았는지 알려줍니다.

관련 글