Мән VpnService.Builder.addDnsServer ішіне жол ретінде жетті және builder оны сол жерде қабылдамады, ештеңе орнатылмай тұрып. Бұл бас тарту жергілікті: ешбір resolver-ге хабарласу болған жоқ, туннель жоқ, сәтсіз болғаны формат тексерісі, DNS емес.

Бұл маңызды, өйткені әдеттегі VPN қолданбасында үш ұқсас DNS кірісі бар: профильдегі мән, сервер жіберетін мән және жүйе деңгейіндегі Private DNS. Тек алғашқы екеуі осы шақыруға жетеді.

Дайындық нысаны аргументті бірден тексереді

VpnService.Builder туннель емес. Ол мекенжайларды, маршруттарды және серверлерді жинайтын дайындық нысаны, және тек establish() сол тізімдерді тірі ParcelFileDescriptor мен интерфейске айналдырады. DNS жазбасы addDnsServer шақырғанда тексеріледі.

Екі салдар: стек ізі қысқа және әдейі ақпаратсыз, ал немқұрайлы catch resolver-сіз туннель қалдырады.

Builder кез келген тізімді сақтайды; тексеруден өткен сервер қосу жолдың құрылыс кезінде мекенжай литералы ретінде талданғанын ғана дәлелдейді.

Аргумент қандай бола алады

Параметр — мекенжай, endpoint емес. Builder анықтамасы IPv4 немесе IPv6 литералын қабылдайды, ал талдау тек сандық: android.net.InetAddresses.parseNumericAddress API 29-дан бастап сол парсердің ашық беті.

Практикалық сәйкестік былай көрінеді:

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

Нұсқа қалай тексеретініңізге әсер етеді, builder не қабылдайтынына емес. InetAddresses API 29-дан қолжетімді, сондықтан Android 10-да талдау бір шақыру; addDnsServer(InetAddress) бастапқы нысан, String жаңа қосымша. API 29-дан төмен InetAddress.getByName хост атын блоктайтын желілік іздеумен шешеді.

Loopback мұнда қабылданбайды, wildcard емес

Десктоп VPN клиенттері өз stub resolver-ін 127.0.0.1:53-ке жібереді; оны Android профиліне көшіру жергілікті машинаны сипаттайтын мәнді енгізеді, ал мұнда жергілікті машина жоқ. Builder тек осы жағдайды қабылдамайды: null немесе loopback мекенжайы IllegalArgumentException лақтырады.

Wildcard — керісінше жағдай, осында көп оқылым қателеседі. 0.0.0.0 және :: loopback емес, сондықтан builder оларды қабылдайды; құрылыста ештеңе лақтырылмайды. Интерфейс ешбір мақсатты атамайтын жазбамен көтеріледі. Мұны ұстау валидаторыңыздың жұмысы: isAnyLocalAddress жарамсыз кіріс деп қараңыз.

Конфигурация шегінде бір рет талдаңыз

Арзан шешім — жол моделіңізге кіретін жерде тексеру:

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 нәтиже кінәлі мәтінді алып жүретін өріс деңгейіндегі қатеге айналады және қолдау тек осы түрмен жұмыс істей алады. Сәтті жолда нысан тікелей builder.addDnsServer(address) ішіне кіреді, ал IllegalArgumentException дәл ұстаңыз, Exception емес.

Мақсатты мән қабылданбағанда оны ашық resolver-мен алмастырмаңыз; үнсіз ашық DNS қоятын профиль қосылады, бірақ ішкі атаулар шешілмейді.

Интерфейс пайда болған соң қолжетімділікті растаңыз

Builder-дің қабылдауы бірінші бақылау нүктесі, соңғысы емес. Интерфейс көтерілген соң LinkProperties.getDnsServers() желінің нақты не алғанын көрсетеді, adb shell dumpsys connectivity сол қасиеттерді сырттан басып шығарады.

Private DNS бөлек басқару және бұл аргументтен өтпейді; DoT провайдерінің хост аты жүйелік параметрге жатады, IP өрісіне емес.

Профиль парсерін қайта өзгертуден бұрын шикі жолды және оның көзін жазып алыңыз, оның хост аты емес литерал екенін, loopback немесе wildcard еместігін растап, талданған нысанды өткізіңіз.

Қатысты мақалалар