addDnsServer Bad Address: Android gerçekte neyi doğrular
addDnsServer kaynaklı Bad address hatası yerel bir biçim denetimidir, DNS kesintisi değildir. Literali ayrıştırın, loopback ve wildcard çıkarın, sonra erişilebilirliği test edin.
Değer VpnService.Builder.addDnsServer çağrısına dize olarak ulaştı ve builder onu hiçbir şey kurulmadan orada reddetti. Bu ret yereldir: hiçbir resolver ile iletişim kurulmadı, tünel yok ve başarısız olan şey biçim denetimi, DNS değil.
Bu önemli çünkü tipik bir VPN uygulamasının üç benzer DNS girişi vardır: profildeki değer, sunucunun gönderdiği değer ve sistem düzeyinde Private DNS. Bu çağrıya yalnızca ilk ikisi ulaşır.
Hazırlık nesnesi argümanı hemen denetler
VpnService.Builder tünel değildir. O, adresleri, rotaları ve sunucuları toplayan hazırlık nesnesidir ve yalnızca establish() bu listeleri canlı bir ParcelFileDescriptor ve arayüze dönüştürür. DNS girdisi addDnsServer çağrılırken denetlenir.
İki sonuç: yığın izi kısa ve kasıtlı olarak bilgi vermez ve dikkatsiz bir catch tüneli resolver olmadan bırakır.
Builder verilen listeyi korur; denetimi geçen bir sunucu eklemek yalnızca dizenin derleme sırasında adres literali olarak ayrıştırıldığını kanıtlar.
Argüman ne olabilir
Parametre bir adrestir, endpoint değil. Builder başvurusu IPv4 veya IPv6 literali alır ve ayrıştırma yalnızca sayısaldır: android.net.InetAddresses.parseNumericAddress API 29’dan itibaren o ayrıştırıcının kamusal yüzüdür.
Pratik eşleme şöyle görünür:
| 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 |
Sürüm nasıl doğruladığınızı etkiler, builder’ın ne kabul ettiğini değil. InetAddresses API 29’dan beri var, bu yüzden Android 10’da ayrıştırma tek çağrıdır; addDnsServer(InetAddress) özgün biçim, String daha yeni ekleme. API 29 altında InetAddress.getByName ana bilgisayar adını bloklayan bir ağ aramasıyla çözer.
Loopback burada reddedilir, wildcard reddedilmez
Masaüstü VPN istemcileri kendi stub resolver’larını sık sık 127.0.0.1:53 adresine yönlendirir; bunu Android profiline kopyalamak yerel makineyi tanımlayan bir değer getirir ve burada yerel makine yoktur. Builder yalnızca bu durumu reddeder: null veya loopback adres IllegalArgumentException fırlatır.
Wildcard bunun tersi durumdur ve hatanın çoğu okuması burada yanılır. 0.0.0.0 ve :: loopback değildir, bu yüzden builder onları kabul eder; derleme sırasında hiçbir şey fırlatılmaz. Arayüz ardından hedef belirtmeyen bir girdiyle açılır. Bunu yakalamak doğrulayıcınızın işidir: isAnyLocalAddress değerini geçersiz girdi sayın.
Yapılandırma sınırında bir kez ayrıştırın
Ucuz çözüm, dizenin modelinize girdiği yerde doğrulamaktır:
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 }
}
Null sonuç, suçlu metni taşıyan alan düzeyinde bir hata olur ve desteğin işlem yapabileceği tek biçim budur. Başarı yolunda nesne doğrudan builder.addDnsServer(address) içine girer ve IllegalArgumentException öğesini özellikle yakalayın, Exception değil.
İstenen değer reddedildiğinde genel bir resolver ile değiştirmeyin; sessizce genel DNS koyan profil bağlanır ama iç adlar çözülemez.
Arayüz oluştuktan sonra erişilebilirliği doğrulayın
Builder’ın kabulü ilk denetim noktasıdır, son değil. Arayüz açıldıktan sonra LinkProperties.getDnsServers() ağın gerçekte ne aldığını bildirir ve adb shell dumpsys connectivity aynı özellikleri dışarıdan yazdırır.
Private DNS ayrı bir denetimdir ve bu argümandan geçmez; DoT sağlayıcısının ana bilgisayar adı sistem ayarına aittir, IP alanına değil.
Profil ayrıştırıcısını yeniden değiştirmeden önce ham dizeyi ve kaynağını kaydedin, onun ana bilgisayar adı değil literal olduğunu, loopback veya wildcard olmadığını doğrulayın ve ayrıştırılmış nesneyi iletin.