iOS 앱에 휴대폰이 VPN에 연결되어 있는지 물으면, 정직한 답은 앱이 당신이 뜻하는 방식으로는 알 수 없다는 것입니다. SDK는 «기기가 터널 안에 있다»는 플래그를 제공하지 않으며, 그에 가까운 정보를 줄 수 있는 비공개 인터페이스는 출시되는 앱에 닫혀 있습니다. 관찰할 수 있는 것은 앱 자체의 구성, 그에 연결된 상태, 그리고 네트워크 스택에서 나오는 한두 가지 간접 단서입니다. 각각은 다른 질문에 답하며, 잘못된 검사의 대부분은 그중 하나를 답 전체로 여기는 데서 나옵니다.

단일 VPN 플래그라는 신화

도달 가능성 플래그가 호스트의 응답 여부를 알려 주듯, SDK 어딘가에 기기가 터널 안에 있는지 알려 주는 속성이 있을 것이라는 믿음이 있습니다. 그런 공개 속성은 없습니다. 설령 있다 해도 «터널이 존재한다»와 «내 트래픽이 그것을 쓴다»는 다른 주장이고, 대부분의 앱에는 두 번째만 중요합니다.

바로 이 간극 때문에 한 줄짜리 VPN 탐지기를 광고하는 라이브러리가 인터페이스 이름이나 프록시 키처럼 취약한 것을 읽고 그것을 판정으로 제시하곤 합니다.

nil을 믿기 전에 설정을 읽어 들여라

공유 매니저 인스턴스는 요청하는 즉시 존재하지만, 그 프로토콜 속성은 로드 콜백이 끝날 때까지 nil로 남습니다. 따라서 nil 프로토콜은 «아직 로드되지 않음»을 «설치되지 않음»만큼 자주 뜻합니다. 읽기는 완료 블록 안에서 하고, 그다음에야 판단하십시오. 존재하는 프로토콜 객체에 활성화 플래그가 켜져 있는 것이 «설치됨»의 모습입니다.

두 번째 신호는 연결 객체에 있습니다. 이 앱에 설치된 구성이 없을 때 시스템이 보고하는 무효 상태입니다. 로드가 끝난 뒤의 nil 프로토콜과 무효 상태가 함께 있으면 그것은 진짜 부재이며, 타이밍 경합이 아닙니다.

연결 변화는 알림으로 도착한다

load와 save에 넘긴 핸들러는 구성에 무슨 일이 있었는지를 보고하며, 터널이 무엇을 하는지는 알려 주지 않습니다. 연결 시점에 둘 중 하나가 발동하기를 기다리는 것은 결코 풀리지 않는 경합입니다. 대신 상태 변경 알림을 지켜보고, 그것이 도착하면 연결 객체의 현재 값을 읽으십시오.

구성이 설치되면 연결 상태는 짧은 순서를 지납니다. 연결 끊김, 연결 중, 연결됨, 재확인 중, 연결 해제 중입니다. «연결됨»은 터널을 설명할 뿐 그 뒤의 서버를 설명하지 않으므로 트래픽이 흐른다는 증거가 아닙니다. On-demand는 앱이 일시 중단된 동안에도 터널을 올릴 수 있고, 그러면 갱신할 것이 생기기도 전에 알림이 도착합니다.

제한된 프록시 스냅샷은 단서이지 판정이 아니다

CFNetwork는 앱에 시스템의 현재 프록시 설정을 넘겨줄 수 있고, 그 결과 안에는 인터페이스 이름을 키로 한 제한된 사전이 있습니다. tun, utun, ppp, ipsec, tap으로 시작하는 이름이 보인다면 터널이 있다는 단서입니다. 그것은 이 앱이 볼 수 있는 범위의 스냅샷일 뿐, 패킷이 어디로 가는지에 대한 진술이 아닙니다.

제공자마다 이름 규칙이 달라 접두사가 없다고 해서 아무것도 증명되지 않으며, 인터페이스가 있어도 트래픽을 나르지 않을 수 있습니다. 도달 가능성은 더 약합니다. 사설 주소에 대한 성공한 요청은 그 순간 그 요청에 경로가 통했다는 것일 뿐, VPN이 설치되어 있다는 뜻이 아닙니다.

시뮬레이터는 Mac을 빌리고, 다른 앱은 보이지 않는다

시뮬레이터에는 자체 네트워크 스택이 없습니다. 그것이 만드는 모든 연결은 Mac의 것입니다. 따라서 호스트 Mac에서 도는 VPN은 시뮬레이션된 앱에 이미 적용되어 있고, 시뮬레이터 자체 설정에는 아무것도 표시되지 않습니다. 시뮬레이터를 시작한 뒤에 터널이 올라왔다면 앱을 디버그하는 것보다 다시 시작하는 편이 보통 빠릅니다. 비표준 포트의 호스트라면 그 포트를 URL에 넣거나 socat TCP-LISTEN:12345,fork TCP:host:12345 같은 로컬 전달이 필요합니다.

공개 API는 다른 앱이나 구성 프로파일에 속한 VPN 프로파일을 열거하지 않습니다. 알려진 한 앱의 경우 canOpenURL을 통한 URL 스킴 검사가 이식 가능한 요령이며, iOS 9부터는 질의하는 스킴을 Info.plist에 선언해야 합니다. 빠뜨리면 호출은 false를 반환합니다. OpenVPN Connect는 openvpn://에 응답하므로 좋은 예이자 나쁜 범용 탐지기입니다.

세 가지 관찰을 결합하고 그것이 무엇을 뜻하는지 말하라

실무에서는 세 결과를 겹쳐 놓으십시오. 로드되어 활성화된 구성, 무효가 아닌 연결 상태, 그리고 터널로만 닿을 수 있는 주소에 대한 요청입니다. 각각은 단독으로 오해를 부르지만, 셋을 함께 두면 사용자가 가정하는 것이 아니라 앱이 알 수 있는 것을 말해 줍니다.

결과는 진단 정보에 세 줄로 쓰고 하나의 불리언으로 쓰지 마십시오. 사용자가 VPN이 꺼져 있다고 하는데 앱이 동의하지 않을 때, 세 줄은 어느 관찰이 어긋났는지를 보여 줍니다. 그것이 조치할 수 있는 지원 티켓과 «제 쪽에서는 됩니다»로 끝나는 티켓의 차이입니다.

관련 글