Застосунок Android не може розв'язати внутрішнє ім'я, хоча браузер самого VPN-клієнта до нього доходить, і та сама збірка працює на іншому телефоні. URL не є змінною. Змінна — це те, яку мережу процесу застосунку дозволено використовувати для розв'язання, і Android не гарантує, що активний VPN — це та мережа, яку використовують ваші сокети. Виконайте ці перевірки по порядку і зупиніться, коли знімок resolver-а не збігається з вашим припущенням.

Крок 1: доведіть, у якій мережі перебуває застосунок

Читайте власне подання застосунку, а не рядок стану. З ConnectivityManager отримайте активну мережу, її LinkProperties, список DNS-серверів і налаштування приватного DNS. Якщо список містить resolver VPN, застосунок має шлях до нього; якщо там resolver Wi-Fi, тунель не є мережею за замовчуванням для цього процесу.

Значок VPN говорить лише про те, що тунель існує. Він не говорить, що процес застосунку був прив'язаний до нього, і Android не завжди спрямовує розв'язання імен через мережу, яка виглядає активною. Локальні VPN-застосунки, що передають трафік на інший пристрій, мережі Wi-Fi без інтернету та збірки виробників можуть залишити застосунок питати resolver за замовчуванням замість серверів тунелю.

Крок 2: запитайте транспорт VPN і прив'яжіть процес

Коли застосунок зобов'язаний використовувати resolver тунелю, запитайте мережу з транспортом VPN і прив'яжіть процес у колбеку, щоб код не вгадував, коли з'явиться мережа:

val request = NetworkRequest.Builder()
    .addTransportType(NetworkCapabilities.TRANSPORT_VPN)
    .build()

connectivityManager.requestNetwork(request, object : NetworkCallback() {
    override fun onAvailable(network: Network) {
        val bound = connectivityManager.bindProcessToNetwork(network)
        Log.i(TAG, "bound to VPN network: " + bound)
    }
})

Виклик змінює мережу за замовчуванням для всього процесу, тому кожен створений після нього сокет використовує її. Уже наявні сокети зберігають мережу, у якій були створені, тому пул з'єднань, відкритий до прив'язки, може продовжувати розв'язання старим шляхом. Повернене значення — boolean, і результат false означає, що прив'язка не відбулася; повторіть спробу з невеликою затримкою і зафіксуйте обидві спроби.

Крок 3: обмежте прив'язку тим, чому вона потрібна

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

Дві властивості resolver-а можуть подолати прив'язку без жодної помилки. Приватний DNS у строгому режимі надсилає запити на іменований сервер DoT замість resolver-а мережі, а застосунок із власним клієнтом DNS-over-HTTPS повністю обходить системний resolver. Перевірте обидві, перш ніж зробити висновок, що прив'язка не вдалася. Запит, який так і не доходить до DNS-сервера VPN, не з'явиться в жодному журналі на боці тунелю.

Крок 4: не довіряйте обмеженню CONNECTED

NetworkType.CONNECTED у WorkManager означає, що мережа підключена, і транспорт VPN задовольняє це навіть тоді, коли Wi-Fi або стільниковий канал під ним зник. Завдання виконується, кожен запит зазнає невдачі, і політика повторів перетворює це на бурю, схожу на помилку планування. Тунель — це мережа; обмеження ніколи не було перевіркою інтернету.

Перевірте можливість, яка справді потрібна роботі, наприклад підтверджений доступ до інтернету, і тримайте обмежену політику повторів із затримкою. Якщо завданню потрібне приватне ім'я, розв'яжіть це ім'я у вибраній мережі до виконання роботи і швидко завершіться з чіткою помилкою замість повторення запиту, який не може бути успішним.

Крок 5: зафіксуйте докази і перевірте діапазон ще раз

Запишіть типи транспорту вибраної мережі, DNS-сервери з LinkProperties, чи повернула прив'язка true і точну помилку першого запиту. Потім виконайте приватне ім'я і публічне ім'я за тієї самої прив'язки. Ця пара показує, чи застосунок використав resolver тунелю, чи тихо повернувся до типового налаштування пристрою, і це та різниця, яку відчуває користувач.

Повторіть на найстарішій підтримуваній версії Android і на одному поточному випуску. Поведінка resolver-а, через яку типовий шлях виглядає правильним, — це саме те місце, де різняться пристрої та версії, а збірка, що проходить лише на найновішому тестовому пристрої, не перевірена для діапазону, який ви постачаєте. adb shell dumpsys connectivity — швидкий спосіб підтвердити, які мережі та можливості повідомляє пристрій, поки ви відтворюєте збій.

Схожі статті