Android VpnService ilə bağlı dörd fərziyyə mənə bir dəfə həftənin böyük hissəsini baha başa gəldi və heç biri şəbəkə protokolu ilə bağlı deyildi. Tətbiq «qoşuldu» dedi, açar ikonu status panelində oturdu, trafik isə yenə adi marşrutla çıxdı. Tunelin mənim olduğunu onu dayandırana qədər, əlavə etdiyim marşrutların elə həmin marşrutlar olduğunu və stopSelf çağırışının interfeysi özü ilə birlikdə söndürəcəyini zənn edirdim. Xidmət sənədləşdirildiyi kimi davranırdı. Pozulan hissə mənim zehni modelim idi.

Mif 1: tunel siz onu dayandırana qədər ayaqda qalır

Android eyni anda bir VPN interfeysi saxlayır. İkincisini qursanız, platform onu növbəyə qoymur; sizin interfeysinizi deaktiv edir və xidmətinizdə onRevoke() çağırır. Kodunuz yalnız düymə basıldıqda sökülürsə, ələ keçirmə arxada bir deskriptor və oxucu ip qoyur, növbəti başlanğıc isə hər ikisini miras alır.

VpnService sənədləri açıq deyir ki, prepare() tətbiqin artıq razılığı olduqda null qaytarır, istifadəçi hələ təsdiq etməlidirsə isə Intent qaytarır. Bu razılıq yalnız niyyəti startActivityForResult() vasitəsilə çatdırsanız qüvvəyə minir. Ötürməni atlayın və establish() null qaytarır, bu da icazə problemi deyil, səssiz uğursuzluq kimi oxunur.

Always-on VPN sizin nəzarət etmədiyiniz bir sahib əlavə edir. Sistem tuneli yükləmədən və ya qəzadan sonra geri qaytara bilər və istifadəçinin əl ilə başlatdığı VPN tətbiqini üstələyir. onRevoke() funksiyasını elə qurun ki, adi söndürmənizlə eyni resursları bağlasın və ona kənar hal deyil, əsas dayandırma yolu kimi baxın. İstifadəçilər VPN tətbiqlərini dəyişir; kodunuz buna dözməlidir.

Mif 2: addRoute tam olaraq sadaladığınızı tutur

Marşrutlar hansı paketlərin deskriptorunuza çatdığını müəyyən edir və əhatə xətası trafikin bir hissəsinin tuneldən keçdiyi, bir hissəsinin isə keçmədiyi qıcıqlandırıcı halı yaradır. addRoute("0.0.0.0", 0) bütün IPv4-ü tutur, yəni hər paket indi sizə gəlir və yönləndirilməli və ya atılmalıdır. Tək host üçün /32 demək olar ki, heç nə tutmur və qalan hər şey VPN heç quraşdırılmamış kimi davranır.

Ailələr ayrıca sayılır. Yalnız IPv4 üçün marşrut IPv6-nı əsas şəbəkədə qoyur, buna görə iki stack-li host tunelin içində tam qoşulmuş görünərkən yenə də tuneldən kənarda həll edə və qoşula bilər.

DNS eyni məntiqə tabedir. addDnsServer() ilə əlavə edilən serverlər tunel həlledicisindən istifadə edən tətbiqlərə gedir, öz şifrələnmiş DNS son nöqtəsi olan və ya Private DNS-i host adına qoyulmuş tətbiq isə onları tamamilə görməzliyə vurur. Adlar bir tətbiq üçün uğursuz olub digəri üçün işləyəndə, tək bir marşruta toxunmadan əvvəl həlledici yolunu yoxlayın.

Mif 3: proqram üzrə qaydalar hər iki tərəfə çevirə biləcəyiniz bir açardır

addDisallowedApplication() və addAllowedApplication() iki filtr deyil, iki rejimdir. Qurucu tunel üzrə bir model qəbul edir, buna görə üç paketdən başqa hər şeyi istəyən tətbiq qadağan olunmuş siyahıdan istifadə edir və icazə verilmiş siyahını boş qoyur. İkisi bir-birini istisna edir və insanlar bunu parametrlər ekranı artıq hər iki açarı təklif etdikdən sonra işləmə vaxtında öyrənir.

Paket görünürlüyü də dişləyir. Android 11 və sonrasında yalnız gördüyünüz paketləri adlandıra bilərsiniz, buna görə tətbiqinizin işlətməsinə icazə olmayan sorğudan qurulan istisna siyahısı səssizcə qeydləri qaçıracaq. Siyahını paket menecerinin həqiqətən qaytardığı ilə müqayisə edin, sonra ona güvənin.

İş profilləri auditoriyanı yenidən bölür. Profilin içində başladılan tunel o profili və tətbiqlərini əhatə edir, şəxsi tərəf isə öz bağlantısını saxlayır. Bu, bir dəfə verilən əhatə qərarıdır və dəstək biletində deyil, interfeysdə yer almalıdır.

Mif 4: stopSelf tuneli bitirir

Bitmir. İnterfeys establish() tərəfindən qaytarılan deskriptorda yaşayır və deskriptor açıq qalarkən xidmət obyekti ölə bilər. Əvvəlcə ParcelFileDescriptor bağlayın, istinadı buraxın, oxucu və yazıcı ipləri birləşdirin və ya kəsin, sonra stopForeground(true) və stopSelf() funksiyalarını bu sıra ilə çağırın.

Unudulmuş deskriptor xidmətin öz dayandırma sorğusundan sağ çıxmış kimi görünməsinin adi səbəbidir və onu əlavə edən tətbiqdən daha uzun yaşayan köhnə marşrutu izah edir.

Əks səhv də eyni dərəcədə geniş yayılmışdır: oxucu ip ortada oxuyarkən deskriptoru bağlamaq, sonra həmin ipi heç kimin yazmadığı istisnanı idarə etməyə buraxmaq. Söndürmə ardıcıllığını bir yerdə saxlayın və həm istifadəçi hərəkəti, həm də onRevoke() ora çağırsın.

Tunel ölü görünəndə nəyi yoxlamaq lazımdır

Tunel qalxmadan əvvəl uzunömürlü soketləri protect() ilə qoruyun. Bu olmadan tunelin öz nəqliyyatı yenidən tunelin içinə yönləndirilir və bağlantı tam olaraq server nasazlığına bənzəyən şəkildə dayanır. Yalnız uzaq şəbəkənin arxasında olan ünvana qarşı sınaq keçirin, keşdən və ya əsas yoldan cavab verən açıq sayta qarşı deyil.

establish() nəticəsini, marşrutları, istisna edilmiş paketləri və söndürmə səbəbini qeyd edin. Bu dörd sətir paket tutmadan razılıq problemini əhatə problemindən və həyat dövrü problemindən ayırır.

Əlaqəli məqalələr