Tunnel ko‘tariladi, kalit belgisi paydo bo‘ladi, ammo brauzerdagi har bir so‘rov hali ham vaqt tugab muvaffaqiyatsiz bo‘ladi. VpnService ilovasida bu birikma odatda o‘qish sikli tirik, chiqish yarmi buzilganligini bildiradi, server qo‘l berishni rad etganini emas. Android interfeysni allaqachon yaratgan, ilova trafigini unga ko‘chirgan va jarayoningizga fayl deskriptorini bergan. Shu deskriptordan keyingi hamma narsa sizning kodingiz, bitta etishmayotgan chaqiruv butun oqimni yutish uchun yetarli.

Tizim nima beradi va nima bermaydi

establish() tun interfeysi uchun ParcelFileDescriptor qaytaradi. Tizim chiquvchi IP paketlarni unga yozadi va jarayoningiz ularni o‘qib, qayerga ketishini hal qilib, oddiy socket orqali yuborishini kutadi. Ostida yadroda uzatish yo‘q, shuning uchun hech kim o‘qimasa, paketlar tashlab yuboriladi va interfeys hisoblagichlari hech qachon qimirlamaydi.

Taxmin qilish o‘rniga sanashdan boshlang. Har bir muvaffaqiyatli o‘qishda hisoblagichni oshiring va birinchi paketlarning manzili hamda protokolini yozib oling. Trafik yaratilayotganda hisoblagich nolda qolsa, xato sizning uzatish kodingizdan yuqorida, bu qidiruvni builder sozlamalari va o‘qish rejimiga toraytiradi. Hisoblagich qimirlab, brauzer baribir ishlamasa, xato yuborish yoki qaytish yo‘lida.

Bloklovchi o‘qish sikl qimirlaydimi-yo‘qmi hal qiladi

setBlocking(true) deskriptorni bloklovchi rejimga o‘tkazadi va API 21 dan beri mavjud. Eski nashrlarda yechim xom deskriptorda fcntl bilan O_NONBLOCK ni tozalaydigan kichik JNI yordamchisi. Rejim muhim, chunki kutayotgan paketsiz o‘qish nima qilishi mumkinligini aynan shu belgilaydi.

Bloklamaydigan rejimda o‘sha o‘qish darhol manfiy qiymat bilan qaytadi, natijani e’tiborsiz qoldiradigan sikl esa hech qanday trafikni siljitmasdan yadroni aylantiradi. Bloklovchi rejimda o‘qish kutadi, bu uzatish oqimiga kerak, lekin keyin oqimni to‘xtatib bo‘lmaydi. O‘qishni muvaffaqiyatsiz qilishning qo‘llab-quvvatlanadigan yo‘li deskriptorni yopishdir, shunda sikl chiqa oladi. Jarayonni o‘ldirish yoki oqimni to‘xtatish keyingi ishga tushishni interfeysga endi mos kelmaydigan deskriptor bilan qoldirishi mumkin.

Har bir chaqiruvda interfeys MTU o‘lchamidagi buferga bitta paket o‘qing va nol yoki manfiy qaytishni bo‘sh paket emas, xato deb biling.

protect() birinchi yuborishdan oldin, keyin emas

Inkapsulyatsiyalangan paket tashuvchi har bir socket avval himoyalanishi kerak. Himoyalanmagan socket siz hozir o‘rnatgan marshrutlash qoidalariga bo‘ysunadi, shuning uchun paketlari tunnelga qaytadi va o‘zingizning o‘qish siklingiz ularni yana oladi. Keyin tunnel o‘z chiqishini cheksiz uzatadi va tashqaridan bu ochilib, hech qachon javob bermaydigan ulanishga o‘xshaydi.

