Een Android-app kan een interne naam niet oplossen terwijl de browser van de VPN-client zelf hem wel bereikt, en dezelfde build werkt op een andere telefoon. De URL is niet de variabele. De variabele is welk netwerk het proces van de app mag gebruiken voor resolutie, en Android garandeert niet dat de actieve VPN het netwerk is dat uw sockets gebruiken. Voer deze controles in volgorde uit en stop wanneer de resolver-snapshot niet overeenkomt met uw aanname.

Stap 1: bewijs op welk netwerk de app zit

Lees de eigen weergave van de app, niet de statusbalk. Haal uit ConnectivityManager het actieve netwerk, de bijbehorende LinkProperties, de lijst met DNS-servers en de instelling voor private DNS. Bevat de lijst de resolver van de VPN, dan heeft de app een pad ernaartoe; bevat hij de resolver van de Wi-Fi, dan is de tunnel niet het standaardnetwerk voor dat proces.

Een VPN-pictogram zegt alleen dat er een tunnel bestaat. Het zegt niet dat het proces van de app eraan gebonden was, en Android leidt naamresolutie niet altijd via het netwerk dat actief lijkt. Lokale VPN-apps die naar een ander apparaat doorsturen, Wi-Fi-netwerken zonder internet en builds van fabrikanten kunnen een app allemaal laten vragen naar de standaardresolver in plaats van de servers van de tunnel.

Stap 2: vraag het VPN-transport aan en bind het proces

Wanneer de app de resolver van de tunnel moet gebruiken, vraag een netwerk met VPN-transport aan en bind het proces in de callback, zodat de code niet raadt wanneer het netwerk verschijnt:

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

De aanroep verandert het standaardnetwerk van het hele proces, dus elke socket die daarna wordt gemaakt, gebruikt het. Sockets die al bestaan, houden het netwerk waarop ze zijn gemaakt, waardoor een verbindingspool die vóór de binding is geopend, via het oude pad kan blijven resolveren. De retourwaarde is een boolean, en een resultaat van false betekent dat de binding niet is gebeurd; probeer het opnieuw met een korte vertraging en log beide pogingen.

Stap 3: beperk de binding tot wat hem nodig heeft

Binding voor het hele proces is grof. Telemetrie, updatecontroles en SDK's van derden verhuizen ook naar de tunnel, en als de tunnel geen internet heeft, beginnen ze te falen. Gebruik voor één verzoek de socketfactory van het netwerk en laat de standaard van het apparaat voor al het andere. Kies bewust één model: een smalle binding per verbinding, of een procesbinding met een expliciete unbind wanneer de VPN verdwijnt.

Twee resolverfuncties kunnen de binding verslaan zonder enige fout. Private DNS in strikte modus stuurt query's naar een genoemde DoT-server in plaats van naar de resolver van het netwerk, en een app met een eigen DNS-over-HTTPS-client omzeilt de systeemresolver volledig. Controleer beide voordat u concludeert dat de binding mislukte. Een query die nooit de DNS-server van de VPN bereikt, verschijnt in geen enkel log aan de tunnelzijde.

Stap 4: vertrouw niet op een CONNECTED-beperking

NetworkType.CONNECTED van WorkManager betekent dat er een netwerk is verbonden, en het VPN-transport voldoet daaraan zelfs wanneer de onderliggende Wi-Fi- of mobiele verbinding weg is. De taak draait, elk verzoek mislukt, en het herhaalbeleid maakt er een storm van die op een planningsfout lijkt. De tunnel is een netwerk; de beperking was nooit een internetcontrole.

Controleer de capaciteit die het werk werkelijk nodig heeft, zoals gevalideerde internettoegang, en houd een begrensd herhaalbeleid met backoff aan. Als de taak een private naam nodig heeft, los die naam dan op in het geselecteerde netwerk voordat u het werk doet, en faal snel met een duidelijke fout in plaats van een verzoek te herhalen dat niet kan slagen.

Stap 5: leg het bewijs vast en test het bereik opnieuw

Log de transporttypen van het geselecteerde netwerk, de DNS-servers uit LinkProperties, of de binding true teruggaf, en de exacte fout van het eerste verzoek. Voer daarna een private naam en een openbare naam uit onder dezelfde binding. Dat paar laat zien of de app de resolver van de tunnel gebruikte of stil terugviel op de standaard van het apparaat, en dat is het verschil dat de gebruiker ervaart.

Herhaal dit op de oudste Android-versie die u ondersteunt en op één huidige release. Het resolvergedrag waardoor het standaardpad correct lijkt, is precies waar apparaten en versies verschillen, en een build die alleen op het nieuwste testapparaat slaagt, is niet geverifieerd voor het bereik dat u uitlevert. adb shell dumpsys connectivity is een snelle manier om te bevestigen welke netwerken en mogelijkheden het apparaat meldt terwijl u de fout reproduceert.

Gerelateerde artikelen