ارزښت VpnService.Builder.addDnsServer ته د تار په توګه ورسېد او builder هغه هلته رد کړ، مخکې له دې چې څه جوړ شي. دا رد سیمه‌ایز دی: له هیچا resolver سره اړیکه نه ده شوې، tunnel نشته، او هغه څه چې ناکام شو د بڼې څیړنه ده، نه DNS.

دا مهم دی ځکه چې یو عادي VPN اپلیکیشن درې ورته DNS ننوتې لري: ارزښت په پروفایل کې، ارزښت چې سرور یې لیږي، او Private DNS په سیسټم کچه. یوازې لومړنۍ دوه دې غږ ته رسېږي.

د چمتووالي شی په سملاسي توګه دلیل څیړي

VpnService.Builder tunnel نه دی. دا د چمتووالي شی دی چې پتې، لارې او سرورونه راټولوي، او یوازې establish() هغه لیستونه ژوندي ParcelFileDescriptor او انټرفیس ته اړوي. د DNS ننوت د addDnsServer په غوښتنې کې څیړل کیږي.

دوه پایلې: سټک ټریس لنډ او په قصد ناڅرګند دی، او بې‌احتیاطه catch پرته له resolver tunnel پرېږدي.

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 نه دی، او څیړل شوی شی ولېږئ.

اړوندې مقالې