Tartib: protect, keyin connect yoki bind, keyin send. connect dan keyin protect chaqirish oldingi marshrut qarorini qoldirishi mumkin, shuning uchun chaqiruv true qaytargan bo‘lsa ham socket noto‘g‘ri yo‘lni ishlatishda davom etadi. Qaytarilgan boolean ni tekshiring va false bo‘lganda baland ovozda muvaffaqiyatsiz bo‘ling, ishlay olmaydigan send ga kirish o‘rniga.

protect() ga hech qachon tegilmagan socketda sendto dan kelgan ruxsat xatosi bu xatoning odatiy belgisidir.

UDP namunasi HTTPS tashimaydi

Ko‘pchilik qo‘llanmalar ko‘chiradigan uzatish namunasi faqat UDP bilan ishlaydi. TCP qo‘l berish, tartib raqamlar, tasdiqlar va qayta yuborishni talab qiladi, tun deskriptori bilan socket orasida yukni ko‘chiradigan sikl esa bularning hech birini bermaydi. Shuning uchun UDP DNS so‘rovi o‘tishi mumkin, har bir HTTPS so‘rov esa tiqilib qoladi. Yoki foydalanuvchi maydonida TCP stekini ishga tushiring yoki ulanishlarni qurilmada TCP ni tugatib oqimni uzatadigan mahalliy proksiga bering.

Biror narsani qayta yozishdan oldin bo‘linishni sinab ko‘ring: bitta UDP so‘rov yuboring va o‘sha xostga bitta TCP ulanish oching. UDP yo‘li ishlab, TCP yo‘li birinchi SYN da to‘xtasa, muammo uzatish kodida, serverda emas. O‘sha bitta taqqoslash foydali hech narsasi yo‘q server jurnallarini o‘qishga ketadigan ko‘p vaqtni tejaydi.

Marshrutlar ro‘yxati va ilova bo‘yicha filtrlar ko‘rganingizni cheklaydi

addAddress, addRoute va addDns tizim tunnelga nima yuborishini belgilaydi. Marshrutlar ro‘yxatidan tashqaridagi manzil hech qachon deskriptoringizga yetib bormaydi, shuning uchun qancha uzatish mantiqi bo‘lsa ham buni tuzatmaydi. Qilgan builder chaqiruvlaringizni yozib oling va ilova haqiqatan yetib bormoqchi bo‘lgan manzillar bilan taqqoslang.

Ilova bo‘yicha tanlovning o‘z chegarasi bor: addAllowedApplication va addDisallowedApplication API 21 talab qiladi, eski nashrlarda bu metodlar umuman yo‘q. Paket bo‘yicha filtrlaydigan dizayn u yerda ishlay olmaydi.

Qayta o‘rnatish eskirgan deskriptorlarni qoldiradi

establish() ni qayta chaqirish yangi deskriptor qaytaradi va oldingi interfeysni yopadi. Eski deskriptor endi yaroqsiz, shuning uchun unda hali bloklangan oqim xato oladi, eski yo‘l uchun yaratilgan socketlarni almashtirish kerak bo‘lishi mumkin. onRevoke foydalanuvchi yoki tizim olib qo‘ygan tunnel uchun qayta chaqiruv. Hayot siklini qayta o‘rnatishdan oldin o‘quvchini to‘xtatadigan bitta egada saqlash ulangan-lekin-o‘lik holatlarning ko‘pini oldini oladi.

Har bir xatoni tegishli bosqich bo‘yicha o‘qing. recvfrom dan ulanishning qayta tiklanishi kod hali o‘qiyotganda uzoq tomon yopilganini bildiradi. Noto‘g‘ri manzil xatosi sarlavha tahlili yoki offset xatosiga ishora qiladi, tarmoqqa emas.

Ish tartibi: bloklovchi rejim yoniq, har o‘qishga bitta paket, sarlavha tahlil qilingan, socket himoyalangan, yuk yuborilgan, topshirishda toza yopilish va manzilni qamrab oluvchi marshrutlar ro‘yxati.

O'xshash maqolalar