두 사람이 같은 질문을 하고 서로 맞지 않는 답을 얻는다. 서 있는 자리가 다르기 때문이다. 한 사람은 시스템 VPN 설정 화면을 열어 앱 목록을 편집하고 있다. 다른 사람은 편집기에서 VpnService.Builder.addDisallowedApplication()을 쓰고 있다. 둘 다 그것을 앱별 VPN 필터라고 부른다. 그들이 설명하는 제어를 실제로 가진 사람은 한 명뿐이고, 둘 다 아무것도 차단하고 있지 않다.

사용자가 보는 화면에서 시작하자

설정을 열고 VPN 항목을 찾아 실제로 활성화된 연결을 보라. 클라이언트가 앱별 목록을 제공한다면 그 목록은 클라이언트 자신의 터널에 속한다. 플랫폼은 무관한 앱이 다른 VPN의 앱 선택을 읽거나 편집할 수 있는 일반 API를 공개하지 않으므로, 두 번째 앱이 사용자를 대신해 그 목록을 고칠 수는 없다.

이것이 이 안내의 첫 갈림길이다. 설치된 VPN에 그런 설정이 없다면 코드로 우회할 것이 없다. 터널을 소유한 제품에 그 기능이 없는 것이다. 있다면 올바른 수정은 그 화면에서, 그것을 열 수 있는 사람이 한다.

패킷을 터널 안으로 따라가자

자신의 앱이 터널을 만들 때는 TUN 인터페이스를 만들고 어떤 앱의 트래픽이 그 안으로 들어가는지 선언한다. 멤버십 호출은 인터페이스가 설정되기 전에 일어나고, 그 뒤로 그 세션의 규칙 집합은 고정된다.

val builder = VpnService.Builder()
builder.addAddress("10.8.0.2", 32)
builder.addRoute("0.0.0.0", 0)
builder.addDisallowedApplication("com.example.bypass")
val tun = builder.establish()   // membership decided here

그 호출들은 방금 앱이 만든 터널에만 적용되고 다른 무엇에도 적용되지 않는다. 기기 전체의 정책이 아니고, 다른 클라이언트를 위해 유지되지 않으며, 다른 사람의 VPN에 닿을 수도 없다. 패키지를 해석할 수 없어 빌더 호출이 예외를 던지면 인터페이스는 결코 설정되지 않는데, 이는 조용한 실패가 아니라 깔끔한 실패다.

제외가 차단처럼 보인 이유

제외된 앱은 여러분의 터널을 우회해 하위 네트워크로 간다. 그것은 차단의 반대다. 트래픽은 여전히 기기를 떠나며, 다만 여러분이 제어하는 인터페이스 밖으로 나간다. 방화벽 스타일 앱은 그 반대를 한다. 앱의 트래픽을 자기 터널로 받아들인 뒤 패킷을 버리거나 전달을 거부한다. 인터페이스는 같고 정책의 방향이 뒤집혀 있는 것이다.

그 반전 뒤의 작업은 설정 플래그가 아니다. 터널 디스크립터에서 IP 패킷을 읽고 흐름별로 판단한 뒤, 보호된 소켓으로 전달하거나 버린다. 처리하지 않은 것은 그저 멈추므로, 반쯤 만든 터널은 동작하는 필터가 아니라 고장 난 네트워크처럼 보인다. 목표가 차단이라면 패킷 처리, 포그라운드 서비스, 분류할 수 없는 트래픽에 대한 문서화된 정책을 예산에 넣어야 한다.

직접 만들 때 깨지는 것

Android는 보통 한 번에 하나의 활성 VPN만 허용하므로, 제품이 체이닝을 지원하지 않는 한 필터 터널과 프라이버시 터널은 같은 자리를 두고 경쟁한다. 연결 차단을 켠 상시 VPN은 실패 방식을 바꾸는데, 여기서 중요한 지점이 있다. 터널로 들어갈 수 없는 트래픽은 직접 전송되는 대신 버려진다. 유출 방지 설계가 원하는 것이고 디버깅 세션이 거의 예상하지 못하는 것이다.

패키지 가시성이 두 번째 함정이다. 앱의 패키지 이름 해석은 NameNotFoundException로 실패할 수 있고, 최신 Android에서는 볼 수 있는 패키지 집합이 선언한 쿼리에 달려 있다. 모든 이름이 해석된다고 가정하지 말고 예외를 처리하며, 앱이 설치되거나 제거될 때 목록을 다시 읽어야 한다. 영원히 캐시에 두지 말고.

관리되는 기기는 세 번째 소유자를 더한다. 기업 모빌리티 정책은 앱별 VPN이나 상시 프로파일을 설정할 수 있고, 일반 앱은 그것을 덮어쓸 수 없다. 자신의 코드를 디버깅하기 전에 기기가 관리되는지 확인하라. 그 경우 바꾸려는 목록은 전화기를 들고 있는 누구도 편집할 수 없을지 모른다.

직접 제어하는 앱으로 시험하자

필터하려는 앱으로 시험하지 마라. 네트워크 동작을 관찰할 수 있는 두 번째 앱을 쓰고, 그 트래픽이 여러분의 터널을 통해 나가는 반면 대상의 트래픽은 나가지 않는지 확인하라. 둘 다 안에 남으면 정책이 동작하고 대상이 제외된 것이다. 둘 다 나가지 않으면 터널 자체가 잘못된 것이고 앱 목록은 문제가 아니다.

그다음 세 가지 중 무엇을 실제로 만드는지 정하라. 앱별 터널은 빌더 API이고, 목록은 프로파일의 일부다. 기기 방화벽은 패킷 처리에 더해 설명할 수 있는 수명 주기가 필요하다. 다른 사람의 VPN을 바꾸는 것은 애초에 지원되는 경로가 아니며, 거기서 정직한 답은 그 설정이 그 제품에 속한다는 것이다.

관련 글