Android VpnService'da ajratilgan tunnel: aslida nimani marshrutlash mumkin
VpnService faqat builder o'z deskriptoriga joylashtirgan paketlarni uzatadi. Ajratilgan tunnelni ayblashdan oldin prefikslar, proksi autentifikatsiyasi, DNS va ilova ro'yxatlarini tekshiring.
VpnService ilovasidagi ajratilgan tunnel bir nechta aniq joyda buziladi va har birining tuzatilishi boshqacha. Mijoz faqat bitta muvaffaqiyatsiz manzilni ko'rsatadi, shuning uchun birinchi ish qaysi chegaraga urilayotganingizni aniqlash: builder olgan marshrutlar, autentifikatsiya qila olmaydigan proksi, faqat e'lon qilgan resolver yoki platforma har bir foydalanuvchi uchun qo'llaydigan ilovalar ro'yxati. Aynan shuning uchun to'rt bosqichli tekshiruvni saqlayman. U quyidagi tartibda boradi va birinchi xatoda to'xtaydi.
Builder platformaga nima berganini tasdiqlang
VpnService.Builder — bu deklaratsiyalar ro'yxati. establish() virtual interfeys uchun ParcelFileDescriptor qaytaradi va platforma o'sha deskriptorga faqat addAddress hamda addRoute prefikslariga mos trafikni yuboradi; addDnsServer mijozlarga qaysi resolverdan so'rashni aytadi. Qo'shgan barcha prefikslaringizdan tashqaridagi manzil interfeys nima va'da qilsa ham ilovangizga hech qachon yetib bormaydi. Aynan shu bitta fakt kod o'zgartirilishidan oldin buzilgan ajratilgan tunnel haqidagi xabarlarning ko'pini tushuntiradi.
Builder yig'gan manzil, marshrut va DNS ro'yxatlarini jurnalga yozing, so'ng ularni muvaffaqiyatsiz manzillar bilan solishtiring. Boshqaruv hosti uchun yetishmayotgan /32 buzilgan tunneldan ancha ko'p uchraydi. Ro'yxat to'g'ri bo'lsa, davom eting; noto'g'ri bo'lsa, qolgan tekshiruv ro'yxati behuda mehnat.
excludeRoute faqat API 33 dan mavjud
Manzil asosidagi istisno eng ko'p qo'llab-quvvatlash mavzusiga aylanadigan so'rovdir. builder.excludeRoute(IpPrefix) API 33 da keldi; bundan oldin qo'llab-quvvatlanadigan yagona yondashuv istisno qilingan prefikstdan tashqari hamma uchun marshrut qo'shishdir, ya'ni to'ldiruvchi prefikslarni o'zingiz hisoblashingiz kerak. Ikki chaqiruv ko'zgu tasviri emas: biri interfeys marshrutlar to'plamidan ayiradi, ikkinchisi to'plamni noldan quradi, eski qurilma esa tanimagan chaqiruvni tashlaydi yoki jimgina e'tiborsiz qoldiradi. Build.VERSION.SDK_INT bo'yicha tarmoqlaning va ikkala yo'lni haqiqiy uskunada sinab ko'ring.
To'ldiruvchilarni hisoblashda prefikslar tekisligiga e'tibor bering. /16 marshrut ichidagi /24 istisnosi qolgan qismni haqiqatan tavsiflovchi qoplovchi prefikslarni talab qiladi, bitta buzuq /8 emas. Yakuniy ro'yxatni jurnalga yozing va istisno qilingan host hali ham tunneldan tashqari yo'l bilan hal qilinishini tasdiqlang.
Proksi hisob ma'lumotlarini ifodalab bo'lmaydi
setHttpProxy(ProxyInfo) interfeysni HTTP yoki SOCKS proksiga yo'naltiradi, PAC URL esa har bir manzil uchun ular orasidan tanlashi mumkin. ProxyInfo ham, PAC formati ham foydalanuvchi nomi va parolni olib yurmaydi, shuning uchun autentifikatsiya talab qiladigan proksi platforma API sidan tashqarida qoladi. Bunga muhtoj ilovalar odatda userspace stek, tun2socks yoki shunga o'xshash dvigatelni joylashtiradi va 407 chaqirig'iga o'zlari javob beradi.
Bu tanlovning oqibatlari bor. Userspace stek faqat siz unga yo'naltirgan trafikni ko'radi, shuning uchun u o'sha deskriptor chegarasida yashashi kerak va o'zining uplink soketi uchun xuddi shu protect() talabini meros oladi. protect() ni tashlab ketsangiz, tunnel o'z transportini ushlab oladi, bu birinchi paketdan keyin tiqilib qoladigan qo'l berish sifatida ko'rinadi. Hisob ma'lumotlarini talab qiladigan proksiga qarshi sinab ko'ring, chunki ochiq proksi platforma yo'lidan o'tadi va hech narsani isbotlamaydi.
Har bir ilova ro'yxatlari va DNS ham deklaratsiya
Builder da addAllowedApplication ham, addDisallowedApplication ham bor va ular bir-birini istisno qiladi: ikkalasini chaqirish istisno tashlaydi. Qanday bo'lmasin ro'yxat interfeys sozlashda har bir foydalanuvchi uchun qo'llanadi, shuning uchun ish profili ilovasi sizning tunnelingiz emas, ish profili tunneli tomonidan boshqariladi. Hech bir API bermaydigan narsa — boshqa ilova qarori ustidan nazorat: paketni tashqaridan tunnelingizga itarib yubora olmaysiz va allaqachon faol VPN ni yopa yoki qayta sozlay olmaysiz.
DNS ham xuddi shu naqshga amal qiladi. addDnsServer resolver manzilini e'lon qiladi; u ilovangizga so'rovlarga javob berishga ruxsat bermaydi. Agar nomlarni o'zingiz hal qilmoqchi bo'lsangiz, resolver ishga tushiring va uning manzilini tunnelga yo'naltiring. Qat'iy host nomiga DoT yoki DoH ishlatadigan ilovalar siz e'lon qilgan manzilni chetlab o'tishi mumkin, shuning uchun so'rov yo'lini ham tutmasangiz, nomlarni hal qilishni eng yaxshi urinish deb biling.
Manifest, always-on va to'rt bosqichli test
Moslik manifestda e'lon qilinadi: BIND_VPN_SERVICE, android.net.VpnService intent filtri va tunnel fonda yashashi kerak bo'lsa foreground xizmati. Always-on VPN qo'shimcha ravishda toza onRevoke talab qiladi, chunki tizim uni foydalanuvchi sozlamalarni o'zgartirganda yoki boshqa ilova boshqaruvni olganda chaqiradi.
Tekshiruvlarni tartib bilan bajaring va birinchi xatoda to'xtang. Birinchi, builder ga berilgan manzil, marshrut va DNS ro'yxatlarini chiqaring. Ikkinchi, establish() deskriptor qaytarganini va transport soketi himoyalanganini tasdiqlang. Uchinchi, kiritilgan prefiks ichidagi bitta va istisno qilingan prefiks ichidagi bitta manzilni so'rang. To'rtinchi, faqat sizning resolveringiz hal qila oladigan host nomini so'rab qaysi resolver haqiqatan javob berganini tekshiring.
Bajarilgan qo'l berish keyingi bosqichlarning birortasini isbotlamaydi. Har bir tekshiruv bitta qatlamni ajratadi, shuning uchun ikkinchi bosqichdagi muvaffaqiyat to'rtinchi haqida hech narsa demaydi.
VpnService.Builder ma'lumotnomasi builder ning butun yuzasini sanab o'tadi. Bundan tashqari kerak bo'lgan hamma narsa boshqa API, boshqa ilova yoki o'zingizning userspace stekingizdir va bu ajratilgan tunnel xatosi emas, dizayn qarori.