샌드박스된 Mac 앱에서 활성 VPN 감지하기
이 질문에 대한 공개 API는 없고, 인터페이스 이름을 쓰는 방법은 하나의 휴리스틱일 뿐입니다. 앱이 실제로 무엇에 의존해야 하는지 결정하는 여섯 가지 점검.
터널이 켜져 있을 때 다르게 동작하는 화면이 하나 필요하지만, 그것을 알려 주는 호출은 없습니다. 이것이 출시 제약입니다. macOS에서는 어떤 공개 프레임워크도 임의의 VPN 연결 여부를 보고하지 않고, iOS에서는 상태가 구성을 설치한 앱에 속합니다. 아래 점검들은 그 한계에서 출시 가능한 무언가로 이어지며, 어느 것이든 탐색을 일찍 끝낼 수 있습니다.
점검 1: 이 질문에 답할 수 있는가?
샌드박스는 어떤 API보다 먼저 질문을 해결합니다. 서드파티 프로세스는 다른 업체의 확장을 열거할 수 없고 그 확장의 구성도 읽을 수 없으므로, 물어볼 수 있는 지원 객체가 없습니다.
모든 우회 방법은 같은 벽에 부딪힙니다. 인터페이스 목록, scutil --nc list 그리고 시스템 구성 직접 읽기는 샌드박스가 보류하는 권한을 요구하거나 Apple이 결코 약속하지 않은 동작에 의존합니다. 계획에 그중 하나가 필요하다면 문제는 계획입니다. 문서화되지 않은 세부 사항 위에 세운 기능은 배송 날짜가 붙은 지원 티켓입니다.
점검 2: 앱이 터널을 직접 관리하는가?
그렇다면 자기 구성에 대해 지원되는 답이 있습니다. 환경설정을 불러오고 오류를 처리한 다음 상태를 읽고, 폴링 대신 변경을 구독하십시오:
vpnManager.loadFromPreferences { error in
// handle a load failure before reading status
}
NotificationCenter.default.addObserver(
forName: .NEVPNStatusDidChange,
object: nil,
queue: nil
) { note in
let status = (note.object as? NEVPNConnection)?.status
}이것이 무엇을 반환하는지 정확히 하십시오. 설치한 터널의 상태입니다. 다른 클라이언트를 쓰는 사용자는 연결 끊김으로 표시되며, 그것은 코드의 버그가 아닙니다. 답 위에 무언가를 짓기 전에 기능이 실제로 두 질문 중 어느 것을 묻고 있는지 결정하십시오.
점검 3: 휴리스틱이 실제로 무엇을 알려 주는가?
널리 복사된 접근은 시스템 프록시 사전에 범위 지정 항목을 물어보고 키를 읽는데, 그 키가 우연히 인터페이스 이름입니다:
let settings = CFNetworkCopySystemProxySettings()?.takeRetainedValue() as NSDictionary?
let scoped = settings?["__SCOPED__"] as? [String: Any]
let names = scoped?.keys ?? []키가 tap, tun, ppp, ipsec 또는 utun 로 시작하면 터널 범위의 인터페이스가 있음을 뜻합니다. 전체 이름을 맞추는 것은 즉시 실패합니다. iOS 12에 utun1과 utun2가 들어왔고 일부 프로파일은 ipsec4, ppp0, utun0으로 나타나기 때문입니다. 대신 접두사를 비교하십시오.
그럼에도 이름은 소유자를 식별하지 않습니다. 시스템 기능과 다른 업체의 확장도 utun 인터페이스를 만들며, 당신의 트래픽을 전혀 나르지 않으면서 존재할 수 있습니다. 주변에 터널 모양의 무언가가 있다는 힌트로 읽으십시오, 그 이상은 아닙니다. 여기서의 거짓 양성은 기능 하나만 제한하면 싸고, 로그인 화면을 제한하면 비쌉니다.
점검 4: 대신 목적지를 시험할 수 있는가?
앱이 내부 서비스에 도달할 수 있는지만 알면 된다면 그 서비스를 시험하십시오. 시간 제한이 있는 짧은 프로브는 기능이 실제로 의존하는 질문에 답하며, 사용자가 클라이언트를 바꾸거나 터널 모양이 바뀌어도 계속 작동합니다.
도달 가능성은 당신의 경로에 대한 관찰입니다. 인터페이스 이름은 경로에 인접한 무언가에 대한 추론이며, 그래서 휴리스틱은 버그 보고서에서 논쟁을 만들고 프로브는 증거를 만듭니다. 사용자가 VPN이 켜져 있다고 주장하는데 프로브가 실패하면 이제 디버그할 구체적인 경로가 있습니다. 이름 해석, 경로, 서비스 권한입니다.
점검 5: 플랫폼이 필요한 것을 강제할 수 있는가?
요구 사항이 터널에서 아무것도 빠져나가지 않는다는 보장이라면, 프로파일이 그 자리이고 탐지기가 아닙니다. iOS 14 이상의 전체 터널 구성에서 includeAllNetworks 를 켜면 앱이 추론하게 하는 대신 플랫폼 동작이 바뀝니다. 이 플래그는 NEVPNProtocol 참조 에 문서화되어 있습니다.
이것은 다른 종류의 답입니다. 관찰 대신 강제입니다. 또한 당신이 제어하는 프로파일에만 적용되므로, 남의 터널을 지켜보는 소비자 앱에는 도움이 되지 않습니다.
점검 6: 실패를 안전하고 관찰 가능하게 만들기
터널이 필요한 기능만 끄고 앱의 나머지는 쓸 수 있게 두십시오. 확신이 없을 때마다 전체 인터페이스를 숨기는 탐지기는 예상하지 못한 이름을 쓰는 터널의 모든 사용자에게 장애를 만들어 냅니다. 대신 보수적 동작으로 돌아가십시오. 로컬 기능은 계속 작동하고 정말로 터널이 필요한 원격 호출만 비활성화됩니다. 그 선택은 제품 결정이며, 휴리스틱 옆에 적어 둘 가치가 있습니다.
관찰한 것을 기록하십시오. 인터페이스 이름, 플랫폼 버전, 프로브 한 번의 결과입니다. 그것이 다음 보고서를 논쟁에서 점검으로 바꿉니다. 그다음 지원되는 선언이 있으면 그것을 선호하십시오. 관리형 구성은 의도를 명시적으로 담을 수 있고 이름을 검사할 이유의 대부분을 없앨 수 있습니다.
점검 1부터 5까지가 지원되는 답 없이 남겨 두었다면, 프로브를 출시하고 결과를 정직하게 표시하십시오. 문서화된 최선 노력 신호는 다음 릴리스에서 깨지는 비공개 API보다 나은 제품 결정입니다.