Səhv fərziyyə odur ki, VpnService tətbiqi sistem açarını çevirir və telefondan sonra qorunur. Əslində baş verən daha dardır: tətbiq razılıq istəyir, interfeys qurur, fayl deskriptoru vasitəsilə paketləri oxuyur və yazır, dayandıqda isə interfeysi geri qaytarır. Eyni anda yalnız bir belə tunel canlı ola bilər və sistem onu soruşmadan ala bilər. İnsanların protokola yazdığı çaşqın davranışın çoxu bu sahiblik modelindən gəlir.

Hər həyat dövrü keçidini kənar hal kimi deyil, dizaynın bir hissəsi kimi qəbul edin.

Mif: tətbiq telefonun VPN-ni işə salır

Axın VpnService.prepare() ilə başlayır, bu istifadəçinin qəbul etməli olduğu Intent qaytarır və establish() ilə davam edir, bu da sonradan tətbiqin nəzarət etmədiyi səbəblərə görə uğursuz ola bilər. İkinci tunelin qurulması birinci interfeysi söndürür və sistem bildirişini əvəz edir. Bu ardıcıllığın heç bir yerində tətbiq cihaz miqyaslı açarə sahib deyil; ona verilən deskriptora və ona düşən paketlərə sahibdir. Hətta daimi bildiriş də tətbiqin dizaynına deyil, sistemə aiddir.

İnterfeys tutulduğu üçün deyil, verildiyi üçün başqa klient yeri istənilən vaxt tuta bilər. Tətbiq bunu qaytarılan dəyərdən deyil, geri çağırışdan öyrənir.

Tətbiqi məcburi dayandırmağın bildiriş panelində görünməsinin səbəbi eynidir: sistem nəyi verdiyini bildirir, tətbiqin nə göstərməyi seçdiyini yox.

Mif: razılıq bir dəfə verilir

Sistem tuneli başqa klientə verdikdə, əsas sinfin onBind()-dən qaytardığı binder üzərində ləğv əməliyyatı göndərir. Həmin binderi özü ilə əvəz edən tətbiq ləğv əməliyyatını özü ötürməlidir, əks halda VpnService.onRevoke() heç vaxt işə düşmür və xidmət artıq mövcud olmayan deskriptora yazmağa davam edir. Razılıq istifadəçi tərəfindən də geri götürülə bilər və sistem yenidən başlatma və ya daim aktiv yenidən qoşulma zamanı xidməti dayandıra bilər.

Bununla məşğul olmaq log sətri deyil, konkret işdir: deskriptoru oxumağı dayandırın, bağlayın, qoşulma bayrağını təmizləyin və istifadəçiyə hansı vəziyyətdə olduğunu deyin. Sonra tətbiqin yenidən qurmalı, yenidən soruşmalı və ya gözləməli olduğuna qərar verin, çünki daim aktiv konfiqurasiyada sistem xidməti özü geri gətirə bilər.

Ləğvi vəziyyət deyil, istisna kimi qəbul edən tətbiq hər yazdığı paket atılarkən qoşulduğunu bildirəcək və bu, məxfilik aləti üçün mümkün olan ən pis uğursuzluq rejimidir.

Mif: interfeys trafiki sizin üçün filtrləyir

Gələn xam IP-dir. Tutmaq və ya filtrləmək IP, TCP, UDP və IPv6 başlıqlarını təhlil etmək, axınları izləmək və cavabları deskriptora geri yazmaq deməkdir ki, bu da tutma tətbiqini sistem imkanı deyil, kiçik şəbəkə yığınına çevirir. protect() ona görə mövcuddur ki, tətbiqin öz nəqliyyat soketi öz tunelini yan keçsin, özünü tutmasın və tunel qurulduqdan sonra yaradılan hər soketdə yoxlanılmağa dəyər boolean qaytarır.

Qurucunun icazəli və qadağan olunmuş tətbiq siyahıları kimin trafikinin interfeysə girəcəyini müəyyən edir. Onlar interfeysin daşıdığı IP paketlərindən kənar yüklərə çıxış vermir və heç bir API başqa klientin tunelini ifşa etmir və ya sistemin VPN profillərini sadalayır. Şəbəkə imkanları bir şəbəkənin VPN nəqli olduğunu deyə bilər, amma tunelin kimə aid olduğunu yox.

Buna görə başqa tətbiqlər haqqında status sualları ziddiyyətli cavablar alır: məlumat sadəcə olaraq prosesinizə açılmır.

Həyat dövrü əslində nə tələb edir

Nəzarət etdiyiniz vəziyyətləri izləyin: hazır, qurulmuş, ləğv edilmiş, dayandırılmış. Yenidən qoşulma sökmə və sonra qurma olmalıdır, deskriptor və nəqliyyat soketi üçün tək sahiblə, çünki qurmaq üçün yarışan iki komponent mövcud yeganə yer üstündə çəkişəcək. Müasir Android-də fon başlatmaları məhduddur, ona görə önyükləmə yayımı zəmanət deyil; API səviyyəsi imkan verdikdə bildirişi ilə ön plan xidmətindən istifadə edin.

Yalnız son vəziyyəti deyil, keçidi qeyd edin və vəziyyət maşınını hər yolu sınamaq üçün kifayət qədər kiçik saxlayın. Testdə çata bilmədiyiniz vəziyyət, sahədə logsuz qarşılaşacağınız vəziyyətdir.

Həyat dövrünü cihazda sınayın

Emulyatorlar qoşulmanı saxtalaşdıra bilər, amma razılıq və ləğv yolunu inandırıcı şəkildə yox, ona görə bunları yeri tutmaq üçün ikinci VPN klienti quraşdırılmış real cihazda işə salın.

adb shell dumpsys connectivity | grep -i -A3 vpn
adb shell dumpsys activity services | grep -i -A2 vpnservice
adb logcat -s VpnService:V AndroidRuntime:E
adb shell am force-stop com.example.vpnapp

Tuneli başladın, bildirişi və interfeysi təsdiqləyin, sonra digər klienti qoşun və ləğv geri çağırışının işləyib-işləmədiyini və vəziyyətin təmizləndiyini izləyin. Tətbiqi məcburi dayandırın və hər hansı bir şeyin hələ canlı deskriptor bildirib-bildirmədiyini yoxlayın.

Ardıcıllığı daim aktiv yenidən başlatmadan sonra təkrarlayın, çünki bu yol istifadəçinin başlatdığı qoşulmadan fərqlənir. Axtardığınız yaşıl ikon deyil, tətbiqin artıq sahib olmadığı deskriptordan istifadəni dayandırdığına dair sübutdur.

Əlaqəli məqalələr