Откриване на активен VPN в приложение за Mac в sandbox режим
Няма публичен 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: може ли платформата да наложи това, което ви трябва?
Когато изискването е гаранция, че нищо не излиза извън тунела, профилът е мястото за това, а не детекторът. Включването на includeAllNetworks в конфигурация за пълен тунел на iOS 14 или по-нова променя поведението на платформата, вместо да кара приложението ви да го извежда. Флагът е документиран в справката за NEVPNProtocol.
Това е различен вид отговор: налагане вместо наблюдение. Освен това важи само за профили, които контролирате, така че не помага на потребителско приложение, което наблюдава чужд тунел.
Проверка 6: направете отказа безопасен и наблюдаем
Изключете само възможността, която се нуждае от тунела, и оставете останалата част от приложението използваема. Детектор, който скрива целия интерфейс, когато не е сигурен, създава прекъсване за всеки, чийто тунел използва име, което никога не сте предвидили. Вместо това се върнете към консервативното поведение: локалните функции продължават да работят и само отдалеченото извикване, което наистина се нуждае от тунела, е изключено. Този избор е продуктово решение и заслужава да бъде записан до евристиката.
Записвайте какво сте наблюдавали: имена на интерфейси, версия на платформата и резултата от една проба. Това превръща следващия доклад от спор в проверка. След това предпочитайте поддържана декларация, където я имате, защото управлявана конфигурация може да носи намерението изрично и да премахне повечето причина да се проверяват имената изобщо.
Ако проверките от 1 до 5 са ви оставили без поддържан отговор, пуснете пробата и назовете резултата честно. Документиран сигнал за максимални усилия е по-добро продуктово решение от частен API, който се чупи в следващото издание.