Appen din sier frakoblet, menylinjen sier tilkoblet, og trafikken flyter tydelig. Det gapet er ikke en race condition du fikser med et nytt forsøk: appen og tunnelen er separate prosesser, og objektet koden din leser er en bufret visning av en konfigurasjon systemet lagrer. Apples Personal VPN-flate er et kontroll-API, ikke en databane, og det meste av den merkelige oppførselen følger av nettopp det. Her er hva som faktisk skjer ved hvert kall.

Behandlerobjektet er en bufret visning, ikke tunnelen

NETunnelProviderManager fylles fra et innstillingslager som systemet eier, så egenskapene betyr ingenting før loadFromPreferences er fullført. Leser du connection.status før det, får du en standardverdi, og derfor rapporterer den første statusoppdateringen etter en omstart frakoblet mens tunnelen kjører. Last inn først, og les deretter status og protokollkonfigurasjon fra samme fullføringshandler. Overvåk senere endringer via NEVPNStatusDidChange i stedet for å polle, og legg merke til at varslingen også utløses for tilkoblinger som On Demand starter, der det ikke finnes noe appkall som kan returnere noe. Det samme gjelder protokollinnstillinger: de leses fra den innlastede konfigurasjonen, ikke fra det appen sendte inn.

Selve tunnelen lever i en Network Extension-leverandørprosess, så appen kan miste sin egen tilstand uten å miste tilkoblingen. Alt grensesnittet viser må bygges opp igjen fra behandleren, ikke huskes fra forrige økt.

Startrekkefølge: lagre, last inn, start deretter

En leverandørbasert tilkobling trenger tre trinn i rekkefølge. Skriv leverandørkonfigurasjonen og kall saveToPreferences, last inn behandleren slik at den lagrede konfigurasjonen er den du holder i hånden, og start deretter via NETunnelProviderSession.startVPNTunnel(). Hopper du over lagringen, har starten ingenting å starte; laster du inn før lagringen, gjenspeiler behandleren fortsatt den gamle konfigurasjonen.

Boolsk verdi som startVPNTunnel returnerer sier bare at forespørselen ble godtatt. Feil på leverandørnivå kommer senere som en statusendring til frakoblet, som du observerer via varselet NEVPNStatusDidChange, og varselhandleren må lese connection.status på nytt etter loadFromPreferences fordi den bufrede verdien fortsatt kan være den gamle. Feil på forespørselsnivå kommer straks tilbake fra den kastende formen av kallet, eller via feilut-parameteren til startVPNTunnelAndReturnError:. Kode som behandler returverdien som resultatet, rapporterer en tilkobling som aldri ble etablert. Den andre stille feilen er en leverandørbundle-identifikator som ikke samsvarer med den installerte utvidelsen: forespørselen avvises, og ingenting i meldingen peker på identifikatoren. Er identifikatoren feil, feiler forespørselen vanligvis med en gang, før noen logglinje fra leverandøren vises.

Å laste innstillingene på nytt etter en start er det som gjør statusskjermer riktige. Behandleren dytter ikke en ny konfigurasjon til deg når systemet endrer den.

Tillitsmateriale kommer via profil, aldri fra appkode

En app har ingen støttet måte å legge et rotssertifikat til iOS’ tillitslager, så en Personal VPN-konfigurasjon kan bare referere materiale enheten allerede stoler på: en kjede etablert av en installert profil, av enhetsstyring eller av en CA systemet stoler på av andre grunner. En app som lager sin egen CA ved første oppstart og forventer at systemet anerkjenner den, vil feile valideringen inne i leverandøren, der appens grensesnitt ikke kan se årsaken.

Behandle den grensen som den designbegrensningen den er, og lever tillitsankeret sammen med registreringsprofilen. Hold VPN-autentisering atskilt fra tillitsbeslutningen, fordi de feiler på forskjellige steder og feilsøkes av forskjellige folk.

Tellerne kommer fra grensesnittet, ikke fra VPN-API-et

Behandleren eksponerer status og konfigurasjon, og ingenting som teller byte per tunnel. Trenger du brukstall, kall getifaddrs() og les if_data for det aktuelle grensesnittet: en0 for Wi-Fi, pdp_ip-grensesnittene for mobil og en utun-enhet for selve tunnelen. Tellerne til utun beskriver indre trafikk og inkluderer protokolloverhead.

Disse tallene er anslag, ikke regnskap per app, og de nullstilles når grensesnittet gjenskapes. Merk dem slik i grensesnittet, ellers bruker noen dem til å fakturere en kunde. Trenger du tall per app, trenger du en helt annen mekanisme, ikke en bedre lesing av disse feltene.

Opprydding hører i stopVPNTunnel, ikke i avslutning

applicationWillTerminate gir deg noen sekunder før systemet kan drepe prosessen, og det er ikke et pålitelig sted å rive ned en tilkobling. Send stoppen til stopVPNTunnel() eller håndter den i leverandørens stopp-callback, og behold behandler- eller konfigurasjonsidentifikatoren du startet med, slik at stoppen treffer den tilkoblingen i stedet for hver konfigurasjon på enheten.

Lagre den identifikatoren ved siden av profilen den hører til, siden et behandlerobjekt ikke registrerer hvilken konfigurasjon brukeren valgte. Og husk at en tilkobling som On Demand reiser, ikke har noe appkall bak seg i det hele tatt, så en statusskjerm må fortsatt laste innstillingene før den tegner noe.

Relaterte artikler