Запитайте застосунок iOS, чи телефон у VPN, і чесна відповідь така: він не може цього знати в тому сенсі, який ви маєте на увазі. SDK не надає прапорця «пристрій у тунелі», а приватні інтерфейси, які могли б до цього наблизитися, закриті для застосунків, що публікуються. Ви можете спостерігати власну конфігурацію застосунку, стан, прив'язаний до неї, і одну-дві непрямі підказки з мережевого стеку. Кожна відповідає на інше питання, і більшість зламаних перевірок походить з того, що одну з них беруть за всю відповідь.

Міф про єдиний прапорець VPN

Вважається, що десь у SDK є властивість, яка повідомляє, чи пристрій у тунелі, так само як прапорець доступності повідомляє, чи відповідає хост. Такої публічної властивості не існує. І навіть якби вона була, «тунель існує» і «мій трафік його використовує» — різні твердження, і для більшості застосунків важливе лише друге.

Саме ця прогалина є причиною, чому бібліотеки, що рекламують детектор VPN в один рядок, зазвичай читають щось крихке, як-от назву інтерфейсу або ключ проксі, і подають це як вирок.

Завантажте налаштування, перш ніж довіряти nil

Спільний екземпляр менеджера існує одразу після запиту, але його властивість протоколу залишається nil, доки не завершиться зворотний виклик завантаження. Тож nil протоколу означає «ще не завантажено» принаймні так само часто, як «не встановлено». Виконуйте читання всередині блоку завершення і лише потім вирішуйте: наявний об'єкт протоколу з увімкненим прапорцем активації — так виглядає «встановлено».

Другий сигнал — на об'єкті з'єднання: недійсний стан, про який система повідомляє, коли цей застосунок не має встановленої конфігурації. Недійсний стан разом із nil протоколу після завершеного завантаження — це справжня відсутність, а не гонка в часі.

Зміни з'єднання надходять як сповіщення

Обробники, передані в load і save, повідомляють, що сталося з конфігурацією, а не що робить тунель. Чекання, що один із них спрацює під час підключення, — це гонка, яка ніколи не розв'язується. Натомість стежте за сповіщенням про зміну стану і читайте поточне значення об'єкта з'єднання, коли воно надходить.

Щойно конфігурацію встановлено, стан з'єднання проходить коротку послідовність: відключено, підключається, підключено, повторно підтверджує, відключається. «Підключено» описує тунель, а не сервер за ним, тож це не доказ, що трафік іде. On-demand може також піднімати тунель, коли застосунок призупинено, і тоді сповіщення надходить раніше, ніж у вас з'явиться що оновлювати.

Обмежений знімок проксі — це підказка, а не вирок

CFNetwork може передати застосунку поточні системні налаштування проксі, і всередині цього результату є обмежений словник із ключем за назвою інтерфейсу. Назва, що починається з tun, utun, ppp, ipsec або tap, — це підказка, що тунель є. Це залишається знімком того, що бачить цей застосунок, а не твердженням про те, куди мандрують пакети.

Провайдери розходяться в найменуванні, тож відсутній префікс нічого не доводить, а наявний інтерфейс може існувати, не несучи трафіку. Доступність ще слабша: успішний запит до приватної адреси показує, що шлях працював для цього запиту в той момент, а не що VPN встановлено.

Симулятор позичає Mac, а інші застосунки залишаються невидимими

Симулятор не має власного мережевого стеку; кожне з'єднання, яке він встановлює, — це з'єднання Mac. Тож VPN, що працює на хост-Mac, уже діє для симульованого застосунку, а налаштування самого симулятора нічого не показують. Якщо тунель піднявся після запуску симулятора, перезапустити його зазвичай швидше, ніж налагоджувати застосунок. Хосту на нестандартному порту потрібен цей порт в URL або локальне переспрямування, як-от socat TCP-LISTEN:12345,fork TCP:host:12345.

Публічні API не перелічуватимуть профілі VPN, що належать іншим застосункам або профілям конфігурації. Для одного відомого застосунку переносний трюк — перевірка схеми URL через canOpenURL, а від iOS 9 схема, про яку запитують, має бути оголошена у вашому Info.plist; якщо її пропустити, виклик поверне false. OpenVPN Connect відповідає на openvpn://, що робить його хорошим прикладом і поганим загальним детектором.

Об'єднайте три спостереження і скажіть, що вони означають

На практиці складіть три результати: конфігурацію, яка завантажилася і ввімкнена, стан з'єднання, який не є недійсним, і запит до адреси, доступної лише через тунель. Кожне окремо вводить в оману; разом вони кажуть, що застосунок може знати, а не що припускає користувач.

Запишіть результат як три рядки в діагностиці, а не як один boolean. Коли користувач каже, що VPN вимкнено, а ваш застосунок не погоджується, три рядки показують, яке спостереження розійшлося, і це різниця між зверненням до підтримки, за яким можна діяти, і таким, що закінчується словами «у мене працює».

Схожі статті