Verdien nådde VpnService.Builder.addDnsServer som en streng, og builderen avviste den der før noe ble etablert. Avvisningen er lokal: ingen resolver er kontaktet, det finnes ingen tunnel, og det som feilet er en formatkontroll, ikke et DNS-utfall.

Dette betyr noe fordi en typisk VPN-app har tre like DNS-innganger: en verdi skrevet eller importert i profilen, en verdi serveren sender under konfigurasjon, og Private DNS på systemnivå. Bare de to første når dette kallet.

Et forberedelsesobjekt sjekker argumentet med en gang

VpnService.Builder er ikke tunnelen. Det er et forberedelsesobjekt som samler adresser, ruter og servere, og bare establish() gjør disse listene til et levende ParcelFileDescriptor og et grensesnitt. DNS-oppføringen sjekkes når du kaller addDnsServer.

To konsekvenser: sporet er kort og med vilje intetsigende, og en slurvete catch rundt hele bygget etterlater en tunnel uten resolver.

Builderen beholder enhver liste du gir den; å legge til en server som består kontrollen beviser bare at strengen ble parset som adresseliteral ved byggetid.

Hva argumentet kan være

Parameteren er en adresse, ikke et endpoint. Builder-referansen tar et IPv4- eller IPv6-literal, og parsingen er bare numerisk: android.net.InetAddresses.parseNumericAddress er det offentlige ansiktet til den parseren fra API 29.

Den praktiske mappingen ser slik ut:

InputResultReason
10.8.0.1acceptedIPv4 literal
2606:4700:4700::1111acceptedIPv6 literal
dns.example.comrejectedhostname; numeric parsing does not resolve it
10.8.0.1:53rejectedport belongs to your own config model
https://dns.example.com/dns-queryrejectedDoH URL, a different configuration path
127.0.0.1rejectedloopback is not a remote resolver
0.0.0.0 or ::accepted by the builderparses fine, but names no destination; only your own validator rejects it

Versjonen påvirker hvordan du validerer, ikke hva builderen godtar. InetAddresses er tilgjengelig fra API 29, så på Android 10 er parsingen ett kall; addDnsServer(InetAddress) er den opprinnelige formen, String den nyere tilleggelsen. Under API 29 løser InetAddress.getByName et vertsnavn med et blokkerende nettsøk.

Loopback avvises her, wildcard ikke

Desktop-VPN-klienter peker ofte sin egen stub resolver mot 127.0.0.1:53; kopieres det til en Android-profil, importeres en verdi som beskriver den lokale maskinen, og her finnes ingen lokal maskin. Builderen avviser bare dette tilfellet: en null- eller loopback-adresse kaster IllegalArgumentException.

Et wildcard er det motsatte tilfellet, og her går de fleste lesningene galt. 0.0.0.0 og :: er ikke loopback, så builderen godtar dem; intet kastes ved byggetid. Grensesnittet kommer så opp med en oppføring som ikke navngir noe mål. Å fange det er din validators jobb: behandle isAnyLocalAddress som ugyldig inndata.

Pars én gang ved konfigurasjonsgrensen

Den billige løsningen er å validere der strengen kommer inn i modellen din:

import android.net.InetAddresses
import java.net.InetAddress

private fun dnsLiteralOrNull(raw: String?): InetAddress? {
    val text = raw?.trim().orEmpty()
    if (text.isEmpty()) return null
    val address = try {
        InetAddresses.parseNumericAddress(text)
    } catch (e: IllegalArgumentException) {
        return null
    }
    return address.takeUnless { it.isAnyLocalAddress || it.isLoopbackAddress }
}

Et null-resultat blir en feltfeil med den skyldige teksten, og det er den eneste formen support kan handle på. På suksessveien går objektet rett i builder.addDnsServer(address), og fang IllegalArgumentException spesifikt, ikke Exception.

Ikke bytt ut med en offentlig resolver når den tiltenkte verdien avvises; en profil som stille setter inn en offentlig DNS kobler fortsatt til, men interne navn slutter å løses.

Bekreft rekkevidde når grensesnittet finnes

Builderens aksept er det første kontrollpunktet, ikke det siste. Når grensesnittet er oppe, viser LinkProperties.getDnsServers() hva nettverket faktisk mottok, og adb shell dumpsys connectivity skriver ut de samme egenskapene utenfra.

Private DNS er en separat kontroll og går ikke gjennom dette argumentet; vertsnavnet til en DoT-leverandør hører til systeminnstillingen, ikke et IP-felt.

Før du endrer profilparseren igjen, logg den rå strengen og kilden, bekreft at det er et literal og ikke et vertsnavn, at det verken er loopback eller wildcard, og send det parsede objektet videre.

Relaterte artikler