Zašto vaša iOS VPN aplikacija pokazuje prekinuto dok je tunel aktivan
Vaša iOS aplikacija upravlja tunelom ali ga ne posjeduje, a stanje menadžera je keširano. Prvo učitajte postavke, zatim pročitajte status i brojače interfejsa.
Vaša aplikacija kaže prekinuto, traka menija kaže povezano, a saobraćaj očigledno teče. Ta razlika nije stanje trke koje popravljate ponovnim pokušajem: aplikacija i tunel su odvojeni procesi, a objekat koji vaš kod čita je keširani prikaz konfiguracije koju sistem čuva. Apple-ov Personal VPN interfejs je kontrolni API, a ne putanja podataka, i većina njegovog neobičnog ponašanja proizlazi iz te jedne činjenice. Evo šta se zapravo dešava pri svakom pozivu.
Objekat menadžera je keširani prikaz, a ne tunel
NETunnelProviderManager se popunjava iz skladišta postavki koje posjeduje sistem, pa njegova svojstva ništa ne znače dok loadFromPreferences ne završi. Ako pročitate connection.status prije toga, dobijate zadanu vrijednost, i zato prvo osvježavanje statusa nakon ponovnog pokretanja prijavljuje prekinuto dok je tunel aktivan. Prvo učitajte, pa pročitajte status i konfiguraciju protokola iz istog rukovaoca završetka. Kasnije promjene pratite kroz NEVPNStatusDidChange umjesto periodične provjere i imajte na umu da se obavještenje javlja i za veze koje pokreće On Demand, gdje ne postoji nikakav poziv aplikacije koji bi nešto vratio. Isto važi i za postavke protokola: čitaju se iz učitane konfiguracije, a ne iz onoga što je aplikacija poslala.
Sam tunel živi u procesu provajdera Network Extension, pa aplikacija može izgubiti vlastito stanje bez gubitka veze. Sve što interfejs prikazuje mora se ponovo izgraditi iz menadžera, a ne pamtiti iz posljednje sesije.
Redoslijed pokretanja: sačuvaj, učitaj, pa pokreni
Veza zasnovana na provajderu zahtijeva tri koraka po redu. Zapišite konfiguraciju provajdera i pozovite saveToPreferences, učitajte menadžera da sačuvana konfiguracija bude ona koju držite, pa pokrenite kroz NETunnelProviderSession.startVPNTunnel(). Preskočite li čuvanje, pokretanje nema šta da pokrene; učitate li prije čuvanja, menadžer i dalje odražava staru konfiguraciju.
Booleova vrijednost koju vraća startVPNTunnel samo kaže da je zahtjev prihvaćen. Greške na nivou provajdera dolaze kasnije kao promjena statusa u prekinuto, što pratite kroz obavještenje NEVPNStatusDidChange, a rukovalac obavještenja mora ponovo pročitati connection.status nakon loadFromPreferences jer keširana vrijednost može još biti stara. Greške na nivou zahtjeva vraćaju se odmah iz oblika poziva koji baca izuzetak ili kroz izlazni parametar greške od startVPNTunnelAndReturnError:. Kod koji vraćenu vrijednost tretira kao ishod prijavljuje vezu koja nikada nije uspostavljena. Drugi tihi kvar je identifikator paketa provajdera koji se ne poklapa s instaliranim proširenjem: zahtjev se odbija i ništa u poruci ne upućuje na identifikator. Ako je identifikator pogrešan, zahtjev obično odmah propada, prije nego se pojavi ijedan red u dnevniku provajdera.
Ponovno učitavanje postavki nakon pokretanja jeste ono što čini ekrane statusa ispravnim. Menadžer vam ne šalje novu konfiguraciju kada je sistem promijeni.
Materijal povjerenja dolazi putem profila, nikada iz koda aplikacije
Aplikacija nema podržan način da doda korijenski certifikat u iOS skladište povjerenja, pa Personal VPN konfiguracija može referencirati samo materijal kojem uređaj već vjeruje: lanac uspostavljen instaliranim profilom, upravljanjem uređajem ili CA kojem sistem vjeruje iz drugih razloga. Aplikacija koja stvori vlastiti CA pri prvom pokretanju i očekuje da ga sistem prihvati propast će na validaciji unutar provajdera, gdje korisnički interfejs aplikacije ne može vidjeti razlog.
Tretirajte tu granicu kao dizajnersko ograničenje kakvo jeste i isporučite sidro povjerenja uz profil za upis. Držite VPN autentifikaciju odvojeno od odluke o povjerenju, jer one propadaju na različitim mjestima i otklanjaju ih različiti ljudi.
Brojači dolaze s interfejsa, ne iz VPN API-ja
Menadžer izlaže status i konfiguraciju i ništa što broji bajtove po tunelu. Ako su vam potrebni brojevi potrošnje, pozovite getifaddrs() i pročitajte if_data za odgovarajući interfejs: en0 za Wi-Fi, interfejse pdp_ip za mobilnu mrežu i utun uređaj za sam tunel. Brojači utun opisuju unutrašnji saobraćaj i uključuju protokolni trošak.
Te brojke su procjene, a ne obračun po aplikaciji, i resetuju se kada se interfejs ponovo stvori. Označite ih tako u interfejsu, ili će ih neko iskoristiti da naplati kupcu. Ako su vam potrebni brojevi po aplikaciji, potreban vam je potpuno drugačiji mehanizam, a ne bolje čitanje ovih polja.
Čišćenje pripada stopVPNTunnel, a ne terminaciji
applicationWillTerminate vam daje nekoliko sekundi prije nego sistem može ubiti proces, što nije pouzdano mjesto za rušenje veze. Pošaljite zaustavljanje na stopVPNTunnel() ili ga obradite u povratnom pozivu za zaustavljanje provajdera, i zadržite identifikator menadžera ili konfiguracije s kojim ste pokrenuli, da zaustavljanje cilja tu vezu umjesto svake konfiguracije na uređaju.
Sačuvajte taj identifikator uz profil kojem pripada, jer objekat menadžera ne bilježi koju je konfiguraciju korisnik odabrao. I zapamtite da veza koju podigne On Demand nema nikakav poziv aplikacije iza sebe, pa ekran statusa i dalje mora učitati postavke prije nego išta nacrta.