Android 앱이 VPN에서 실행을 거부한다: 어느 계층이 판단하는가
앱은 로컬 전송 검사, 서버 측 주소 규칙 또는 자체 정책 때문에 VPN을 거부할 수 있다. 출구를 바꾸기 전에 이 세 가지를 구분해야 한다.
Android 앱이 터널이 올라오는 순간 작동을 멈출 때, 원인이 될 수 있는 것은 세 가지 서로 다른 일이며 그것들은 비슷해 보이는 실패를 만든다. 앱이 휴대폰 자체의 네트워크 상태를 읽고 로컬에서 거부할 수 있다. 서버가 도착 주소를 분류해 거부할 수 있다. 아니면 거부가 VPN과 전혀 무관할 수도 있다. 아래 순서는 무엇이든 바꾸기 전에 증거를 모으는데, 출구를 바꾸는 것이 가장 비싼 단계이고 검사가 로컬일 때 도움이 될 가능성이 가장 낮기 때문이다.
1단계: 앱이 언제 거부하는지 파악하기
시점이 첫 번째 구분 기준이다. 로그 버퍼를 비우고 실패를 재현한 뒤, 앱이 불평하기 전에 무엇을 했는지 보라:
adb logcat -c
# reproduce the failure in the app
adb logcat -d | grep -iE 'vpn|network|connect|http' | tail -60
어떤 발신 요청도 시도되기 전에 앱이 거부한다면 로컬 판단을 보고 있는 것이다. 연결하고 무언가를 보낸 뒤 오류를 표시한다면 거부는 반대편에서 온 것이다. 터널을 내린 상태에서도 앱이 똑같이 실패한다면 VPN은 애초에 변수가 아니었다.
그 시점을 확정이 아니라 증거로 다루라. 앱은 캐시된 응답을 다시 재생할 수 있고, 백그라운드 요청은 당신이 보기 전에 성공하거나 실패했을 수 있다. 메시지가 나타난 순간만이 아니라 마지막 성공 요청과 오류의 타임스탬프를 기록하라.
2단계: 휴대폰 자체의 네트워크 관점 읽기
Android는 VPN 상태를 네트워크 기능으로 노출하므로, 앱이 터널이 활성임을 알아차리는 데 상용 공급자 목록이 필요하지 않다. 앱은 연결 서비스에 현재 네트워크가 무엇인지 묻고, 그 답에는 VPN 전송 비트가 포함된다:
val cm = context.getSystemService(ConnectivityManager::class.java)
val caps = cm.getNetworkCapabilities(cm.activeNetwork)
val onVpn = caps?.hasTransport(NetworkCapabilities.TRANSPORT_VPN) == true
그 검사는 로컬이고 값싸며, 원격 분류 없이도 “이 앱은 VPN에서 작동하지 않는다”는 종류의 보고를 통째로 설명한다. 앱이 볼 수 있는 것은 여전히 자체 네트워크 맥락에 달려 있으므로 모든 앱이 기기의 모든 프로필을 검사한다고 가정하지 마라.
워크스테이션에서 시험 기기에 adb shell dumpsys connectivity 를 사용하고 VPN 네트워크 항목을 찾아 같은 상태를 볼 수 있다. 터널을 올린 실행과 내린 실행을 비교하고 두 출력을 모두 보관하라.
3단계: 서버가 실제로 보는 것 읽기
다른 관찰자는 서비스다. 도착하는 출발지 주소를 보며, 주소와 그 뒤의 호스팅 네트워크, 지역, 통신사 또는 계정과 기기에 묶인 신호에 따라 행동할 수 있다. 그중 어느 것도 고유한 신원이 아니며, 주소 공유 때문에 곁가지 차단은 흔한 일이다. 제한된 주소 하나가 같은 번역 뒤의 무관한 사용자들을 함께 끌어내릴 수 있다.
주소는 앱이 쓰는 것과 같은 경로로 얻어라. 노트북 브라우저에서가 아니다. 휴대폰에서 주소 반향 서비스로 보낸 단순한 요청은 먼 쪽이 무엇을 받는지 보여 주고, 그것을 셀룰러를 통한 요청과 비교하면 주소가 애초에 바뀌었는지 알 수 있다.
앱이 셀룰러에서는 작동하고 같은 계정으로 터널에서는 실패한다면 거부는 먼 쪽이나 앱 자체 정책에 있다. 둘 다에서 실패한다면 VPN은 구분 요인이 아니며 끝점 시험을 멈춰야 한다.
4단계: 증거를 세 가지 판정 중 하나에 맞추기
세 가지 조합이 거의 모든 보고를 덮는다. 터널이 활성인데 발신 시도가 전혀 없는 거부는 로컬 전송 검사를 가리킨다. 나갔다가 오류, 특정 호스트의 시간 초과 또는 지역 메시지와 함께 돌아오는 요청은 먼 쪽을 가리킨다. 터널 없이 셀룰러에서 재현되는 실패는 계정, 앱 버전 또는 서비스 자체 정책을 가리키며, 어떤 VPN 변경도 그것을 움직이지 못한다.
판정을 그것을 낳은 증거와 함께 적어라. 이 단계의 가치는 휴대폰 자체에서 도는 검사를 고치려고 누군가 네 번이나 출구 노드를 바꾸는 순환을 멈춘다는 데 있다.
주장을 정직하게 유지하는 효과도 있다. 직접 호스팅은 끝점과 그 인터넷 출구를 바꾸지만, Android가 VPN 네트워크가 활성임을 잊게 만들지 않고 주소를 분류하는 서비스의 수용을 보장하지도 않는다. 로컬 필터는 상용 VPN 네트워크에서만큼이나 자신이 소유한 VPN 네트워크에서도 쉽게 작동할 수 있다.
5단계: 지원되는 경로를 택하고 검증하기
제품의 문서화된 정책과 그 지원 책임자에서 시작하라. 클라이언트 버전, 정확한 메시지, 좁은 실패 시간대를 보내라. 오류가 존재함을 증명하려고 전체 트래픽 캡처나 자격 증명을 보내지 마라.
서비스가 직접 접근을 허용하고 기기 정책이 그것을 허용한다면 앱별 제외가 지원되는 방식이며, 터널을 숨기는 대신 그 앱을 의도적으로 터널에서 빼낸다. 그러면 앱의 트래픽은 자체 경로로 나가며, 이는 누군가 책임져야 하는 정책 결정이다. VPN 없이 차단하는 구성에서는 제외된 앱이 단순히 연결을 잃을 수 있으므로, 작동한다고 약속하기 전에 그 조합을 시험하라.
어떤 변경 뒤에도 첫 단계의 시점 시험을 반복하고, 앱이 작동하는지 확인하며, 다른 모든 앱이 여전히 터널을 쓰는지 확인하라. 그다음 이전 구성을 되돌리고 실패가 다시 나타나는지 확인하라. 재현할 수 없는 수정은 다시 만나게 될 우연이기 때문이다.