Ingenting i VpnService fangar trafikk av seg sjølv. Det ber systemet om eit tun-grensesnitt, gir det grensesnittet eit sett adresser og ruter, og frå det augneblinken kopierer kjernen kvar pakke som samsvarer med desse rutene, inn i ein fildeskriptor appen kan lese. Koden til appen ser aldri pakkane rutene ikkje valde, så omfanget av ein tunnel er eit spørsmål om rutetabellen før det er eit programmeringsspørsmål. Difor kan same tenesteimplementasjon sluke kvar straum på ein telefon og berre ein del på ein annan, og difor reparerer ei ekstra rute nokre gonger ein tunnel som såg øydelagd ut. Det du får er det du kunngjorde, minus alt byggjaren teidde og avviste.

Ruter avgjer kva pakkar som kjem

Builder.addRoute(prefix, prefixLength) installerer eit prefiks i rutetabellen til VPN-nettet. Systemet handsamar det nettet som standard for appane i omfanget, så oppføringane blir lesne før standardruta til det fysiske nettet, og eit samsvarande prefiks er nok til å leie ein straum bort. Difor tek ei rute for 0.0.0.0/0 IPv4 fullt ut, inkludert skrivaren, cast-målet og admin-sida til rutaren.

Klientar som vil ha den dekninga utan å slette den fysiske standardoppføringa, brukar i staden paret 0.0.0.0/1 og 128.0.0.0/1. To meir spesifikke ruter slår ei standardrute, saman dekkjer dei heile adresserommet, og telefonens eiga standardoppføring blir verande i tabellen for sokkane som framleis er bundne til det fysiske nettet.

Adresser og DNS-oppføringar kjem frå same byggjar og svarer på eit anna spørsmål. addAddress gir grensesnittet ei adresse med prefikslengd, og addDnsServer installerer ein løysar som appane i omfanget vil spørje gjennom grensesnittet. Båe familiane kan sitje på eitt grensesnitt, så eit reint IPv4-rutesett ved sida av ei IPv6-adresse er ein konfigurasjon som blir lesen rett og likevel lekk. Viss du rutar ein familie der grensesnittet ikkje har adresse, har kjernen inga kjeldeadresse for dei pakkane, og dei viser seg aldri ved deskriptoren.

Kva establish() gir tilbake

establish() returnerer ein ParcelFileDescriptor, eller null når appen ikkje er autorisert. Null er ein samtykketilstand, ikkje ein nettverksfeil: VpnService.prepare() må allereie ha returnert null, eller brukaren må ha godkjent systemdialogen før kallet. Samtykket kan trekkjast tilbake medan tenesta køyrer, og grensesnittet blir stengt under føtene dine utan noko tilbakekall i leseløkka.

Deskriptoren er ikkje-blokkerande med mindre du seier noko anna, så ei lesing kjem straks tilbake utan data i staden for å parkere tråden. Ei løkke skriven for ein blokkerande socket brenn ein kjerne, og ei løkke som handsamar ei tom lesing som fatal, riv tunnelen ned i eit ledig sekund. Builder.setBlocking(true) endrar denne åtferda, og prisen er ein tråd som ventar inne i lesinga.

Rute- og adresseargument blir validerte som LinkAddress-verdiar, og multicast-mål som 224.0.0.0/4 blir avviste blankt. Eit punkt-til-punkt tun-grensesnitt har heller ikkje eit broadcast-domene, så multicast-oppdaging over det krev ein annan design i staden for endå ei rute. Referansen VpnService.Builder er lista du bør sjekke før du konkluderer med at eit kall blei ignorert.

Omfanget per app snevrar inn settet, ikkje tunnelen

Frå API 21 godtek byggjaren addAllowedApplication og addDisallowedApplication, og dei to listene utelukkar kvarandre innanfor ein byggjar. Ei tillatingsliste gjer tunnelen eksisterande for dei pakkane, medan alt anna held på det fysiske nettet; ei blokkeringsliste fangar alt utanom dei namngjevne pakkane, som er det ein klient tilbyr som delt tunnellering. Før API 21 finst ingen plattformmekanisme i det heile, og åtferd per app kom frå tredjepartsklientar som filtrerte på UID i sin eigen videresendar. Skilnaden tel når du feilsøkjer, fordi ein app-tunnel med ei tillatingsliste på éin pakke nesten ikkje gir trafikk, og det er korrekt åtferd, ikkje ei øydelagd rute.

Uansett omfang må sokkelen appen din opnar mot VPN-tenaren, ikkje reise gjennom tunnelen han byggjer. VpnService.protect(socket) bind den sokkelen til det underliggjande nettet slik at pakkane hoppar over tun-eininga. Viss du hoppar over kallet, blir handtrykket slukt av grensesnittet som skulle heve det.

VpnService.setUnderlyingNetworks lukkar løkka ved å fortelje systemet kva fysisk nett som ber tunnelen. Den verdien avgjer korleis VPN rapporterer tilkopling til andre apper, og ein null- eller utdatert verdi er ein vanleg årsak til ein tilkopla tunnel som resten av telefonen handsamar som fråkopla. Oppdater han når det underliggjande nettet endrar seg, ikkje berre ved oppstart.

Kontrollsummar og MTU: der ei korrekt rute likevel feilar

Når pakkane først kjem, avgjer to detaljar på pakkenivå om noko fungerer ende til ende. Den første er kjeldeadressa: med fleire grensesnittadresser kan kjernen sende pakkar som ber den første, så ein videresendar som skriv om hovud, må rette adressa og kontrollsummen som dekkjer henne.

Den andre er omfanget til kontrollsummen. Når appen byggjer TCP- eller UDP-pakkar sjølv, dekkjer kontrollsummen eit pseudo-hovud med kjeldeadresse, måladdresse, protokollnummer og transportlengd, og å utelate nokon av dei gir pakkar som kjem og blir kasta. Den feilen ser ut som ein tidsavbrot etter eit svar som aldri kjem, noko som sender dei fleste tilbake til rutene. setMtu fastset MTU-en til grensesnittet, og kvar lesing returnerer nøyaktig éin fullstendig IP-pakke, så ein buffer skriven for ein bytestraum vil fragmentere parseringa di, ikkje pakka.

Ein verifiseringsrunde som skil laga

For å finne kvar omfanget gjekk gale, test laga i rekkjefølgje. Spør eininga kva ruter VPN-nettet faktisk held, sjekk deretter om ein straum til ei kjend adresse dukkar opp som ei lesing på deskriptoren, og sjekk deretter om pakka videresendaren din sender ut, er velforma. Eit ruteproblem viser ingenting ved deskriptoren, medan eit kontrollsumproblem viser ei pakke som kjem og forsvinn.

Viss ingenting når deskriptoren, er det rutesettet som er mistenkt og ikkje lesaren: stadfest prefiksa, stadfest at det finst ei adresse i same familie, og stadfest at appen er innanfor omfanget du sette. Viss pakkane når deskriptoren, men ingenting kjem tilbake, undersøk protect() og verdien for det underliggjande nettet før du rører ei rute igjen. Viss den fjerne sida rapporterer misdanna pakkar, er kontrollsummen og MTU-en staden å sjå. Éin sondering per lag sparer ein ettermiddag med gjetting.

Relaterte artiklar