Android VPN: VpnService deskriptori va root tun qurilmasi
Android ilovalari tun0 ni o'zlari yarata olmaydi: establish() nima qaytaradi, Binder qayerda to'xtaydi va JNI qayerda boshlanadi, root yaratgan qurilma qachon g'olib bo'ladi.
Ikki yo'l Android ilovasi oldiga IP interfeysini qo'yishi mumkin va ikkisi ham egalari juda boshqacha bo'lgan bir xil turdagi fayl deskriptorida tugaydi. Biri VpnService va uning builderi orqali, ikkinchisi root shell va /dev/net/tun orqali o'tadi. Bu deskriptordagi har bir o'qish chiquvchi paket, har bir yozish kiruvchi paketdir. Yo'llarni ajratadigan narsa siyosat kimning qo'lida ekani, OS yangilanishidan kim omon qolishi va marshrutlash jadvalining qanchasiga tegish mumkinligidir.
Platforma yo'lini tanlang, agar u rad etadigan aniq narsani ayta olmasangiz. Bu rad javob odatda TAP, o'z ilovalar to'plamingizdan tashqarida ushlash yoki freymvork hech qachon oshkor qilmaydigan marshrutlash qoidasi bo'ladi.
Platforma yo'lida siz buyruqlar o'rniga niyat e'lon qilasiz. Kamida bitta manzil, kerakli marshrutlar, DNS serverlari va ixtiyoriy ilovalar ro'yxatini berasiz, so'ng Android tizim xizmati o'z identifikatori ostida imtiyozli sozlashni bajaradi. Interfeys nomini oldindan hech qachon bilmaysiz va uni yaratadigan ioctl ni hech qachon chiqarmaysiz, va gap shunda.
IP interfeys olishning ikki yo'li
root yo'li eski retsept. Siz /dev/net/tun ni ochasiz, IFF_TUN bilan TUNSETIFF ni chaqirasiz, interfeysni ip link bilan ko'tarasiz va manzillar hamda marshrutlarni qo'lda qo'shasiz. Har bir qadamni o'zingiz to'g'ri bajarishingiz kerak, freymvork jimgina hal qilganlarini ham. Bitta marshrut yetishmasa, foydalanuvchiga o'lik serverdagidek hisobot boradi.
Nosozliklarni tuzatish sozlash qanchalik boshqacha bo'lsa, shunchalik boshqacha. root yo'lida interfeys yo bor, yo ioctl to'g'ridan-to'g'ri o'qiy oladigan xato qaytardi. Platforma yo'lida interfeys establish() muvaffaqiyatli bo'lgandan keyingina bor, shuning uchun muvaffaqiyatsizlik qurilma tuguni o'rniga istisno yoki null deskriptor sifatida keladi, uni siz titkilashingiz mumkin.
establish() aslida nima qaytaradi
Builder.establish() uchta natijaga ega va ular uchta boshqacha javobni talab qiladi. Deskriptor interfeys sozlanganini va foydalanish uchun sizniki ekanini bildiradi, null so'rov o'tmaganini, tashlangan istisno esa tizim xizmati uni rad etganini bildiradi. null va muvaffaqiyatni bitta boolean ga birlashtirish paketni hech qachon tashimaydigan ishlayotgan tunnel haqida ilova xabar berishining eng keng tarqalgan usuli. Builder ma'lumotnomasi manzil talabini ko'rsatadi, va serverni ayblashdan oldin uni o'qishga arziydi.
Yo'nalishlarni deskriptor belgilaydi, sizning protokolingiz emas. O'qishlar sizga VPN uchun allaqachon tanlangan chiquvchi paketlarni beradi, yozishlar esa kiruvchi paketlarni interfeysga qayta quyadi. O'sha paketlarni shifrlash, autentifikatsiya qilish va freymlash sizning transportingiz ishi, chunki platforma paket chegarasida to'xtaydi.
Binder bir qadam, JNI boshqa o'q
builder so'rovi Binder orqali tizimga kiradi va uning ostida bir joyda platforma qurilmani sozlash uchun native kod chaqiradi. Bu bitta chaqiruv ichida qatlamlangan ikki xil mexanizm. Binder ilovangiz va tizim xizmati o'rtasidagi jarayonlararo aloqa, JNI esa jarayon ichida Java dan native kodga ko'prik. Android 9 AOSP daraxtini o'qish stekni tom ma'noda ko'rinadigan qiladi va ichki sinf nomlari hamda fayl yo'llari nashrlar orasida o'zgarishini yodda tutish kerak.
O'zgarmaydigan narsa siz tayanishingiz mumkin bo'lgan shartnoma: builder, u qaytaradigan deskriptor va uning atrofidagi xizmat hayot tsikli. Hech qaysi ilova interfeys olish uchun ichki xizmat tranzaksiyasini chaqirmasligi yoki qurilma tugunini qayta yaratmasligi kerak. Agar kodingiz AOSP sinf nomiga bog'liq bo'lsa, u siz sinamagan nashrda buziladi.
TUN IP tashiydi, TAP Ethernet
TUN IP interfeys. TAP Ethernet interfeys, va bu farq ko'prik qurish umuman mumkinmi-yo'qmi ekanini hal qiladi. TUN qurilmasida MAC manzili ham, uzatish uchun Ethernet sarlavhasi ham yo'q, shuning uchun TUN mijozi marshrutlar qanday yozilganidan qat'i nazar layer-2 ko'prigiga qo'shila olmaydi.
VpnService sizga IP variantini beradi, ilova darajasidagi VPN ga kerak bo'ladigan va xom Ethernet stekisiz qo'llab-quvvatlay oladigan narsa shu. Agar dizayningiz ko'prik talab qilsa, platforma yo'li sizni u yerga olib bormaydi, root yo'li esa faqat yadro va qurilma ruxsatlari hamkorlik qilsa olib boradi.
root yo'li hali ham qayerda g'olib
Uch ish odamlarni platforma yo'lidan uzoqlashtiradi. layer-2 ko'prigi uchun TAP kerak. O'z VPN doirangizdan tashqaridagi ilovalar trafigini ushlash uchun freymvork bermaydigan ko'rinuvchanlik kerak. builder hech qachon oshkor qilmaydigan siyosat marshrutlash, masalan bitta manzil uchun alohida jadval, o'zingiz o'rnatadigan qoidalarni talab qiladi.
Xarajatlar keyin keladi: ochilgan bootloader yoki root qilingan obraz, oyog'ingiz ostida siljiydigan SELinux siyosati va OTA dan keyin to'g'ri xatti-harakatni to'xtatadigan qurilma. root qilingan retseptni oddiy ilova tarqatish orqali ham chiqarib bo'lmaydi, shuning uchun ko'p jamoalar uni mahsulot emas, ichki diagnostika yo'li sifatida saqlaydi.
Ikkisi orasida tanlov
Qo'lingizdagi koddan emas, sizga kerakli interfeysdan boshlang. Javob ilova bilan cheklangan marshrutlarga ega TUN qurilmasi bo'lsa, platforma yo'li qisqaroq va yangilanishlardan omon qoladi. Javob Ethernet freymlar, boshqa ilovalarni ushlash yoki builder rad etadigan marshrutlash qoidalarini o'z ichiga olsa, siz root hududidasiz va uni operatsion xarajat sifatida byudjetga kiritishingiz kerak.
Ko'p bahslarni hal qiladigan tekshiruv: avval platforma yo'lini quring, establish() natijasini uzoq sessiya holatidan alohida qayd eting va har bir yo'nalishda bitta paketni tasdiqlang. Shundan keyingina yetishmayotgan imkoniyat qo'llab-quvvatlanadigan yo'ldan chiqishni oqlaydimi-yo'qmi hal qiling.