addDnsServer Bad Address: kva Android eigentleg validerer
Bad address-feilen frå addDnsServer er ein lokal formatkontroll, ikkje eit DNS-avbrot. Pars literalen, fjern loopback og wildcard, og test deretter rekkevidda.
Verdien nådde VpnService.Builder.addDnsServer som ein streng, og builderen avviste han der før noko var etablert. Avvisinga er lokal: ingen resolver er kontakta, det finst ingen tunnel, og det som svikta er ein formatkontroll, ikkje DNS.
Dette spelar ei rolle fordi ein vanleg VPN-app har tre like DNS-inngangar: ein verdi i profilen, ein verdi serveren sender under konfigurasjon, og Private DNS på systemnivå. Berre dei to første når dette kallet.
Eit førebuingsopjekt sjekkar argumentet med ein gong
VpnService.Builder er ikkje tunnelen. Det er eit førebuingsopjekt som samlar adresser, ruter og serverar, og berre establish() gjer listene om til eit levande ParcelFileDescriptor og eit grensesnitt. DNS-oppføringa blir sjekka når du kallar addDnsServer.
To følgjer: sporet er kort og med vilje lite informativt, og ein slurvete catch rundt heile bygget lèt etter seg ein tunnel utan resolver.
Builderen held på kva liste du enn gjev han; å leggje til ein server som passerer kontrollen beviser berre at strengen vart parsa som adresseliteral ved byggetid.
Kva argumentet kan vere
Parameteren er ei adresse, ikkje eit endpoint. Builder-referansen tek ein IPv4- eller IPv6-literal, og parseringa er berre numerisk: android.net.InetAddresses.parseNumericAddress er det offentlege andletet til den parsaren frå API 29.
Den praktiske koplinga ser slik ut:
| Input | Result | Reason |
|---|---|---|
10.8.0.1 | accepted | IPv4 literal |
2606:4700:4700::1111 | accepted | IPv6 literal |
dns.example.com | rejected | hostname; numeric parsing does not resolve it |
10.8.0.1:53 | rejected | port belongs to your own config model |
https://dns.example.com/dns-query | rejected | DoH URL, a different configuration path |
127.0.0.1 | rejected | loopback is not a remote resolver |
0.0.0.0 or :: | accepted by the builder | parses fine, but names no destination; only your own validator rejects it |
Versjonen påverkar korleis du validerer, ikkje kva builderen godtek. InetAddresses er tilgjengeleg frå API 29, så på Android 10 er parseringa eitt kall; addDnsServer(InetAddress) er den opphavlege forma, String den nyare tilføyinga. Under API 29 løyser InetAddress.getByName eit vertsnamn med eit blokkerande nettsøk.
Loopback blir avvist her, wildcard ikkje
Desktop-VPN-klientar peikar ofte stub resolveren sin mot 127.0.0.1:53; blir det kopiert inn i ein Android-profil, blir ein verdi importert som skildrar den lokale maskinen, og her finst ingen lokal maskin. Builderen avviser berre dette tilfellet: ei null- eller loopback-adresse kastar IllegalArgumentException.
Eit wildcard er det motsette tilfellet, og her tek dei fleste tolkingane av denne feilen feil. 0.0.0.0 og :: er ikkje loopback, så builderen godtek dei; ingenting blir kasta ved byggetid. Grensesnittet kjem så opp med ei oppføring som ikkje namngjev noko mål. Å fange det er jobben til validatoren: handsam isAnyLocalAddress som ugyldig inndata.
Pars ein gong ved konfigurasjonsgrensa
Den billege løysinga er å validere der strengen kjem 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 }
}
Eit null-resultat blir ein feltfeil med den skuldige teksten, og det er den einaste forma støtta kan handle på. På suksessvegen går objektet rett inn i builder.addDnsServer(address), og fang IllegalArgumentException spesifikt, ikkje Exception.
Ikkje byt til ein offentleg resolver når den tiltenkte verdien blir avvist; ein profil som stille set inn ein offentleg DNS koplar framleis til, men interne namn sluttar å bli løyste.
Stadfest rekkevidde når grensesnittet finst
Aksepten frå builderen er det første kontrollpunktet, ikkje det siste. Når grensesnittet er oppe, viser LinkProperties.getDnsServers() kva nettverket faktisk tok imot, og adb shell dumpsys connectivity skriv ut dei same eigenskapane utanfrå.
Private DNS er ein eigen kontroll og går ikkje gjennom dette argumentet; vertsnamnet til ein DoT-leverandør høyrer til systeminnstillinga, ikkje eit IP-felt.
Før du endrar profilparsaren igjen, logg den rå strengen og kjelda, stadfest at det er ein literal og ikkje eit vertsnamn, at det korkje er loopback eller wildcard, og send det parsa objektet vidare.