Android VpnService niyə bəzi trafiki tutur, hamısını deyil
Marşrutlar, DNS qeydləri və tətbiq üzrə əhatə hansı paketlərin tun cihazına çatdığını, yerli cihazların niyə yox olduğunu və qurucunun nədən imtina etdiyini həll edir.
VpnService özü heç bir trafiki tutmur. O, sistemdən tun interfeysi istəyir, həmin interfeysə bir sıra ünvan və marşrut verir və o andan kernel həmin marşrutlara uyğun gələn hər paketi tətbiqin oxuya bildiyi fayl deskriptoruna köçürür. Tətbiqin kodu marşrutların seçmədiyi paketləri heç vaxt görmür, yəni tunelin əhatəsi proqramlaşdırma sualından əvvəl marşrut cədvəli sualıdır. Buna görə eyni xidmət tətbiqi bir telefonda bütün axını udə bildiyi halda digərində yalnız bir dilimini udur və buna görə marşrut əlavə etmək bəzən sınıq görünən tuneli düzəldir. Nə aldığınız, bəyan etdiyinizdir, qurucunun səssizcə imtina etdiyi hər şey çıxılmaqla.
Marşrutlar hansı paketlərin gəldiyini müəyyən edir
Builder.addRoute(prefix, prefixLength) VPN şəbəkəsinin marşrut cədvəlinə prefiks quraşdırır. Sistem həmin şəbəkəni əhatədəki tətbiqlər üçün ilkin hesab edir, ona görə onun qeydlərinə fiziki şəbəkənin ilkin marşrutundan əvvəl baxılır və uyğun prefiks axını yönləndirmək üçün kifayətdir. Buna görə 0.0.0.0/0 üçün marşrut IPv4-ü tamamilə götürür, çap cihazı, cast hədəfi və marşrutlaşdırıcının admin səhifəsi daxil olmaqla.
Bu əhatəni fiziki ilkin qeydi silmədən istəyən müştərilər bunun əvəzinə 0.0.0.0/1 və 128.0.0.0/1 cütündən istifadə edir. İki daha dəqiq marşrut ilkin marşrutu üstələyir, birlikdə bütün ünvan məkanını əhatə edir və telefonun öz ilkin qeydi fiziki şəbəkəyə bağlı qalan soketlər üçün cədvəldə qalır.
Ünvanlar və DNS qeydləri eyni qurucudan gəlir və başqa suala cavab verir. addAddress interfeysə prefiks uzunluğu ilə ünvan verir, addDnsServer isə əhatədəki tətbiqlərin interfeys vasitəsilə sorğulayacağı həlledici quraşdırır. Hər iki ailə bir interfeysdə ola bilər, ona görə yalnız IPv4 marşrut dəsti IPv6 ünvanının yanında düzgün oxunan və yenə də sızdıran konfiqurasiyadır. İnterfeysin ünvanı olmayan ailəni marşrutlaşdırsanız, kernelin həmin paketlər üçün mənbə ünvanı olmur və onlar heç vaxt deskriptorda görünmür.
establish() nə qaytarır
establish() ParcelFileDescriptor qaytarır, tətbiq icazəli deyilsə null. Null şəbəkə xətası deyil, razılıq vəziyyətidir: ya VpnService.prepare() artıq null qaytarmalı idi, ya da istifadəçi çağırışdan əvvəl sistem dialoqunu təsdiqləməli idi. Razılıq xidmət işləyərkən geri alına bilər və interfeys oxuma dövrünüzə heç bir geri çağırış olmadan altınızdan bağlanır.
Deskriptor siz əksini deməsəniz bloklamır, yəni oxuma ipi gözləməyə qoymadan boş data ilə dərhal qayıdır. Bloklayan soket üçün yazılmış dövr bir nüvəni yandırır, boş oxumanı ölümcül sayan dövr isə boş bir saniyədə tuneli dağıdır. Builder.setBlocking(true) bu davranışı dəyişir və qiyməti oxuma içində gözləyən ipdir.
Marşrut və ünvan arqumentləri LinkAddress dəyərləri kimi yoxlanılır və 224.0.0.0/4 kimi multicast təyinatları qəti şəkildə rədd edilir. Nöqtədən nöqtəyə tun interfeysinin də yayım domeni yoxdur, ona görə onun üzərində multicast kəşfi bir marşrut daha deyil, başqa dizayn tələb edir. Burada VpnService.Builder sənədi çağırışın diqqətdən qaçdığı qənaətinə gəlməzdən əvvəl baxmalı olduğunuz siyahıdır.
Tətbiq üzrə əhatə dəsti daraldır, tuneli yox
API 21-dən qurucu addAllowedApplication və addDisallowedApplication qəbul edir və iki siyahı bir qurucu daxilində qarşılıqlı istisnadır. İcazə siyahısı tunelin həmin paketlər üçün mövcud olmasına səbəb olur, qalan hər şey fiziki şəbəkəni saxlayır; qadağa siyahısı adlanan paketlərdən başqa hər şeyi tutur, müştərinin bölünmüş tunelleşdirmə kimi təqdim etdiyi şey budur. API 21-dən əvvəl platforma mexanizmi ümumiyyətlə yoxdur və tətbiq üzrə davranış öz yönləndiricisində UID üzrə filtrləyən üçüncü tərəf müştərilərindən gəlirdi. Fərq sazlama zamanı vacibdir, çünki bir paketlik icazə siyahısı olan tətbiq tuneli demək olar ki, heç trafik yaratmır və bu düzgün davranışdır, sınıq marşrut deyil.
Əhatə nə olursa olsun, tətbiqinizin VPN serverinə açdığı soket qurduğu tuneldən keçməməlidir. VpnService.protect(socket) həmin soketi alt şəbəkəyə bağlayır, beləliklə paketləri tun cihazını keçir. Çağırışı buraxın və əl sıxışma, onu qaldırmalı olan interfeys tərəfindən udulur.
VpnService.setUnderlyingNetworks sistemə tuneli hansı fiziki şəbəkənin daşıdığını deyərək dövrü bağlayır. Bu dəyər VPN-in digər tətbiqlərə bağlantı barədə necə məlumat verdiyini müəyyən edir və null və ya köhnəlmiş dəyər telefonun qalan hissəsinin oflayn saydığı qoşulmuş tunelin adi səbəbidir. Yalnız başlanğıcda deyil, alt şəbəkə dəyişdikdə onu yeniləyin.
Yoxlama məcmuləri və MTU: düzgün marşrutun yenə də uğursuz olduğu yer
Paketlər gəldikdən sonra paket səviyyəsində iki detal hər şeyin ucdan uca işləyib-işləmədiyini həll edir. Birincisi mənbə ünvanıdır: bir neçə interfeys ünvanı ilə kernel birincisini daşıyan paketlər buraxa bilər, ona görə başlıqları yenidən yazan yönləndirici ünvanı və onu əhatə edən yoxlama məcmusunu düzəltməlidir.
İkincisi yoxlama məcmusunun əhatəsidir. Tətbiq TCP və ya UDP paketlərini özü qurduqda yoxlama məcmusu mənbə ünvanı, təyinat ünvanı, protokol nömrəsi və daşıma uzunluğunu saxlayan psevdo-başlığı əhatə edir və bunlardan hər hansı birini buraxmaq gəlib düşən paketlər verir. Bu uğursuzluq heç vaxt gəlməyən cavabdan sonra fasilə kimi görünür və bu, çoxlarını yenidən marşrutlara qaytarır. setMtu interfeys MTU-nu təyin edir və hər oxuma tam bir IP paketi qaytarır, ona görə bayt axını üçün yazılmış bufer paketi deyil, təhlilinizi parçalayacaq.
Qatları ayıran yoxlama mərhələsi
Əhatənin harada səhv getdiyini tapmaq üçün qatları sıra ilə sınayın. Cihazdan VPN şəbəkəsinin həqiqətən hansı marşrutları saxladığını soruşun, sonra tanınmış ünvana axının deskriptorda oxuma kimi görünüb-görünmədiyini yoxlayın, sonra yönləndiricinizin buraxdığı paketin düzgün formalaşdığını yoxlayın. Marşrut problemi deskriptorda heç nə göstərmir, yoxlama məcmusu problemi isə gəlib yox olan paket göstərir.
Deskriptora heç nə çatmırsa, şübhəli oxuyucu deyil, marşrut dəstidir: prefiksləri təsdiqləyin, eyni ailədə ünvan olduğunu təsdiqləyin və tətbiqin qurduğunuz əhatə daxilində olduğunu təsdiqləyin. Paketlər deskriptora çatır, amma heç nə qayıtmırsa, yenidən marşruta toxunmazdan əvvəl protect() və alt şəbəkə dəyərini yoxlayın. Uzaq tərəf qüsurlu paketlər bildirirsə, yoxlama məcmusu və MTU baxmalı yerlərdir. Hər qat üçün bir yoxlama bir günortanı təxmin etməkdən qurtarır.