Android VPN tunnelidan quyi tarmoqni qanday chiqarib tashlash mumkin
VpnService marshrutni chiqarib tashlay olmaydi, shuning uchun to'ldiruvchini qo'shasiz: /8 uchun yaratilgan sakkizta prefiks, qolganini ushlaydigan IPv6, DNS va qidiruv tekshiruvlari bilan.
Android'ning VpnService xizmatida chiqarib tashlash marshruti yo'q va API o'qishning hech qanday miqdori uni yaratmaydi. Builder.addRoute() tunnelga faqat manzillar qo'shadi, shuning uchun LAN segmentini mahalliy saqlash bu segment marshrutlar ro'yxatiga umuman kirmasligini bildiradi. Buning o'rniga siz segmentning to'ldiruvchisini qo'shasiz, u oddiy prefikslar bilan ifodalanadi. Ish arifmetika, va u bir nechta oldindan aytish mumkin bo'lgan joylarda barbod bo'ladi.
Quyidagi tekshiruvlarni tartib bilan o'tkazing. Har biri oldingisi turgan deb hisoblaydi, shuning uchun quyidagi belgilarni yamab qo'yish o'rniga birinchi muvaffaqiyatsizlikda to'xtang.
Tunnel da'vo qilgan narsadan boshlang
0.0.0.0/0 ni addRoute() ga berish Android'ga har bir IPv4 manzil tunnelga tegishli ekanini aytadi. Shuning uchun ko'p mijozlar bo'lingan tunnellashga qodir emasdek ko'rinadi: ular butun manzil maydonini da'vo qiladi va keyin undan ayirishga urinadi. Quruvchida hech narsa ayirmaydi. Mahalliy saqlamoqchi bo'lgan tarmoq uchun aniqroq marshrut odamlar kutganning aksini qiladi, chunki eng uzun mos prefiks yutadi va o'sha tarmoq tunnel ichida qoladi.
Marshrutlar ro'yxati butun siyosatdir. Uning orqasida har bir manzil uchun veto yo'q va Builder ma'lumotnomasi shunday narsani beradigan metodni sanab o'tmaydi.
To'ldiruvchini prefiks arifmetikasidan yarating
Chiqarib tashlangan prefiksning to'ldiruvchisi manzillar daraxtining ildiziga boradigan yo'lda uning aka-ukalarining to'plamidir. 1 dan chiqarib tashlangan uzunlikkacha har bir uzunlik uchun prefiksingizni o'z ichiga olgan o'sha uzunlikdagi blokni oling, prefiks ostidagi bitni aylantiring va natijani chiqaring. Ishga tushirmaguningizcha bu mavhum tuyuladi.
10.0.0.0/8 ni chiqarib tashlash sakkizta marshrut beradi: 128.0.0.0/1, 64.0.0.0/2, 32.0.0.0/3, 16.0.0.0/4, 0.0.0.0/5, 12.0.0.0/6, 8.0.0.0/7, 11.0.0.0/8. Ulardan hech biri 10.0.0.0/8 ni o'z ichiga olmaydi va birgalikda qolgan hammasini qoplaydi.
Sakkiz qator har qanday prefiks uchun o'sha ro'yxatni yaratadi:
import ipaddress
def complement(addr, length):
base = int(ipaddress.IPv4Address(addr))
out = []
for k in range(1, length + 1):
block = base & (0xFFFFFFFF << (32 - k))
sibling = block ^ (1 << (32 - k))
out.append(f"{ipaddress.IPv4Address(sibling)}/{k}")
return out
print(complement("10.0.0.0", 8))
Marshrutlar soni prefiks uzunligiga teng va bu kuzatilishi kerak bo'lgan raqam. Bitta /21 chiqarib tashlash 21 marshrutga tushadi va o'qiladigan bo'lib qoladi. O'nta chiqarib tashlash bir necha yuzga tushishi mumkin, bu odatda generatorni emas, tarmoq dizaynini o'zgartirish kerakligini bildiradi.
Manzillar oilasi va tunnel qamrovini tekshiring
IPv4 marshrutlari IPv6 uchun hech narsa qilmaydi. Agar tunnel IPv6 manzilini da'vo qilsa, IPv6 LAN prefiksiga o'z to'ldiruvchisi kerak, u 128 bit ustida o'sha arifmetika bilan yaratiladi. Chiqarib tashlash qog'ozda ishlab, mahalliy qurilma yetib bo'lmaydigan bo'lib qolishining keng tarqalgan sababi shu: xostga IPv6 orqali yetib borilgan va faqat IPv4 kesib tashlangan edi. Arifmetika noto'g'ri degan xulosaga kelishdan oldin ikkala oilani tekshiring.
Qamrov tekshiruvning ikkinchi yarmi. Android marshrutlashni tarmoq va ilova bo'yicha kuzatadi, shuning uchun bir xil prefiks bitta ilova uchun tunneldan, boshqasi uchun to'g'ridan-to'g'ri o'tishi mumkin, bu VPN qanday e'lon qilinganiga bog'liq.
DNS va har bir ilova qoidalarini o'z joyiga qo'ying
Marshrutlarni chiqarib tashlash resolverni o'zgartirmaydi. Mahalliy xost nomiga hali ham tunnelning DNS serveri javob berishi mumkin, uning manzili mahalliy marshrutlanayotganda, va nomuvofiqlik LAN yeta olmaydigan narsaga hal bo'ladigan nom sifatida ko'rinadi. Resolver siyosatini ataylab belgilang, qidiruv domeni yoki bo'lingan DNS qoidasi bilan. Marshrutlar buni siz uchun hal qilgan deb o'ylamang.
addDisallowedApplication() bitta ilovani tunneldan tashqarida ushlab turadi; ichkarida qoladigan ilovalar uchun manzilni tashqarida ushlab turmaydi. protect() siz ochgan soketga tunnelni chetlab o'tishga imkon beradi va shu bilan tunnel o'z transportini ushlashdan qochadi. Ikkalasi ham to'ldiruvchini almashtirmaydi.
O'z ro'yxatingiz bilan emas, qidiruv bilan tekshiring
Tunnel ko'tarilgach, o'zingiz qurgan ro'yxatni qayta o'qish o'rniga qurilmadan manzil aslida qayerga ketishini so'rang. iproute2 bilan keladigan buildda adb shell ip route get 10.1.2.3 yadro tanlagan interfeysni nomlaydi. Xuddi shu buyruqni ommaviy manzil uchun bajaring va u tunnelni nomlashini tasdiqlang.
Yana ikkita tekshiruv aylanani yopadi. Avval mahalliy nomni hal qiling, keyin hal qilingan manzilda adb shell ip route get ni ishga tushiring va tunnel bo'lmagan interfeysni talab qiling, chunki muvaffaqiyatli adb shell ping -c 1 host.lan yetib borishni isbotlaydi, yo'lni emas. Tunnel bittasini da'vo qilsa, manzillar oilasi testini IPv6 ustida takrorlang. O'zingiz yuboradigan API darajasida sinang, chunki VPN tarmoqlarining marshrutlash jadvaliga qanday taqdim etilishi versiyalar orasida o'zgargan. Qog'ozda to'g'ri ko'rinadigan marshrutlar ro'yxati va noto'g'ri interfeysni tanlaydigan qidiruv turli xatolar, va foydalanuvchilarga faqat ikkinchisi yetib boradi.
Agar chiqarib tashlash ro'yxati o'sishda davom etsa, marshrut yaratishni to'xtating va uzoq tarmoqni qayta raqamlang yoki buning o'rniga tunnelni toraytiring. Generator mavjud bo'lmagan API uchun aylanma yo'l, dizayn asbobi emas.