Android VpnService: TUN oxumasının dayanması ENOBUFS yazma xətalarına qarşı
Heç qayıtmayan oxuma ilə ENOBUFS ilə uğursuz olan yazmanın səbəbləri əksdir. Düzəlişi seçmək üçün elan edilən pəncərəni və paket uzunluğunu ölçün.
Eyni VpnService dövrəsində iki simptom görünür və hər ikisi eyni şeydə günahlandırılır: heç qayıtmayan oxuyucu və ENOBUFS ilə uğursuz olan yazma. Bunlar bir xətanın variantları deyil. Dayanmış oxuma qarşı tərəflə axın nəzarəti barədə fikir ayrılığıdır; uğursuz yazma isə interfeysin qəbul etmədiyi paketdir. Onları bir problem kimi qəbul etsəniz, heç vaxt iştirak etməyən buferləri tənzimləməyə bir gün sərf edəcəksiniz. Aşağıdakı bölgü dövrənin hansı yarısını əvvəl ölçmək qərarımdır.
Bir dövrə, iki müstəqil uğursuzluq nöqtəsi
Xidmətiniz TUN fayl deskriptorundan IP paketi oxuyur, onu yoxlayır və eyni deskriptora cavab yazır. Bu yolda qırılan hər şey həmin iki çağırışdan birində üzə çıxır, buna görə də hər ikisi tunelin xarab olması kimi bildirilir. Çağırışların müqavilələri fərqlidir. Oxuma nüvənin sizə paket verməsini gözləyir, yazma isə nüvəyə rədd etməyə icazəsi olan paket verir.
Oxumalar barədə düşünmək asan yarıdır. Heç nə qaytarmayan oxuma ya heç gəlməyən trafiki gözləyir, ya da qarşı tərəf göndərməyi dayandırdığı üçün gözləyir.
Dayanmış oxuma axın nəzarəti barədə fikir ayrılığıdır
TUN cihazını oxumaq paket mövcud olana qədər bloklanır. Bu dizayn davranışıdır və buna görə read daxilində gözləyən ip boş kanalda normal görünür. Bu, sizin TCP yığınınız lokal tətbiqdən məlumat qəbul etməyə davam edib uzaq qarşı tərəfin daha çox göndərməsi üçün kifayət qədər pəncərə elan etmədikdə asılmağa çevrilir. Qarşı tərəf elan etdiyiniz pəncərəni doldurur, ACK və pəncərə yenilənməsini gözləyir və dayanır. Sonra oxuyucunuzun qaytaracağı heç nə olmur və tətbiq açıq və səssiz bir bağlantı görür.
Ümumi səbəblər elan edilən pəncərəni izləmədən soketə yazan yığın və buferini boşaltdıqdan sonra pəncərə yenilənməsi göndərməyi unudan yığındır. Xaricdən eyni görünürlər: baytlar çıxır, heç nə qayıtmır, heç bir xəta qalxmır. Oxuyucu ipi təhlil, DNS həlli və ya disk giriş-çıxışında bloklamaq əlaqəsiz səbəbdən eyni formalı simptom yaradır, ona görə axın nəzarətini günahlandırmadan əvvəl ipin həqiqətən read daxilində olduğunu təsdiqləyin.
Qarşı tərəfin göndərmə növbəsini və son gördüyü pəncərəni yoxlayın. Qarşı tərəf pəncərəniz sıfır olduğu üçün məlumat saxlayırsa, düzəliş ACK yolunuzdadır, TUN oxumasında deyil.
ENOBUFS ölçü problemidir, bufer qıtlığı deyil
TUN interfeysində ENOBUFS qaytaran yazma adətən paketin uzunluğunu rədd edir. İnterfeysin MTU-su var, ondan böyük paket növbəyə qoyula bilməz və eyni paketi təkrar cəhd etmək hər dəfə eyni şəkildə uğursuz olur. Bu determinizm əlamətdir. Həqiqi bufer qıtlığı təzyiq azaldıqca keçir, ölçü rəddi isə nə qədər gözlədiyinizə əhəmiyyət vermir.
TCP-nin məhz bunun üçün mexanizmi var və bu, insanların keçdiyi addımdır: MSS məhdudlaşdırması. İstifadəçi məkanında seqmentlər yaradarkən yük ölçüsünü siz seçirsiniz və onu tunelin MTU-su əvəzinə lokal interfeysin MTU-sundan götürmək tunelin daşıya bilmədiyi seqmentlər çıxarır. İkisinin kiçiyinə məhdudlaşdırın. Məhdudlaşdırma yalnız TCP-ni əhatə edir, ona görə həddindən böyük UDP datagramını kodunuz parçalamalı və ya atmalıdır.
Sazlama zamanı yazdığınız hər paketin uzunluğunu qeyd edin. Uğursuz olan uzunluq cavabdır və təkrar cəhdlər arasında dəyişməyəcək.
Halları ayıran üç ölçmə
Hər iki uğursuzluq üçün də sazlayıcıya ehtiyac yoxdur. Üç müşahidə özünüzü düzgün bölməyə yönəltməyə kifayətdir və onlar yenidən qurmaqdan az vaxt alır.
| What you see | Where to look |
|---|---|
| Reader parked, peer send queue empty, last advertised window zero | Window updates in your ACK path |
| Write fails on one length and succeeds on a smaller one | MSS clamp and tunnel MTU |
| Both directions look fine, app still sees no data | Protected socket and routing loop |
Üçüncü sətir uyğun gəlirsə, dövrə özü qaydasındadır və problem tunelin görə bilmədiyi yerdədir: öz VPN trafikinizi tunelə geri daşıyan qorunmamış nəqliyyat soketi, bu da adətən uğurlu olub sonra heç nə çatdırmayan bağlantı kimi görünür.
Hər iki yolun asılı olduğu boru xəttini düzəldin
İnterfeys düzgün qurulmadan heç bir simptomu qovmağa dəyməz. Vacib olan builder çağırışları ünvan, marşrut, MTU və razılıqdır, bu sıra ilə:
Builder()
.addAddress(10.8.0.2, 32)
.addRoute(0.0.0.0, 0)
.setMtu(1400)
.establish()MTU-nu nümunənin istifadə etdiyi dəyərdə saxlamaq əvəzinə tunelin real dəyərinə qoyun. Sonradan yazdığınız hər şey bu rəqəmlə məhdudlaşır və təyin etdiyiniz MTU ilə məhdudlaşdırdığınız MSS arasındakı uyğunsuzluq düzəlişdən sonra yazma xətasını qaytarmağın ən geniş yayılmış yoludur. Sonra VPN serverinə trafik daşıyan soketi qoruyun. protect olmadan bu paketlər öz tunelinizə geri yönləndirilir və bağlantı heç vaxt tamamlanmır, bu da dayanmış oxuma kimi görünür, amma əslində marşrut dövrəsidir.
Razılıqdan yan keçmək olmaz. prepare null qaytarmadan başladılan xidmət interfeys almır və establish xəta atmaq əvəzinə null qaytarır, ona görə dövrəni başlatmadan əvvəl deskriptoru yoxlayın. VpnService sənədi nümunəni kopyalamaq əvəzinə builder müqaviləsini təsdiqləmək üçün yerdir.
Bir dəfə bir istiqaməti yoxlayın
TCP-yə toxunmadan əvvəl tuneldən UDP əks-səda göndərin və paket uzunluqlarını izləyin. Sonra əl sıxışması açın və seqmentlərin hesabladığınız MSS-in altında qaldığını təsdiqləyin. Bağlantıları deyil, paketləri sayın ki, dayanma asılmış soket əvəzinə sayğacda boşluq kimi görünsün. Yazmaların partlamasından sonra oxumalar dayanırsa, şübhəli pəncərədir; yazmalar dərhal uğursuz olursa, uzunluqdur.
Sonra cihazı yenidən başladın və bir dəfə təkrarlayın, çünki yalnız ilk şəbəkə dəyişikliyinə qədər işləyən VpnService axın nəzarəti deyil, marşrut problemidir.