addDnsServer Bad Address: kion Android efektive kontrolas
Bad address-eraro de addDnsServer estas loka formatkontrolo, ne DNS-paneo. Analizu la literalon, forigu loopback kaj wildcard, poste testu atingeblon.
La valoro alvenis al VpnService.Builder.addDnsServer kiel ĉeno, kaj la builder rifuzis ĝin tie antaŭ ol io ajn estis starigita. Tiu rifuzo estas loka: neniu resolver estis kontaktita, ne ekzistas tunelo, kaj malsukcesis formatkontrolo, ne DNS-paneo.
Tio gravas ĉar tipa VPN-aplikaĵo havas tri similajn DNS-enigojn: valoro tajpita aŭ importita en la profilon, valoro kiun la servilo sendas dum agordo, kaj Private DNS ĉe sistema nivelo. Nur la du unuaj povas atingi ĉi tiun vokon.
Prepara objekto kontrolas la argumenton tuj
VpnService.Builder ne estas la tunelo. Ĝi estas prepara objekto, kiu kolektas adresojn, vojojn kaj servilojn, kaj nur establish() transformas tiujn listojn en vivan ParcelFileDescriptor kaj interfacon. La DNS-riktaro estas kontrolata kiam vi vokas addDnsServer, ne kiam vi starigas.
Du sekvoj sekvas. La spuro estas mallonga kaj intence seninforma: la valoro alvenis kiel simpla ĉeno. Kaj senzorga catch ĉirkaŭ la tuta konstruo lasas tunelon kun adresoj kaj vojoj sed sen resolver.
La builder konservas ajnan liston, kiun vi donas. Aldoni servilon, kiu trapasas la kontrolon, pruvas nur ke la ĉeno estis analizita kiel adresa literalo ĉe konstrua tempo.
Kio rajtas esti la argumento
La parametro estas adreso, ne endpoint. La Builder-referenco akceptas literalon IPv4 aŭ IPv6, kaj la analizo estas nur numera: android.net.InetAddresses.parseNumericAddress estas la publika vizaĝo de tiu analizilo ekde API 29. Gastignomo ĉi tie ne estas malrapida adreso sed ĉeno, kiu ne analizeblas.
La praktika mapado aspektas tiel:
| 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 |
La versio influas kiel vi validigas, ne kion la builder akceptas. InetAddresses haveblas ekde API 29, do sur Android 10 kaj pli nova la analizo estas unu voko. addDnsServer(InetAddress) estas la origina formo, String la pli nova aldono. Sub API 29 InetAddress.getByName solvos gastignomon per bloka reta serĉo kaj ŝanĝos tajperaron en malrapidan starton.
Loopback estas rifuzata ĉi tie, wildcard ne
Labortablaj VPN-klientoj ofte direktas sian propran stub-resolver al 127.0.0.1:53. Kopii tion en Android-profilo importas valoron priskribantan la lokan maŝinon, kaj ĉi tie ne estas loka maŝino. La builder rifuzas nur ĉi tiun kazon: nula aŭ loopback-adreso ĵetas IllegalArgumentException.
Wildcard estas la kontraŭa kazo, kaj ĉi tie plej multaj legadoj eraras. 0.0.0.0 kaj :: ne estas loopback, do la builder akceptas ilin; nenio ĵetiĝas ĉe konstrua tempo. La interfaco leviĝas kun riktaro, kiu nomas neniun celon. Kapti tion estas la tasko de via validigilo: traktu isAnyLocalAddress kiel nevalidan enigon.
Analizu unufoje ĉe la agorda limo
La malmultekosta riparo estas validigi tie, kie la ĉeno eniras vian modelon:
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 }
}
Nula rezulto fariĝas kampnivela eraro kun la kulpa teksto, kaj tio estas la sola formo, pri kiu subteno povas agi. Sur la sukcesa vojo la objekto iras rekte en builder.addDnsServer(address). Kaptu IllegalArgumentException specife, ne Exception: larĝa kapto ankaŭ glutas nulmontrilajn erarojn.
Ne anstataŭigu per publika resolver, kiam la celata valoro estas rifuzata. Profilo, kiu silente ŝanĝas al publika DNS, ankoraŭ konektiĝas, sed internaj nomoj ĉesas solviĝi.
Konfirmu atingeblon post kiam la interfaco ekzistas
Akcepto fare de la builder estas la unua kontrolpunkto, ne la lasta. Post kiam la interfaco staras, LinkProperties.getDnsServers() montras kion la reto efektive ricevis. adb shell dumpsys connectivity presas la samajn ecojn de ekstere.
Private DNS estas aparta regilo kaj ne iras tra ĉi tiu argumento. Gastignomo de DoT-provizanto apartenas al la sistema agordo, ne al IP-kampo.
Antaŭ ol vi denove ŝanĝos la profilan analizilon, laboru laŭ ĉi tiu ordo: registru la krudan ĉenon kaj ĝian fonton, konfirmu ke ĝi estas literalo kaj ne gastignomo, ke ĝi estas nek loopback nek wildcard, kaj transdonu la analizitan objekton.