Egy Android-alkalmazás nem tud feloldani egy belső nevet, miközben a VPN-kliens saját böngészője eléri, és ugyanaz a build egy másik telefonon működik. Az URL nem változó. A változó az, hogy az alkalmazás folyamata melyik hálózatot használhatja a feloldáshoz, és az Android nem garantálja, hogy az aktív VPN az, amelyet a socketjeink használnak. Végezzük el ezeket az ellenőrzéseket sorrendben, és álljunk meg, amikor a feloldó pillanatképe ellentmond a feltételezésünknek.

1. lépés: Bizonyítsuk be, melyik hálózaton van az alkalmazás

Az alkalmazás saját nézetét olvassuk, ne az állapotsort. A ConnectivityManager-ból kérjük le az aktív hálózatot, annak LinkProperties-jét, a DNS-kiszolgálók listáját és a privát DNS beállítását. Ha a lista tartalmazza a VPN feloldóját, az alkalmazásnak van arra útvonala; ha a Wi-Fi feloldóját tartalmazza, az alagút nem az adott folyamat alapértelmezett hálózata.

A VPN ikon csak azt mondja, hogy létezik alagút. Azt nem, hogy az alkalmazás folyamata ahhoz volt kötve, és az Android nem mindig az aktívnak látszó hálózaton keresztül irányítja a névfeloldást. A másik eszközre továbbító helyi VPN-alkalmazások, az internet nélküli Wi-Fi hálózatok és a gyártói buildek mind oda vezethetnek, hogy az alkalmazás az alapértelmezett feloldót kérdezi az alagút kiszolgálói helyett.

2. lépés: Kérjük a VPN transzportot, és kössük a folyamatot

Amikor az alkalmazásnak az alagút feloldóját kell használnia, kérjünk VPN transzporttal rendelkező hálózatot, és a visszahívásban kössük a folyamatot, hogy a kód ne találgassa, mikor jelenik meg a hálózat:

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)
    }
})

A hívás az egész folyamat alapértelmezett hálózatát megváltoztatja, így minden utána létrehozott socket azt használja. A már létező socketek megtartják a létrehozásukkori hálózatot, ezért a kötés előtt megnyitott kapcsolatkészlet továbbra is a régi útvonalon oldhat fel. A visszatérési érték logikai érték, a hamis eredmény azt jelenti, hogy a kötés nem történt meg; próbáljuk újra rövid késleltetéssel, és naplózzuk mindkét kísérletet.

3. lépés: Szűkítsük a kötést arra, aminek szüksége van rá

Az egész folyamatra kiterjedő kötés durva. A telemetria, a frissítésellenőrzések és a harmadik féltől származó SDK-k is átkerülnek az alagútra, és ha az alagútnak nincs internete, elkezdenek meghibásodni. Egyetlen kéréshez használjuk a hálózat socketgyárát, és minden mást hagyjunk az eszköz alapértelmezésén. Tudatosan válasszunk egy modellt: szűk kötés kapcsolatonként, vagy folyamatkötés kifejezett oldással, amikor a VPN eltűnik.

A feloldó két szolgáltatása hiba nélkül is legyőzheti a kötést. A szigorú módú privát DNS a lekérdezéseket egy megnevezett DoT-kiszolgálóra küldi a hálózati feloldó helyett, és az a saját DNS-over-HTTPS klienst szállító alkalmazás teljesen megkerüli a rendszerfeloldót. Mindkettőt ellenőrizzük, mielőtt arra jutunk, hogy a kötés meghiúsult. Az a lekérdezés, amely soha nem érkezik meg a VPN DNS-kiszolgálójára, egyetlen alagút oldali naplóban sem fog megjelenni.

4. lépés: Ne bízzunk a CONNECTED feltételben

A WorkManager NetworkType.CONNECTED feltétele azt jelenti, hogy egy hálózat csatlakoztatva van, és a VPN transzport ezt akkor is teljesíti, amikor az alatta lévő Wi-Fi vagy mobil kapcsolat megszűnt. A feladat lefut, minden kérés meghiúsul, és az újrapróbálkozási szabályzat olyan viharrá alakítja, amely ütemezési hibának látszik. Az alagút egy hálózat; a feltétel soha nem volt internetellenőrzés.

Ellenőrizzük a feladat által ténylegesen igényelt képességet, például az igazolt internetelérést, és tartsunk korlátozott, visszalépéses újrapróbálkozási szabályzatot. Ha a feladatnak privát névre van szüksége, oldjuk fel azt a nevet a kiválasztott hálózatban a munka előtt, és gyorsan, világos hibával álljunk le, ahelyett hogy olyan kérést ismételnénk, amely nem sikerülhet.

5. lépés: Rögzítsük a bizonyítékokat, és teszteljük újra a tartományt

Naplózzuk a kiválasztott hálózat transzporttípusait, a LinkProperties-ből származó DNS-kiszolgálókat, hogy a kötés igazat adott-e vissza, és az első kérés pontos hibáját. Ezután futtassunk egy privát nevet és egy nyilvános nevet ugyanazon kötés alatt. Ez a pár megmutatja, hogy az alkalmazás az alagút feloldóját használta-e, vagy csendben visszaesett az eszköz alapértelmezésére, és ez az a különbség, amelyet a felhasználó tapasztal.

Ismételjük meg a legrégebbi támogatott Android-verzión és egy jelenlegi kiadáson. Az a feloldóviselkedés, amely miatt az alapértelmezett útvonal helyesnek látszik, pontosan az, ahol az eszközök és verziók eltérnek, és az a build, amely csak a legújabb teszteszközön megy át, nincs igazolva a szállított tartományra. A adb shell dumpsys connectivity gyors módja annak ellenőrzésére, milyen hálózatokat és képességeket jelent az eszköz, miközben a hibát reprodukáljuk.

Kapcsolódó cikkek