Waarom Android VpnService sommige verkeer onderskep en nie alles nie
Roetes, DNS-inskrywings en die toepassingbereik bepaal watter pakkette die tun-toestel bereik, waarom plaaslike toestelle verdwyn, en wat die bouer weier.
Niks aan 'n VpnService onderskep self verkeer nie. Dit vra die stelsel om 'n tun-koppelvlak, gee daardie koppelvlak 'n stel adresse en roetes, en van daardie oomblik af kopieer die kernel elke pakket wat by daardie roetes pas na 'n lêerbeskrywer wat die app kan lees. Die app se kode sien nooit die pakkette wat die roetes nie gekies het nie, so die omvang van 'n tonnel is eers 'n vraag oor die roetertabel en dan eers een oor programmering. Dis waarom dieselfde diensimplementering elke vloei op een foon kan insluk en op 'n ander net 'n skyfie, en waarom die byvoeg van 'n roete soms 'n tonnel herstel wat gebreek gelyk het. Wat jy kry is wat jy verklaar het, minus alles wat die bouer stilweg geweier het.
Roetes bepaal watter pakkette aankom
Builder.addRoute(prefix, prefixLength) plaas 'n voorvoegsel in die VPN-netwerk se roetertabel. Die stelsel behandel daardie netwerk as die verstek vir die apps in die bereik, so sy inskrywings word voor die fisiese netwerk se verstekroete geraadpleeg en 'n passende voorvoegsel is genoeg om 'n vloei te herlei. 'n Roete vir 0.0.0.0/0 neem dus IPv4 volledig, insluitend die drukker, die cast-teiken en die router se admin-bladsy.
Kliënte wat daardie dekking wil hê sonder om die fisiese verstekinskrywing te skrap, gebruik eerder die paar 0.0.0.0/1 en 128.0.0.0/1. Twee meer spesifieke roetes klop 'n verstekroete, saam dek hulle die hele adresruimte, en die foon se eie verstekinskrywing bly in die tabel vir die sokkels wat steeds aan die fisiese netwerk gebind is.
Adresse en DNS-inskrywings kom van dieselfde bouer en beantwoord 'n ander vraag. addAddress gee die koppelvlak 'n adres met 'n voorvoegsellengte, en addDnsServer installeer 'n oplosser wat apps in die bereik deur die koppelvlak sal ondervra. Albei families kan op een koppelvlak sit, so 'n slegs-IPv4-roetestel langs 'n IPv6-adres is 'n konfigurasie wat korrek lees en steeds lek. As jy 'n familie roeteer waarin die koppelvlak geen adres het nie, het die kernel geen bronadres vir daardie pakkette nie en verskyn hulle nooit by die beskrywer nie.
Wat establish() teruggee
establish() gee 'n ParcelFileDescriptor terug, of null wanneer die app nie gemagtig is nie. Null is 'n toestemmingstoestand eerder as 'n netwerkfout: VpnService.prepare() moes reeds null teruggegee het, of die gebruiker moes die stelseldialoog voor die oproep goedgekeur het. Toestemming kan herroep word terwyl die diens loop, en die koppelvlak sluit onder jou uit sonder enige terugroep in jou leeslus.
Die beskrywer is nie-blokkerend tensy jy anders sê, so 'n lees gee dadelik terug met geen data in plaas daarvan om die draad te parkeer. 'n Lus wat vir 'n blokkerende sokkel geskryf is, brand 'n kern, en 'n lus wat 'n leë lees as noodlottig beskou, skeur die tonnel af gedurende 'n ledige sekonde. Builder.setBlocking(true) verander daardie gedrag, en die prys is 'n draad wat binne die lees wag.
Roete- en adresargumente word as LinkAddress-waardes gevalideer, en multicast-bestemmings soos 224.0.0.0/4 word summier verwerp. 'n Punt-tot-punt tun-koppelvlak het ook geen uitsaaidomein nie, so multicast-ontdekking daaroor vereis 'n ander ontwerp eerder as nog 'n roete. Die VpnService.Builder-verwysing is die lys om na te gaan voordat jy aflei dat 'n oproep geïgnoreer is.
Toepassingbereik vernou die stel, nie die tonnel nie
Vanaf API 21 aanvaar die bouer addAllowedApplication en addDisallowedApplication, en die twee lyste is wedersyds uitsluitend binne een bouer. 'n Toelaatlys laat die tonnel vir daardie pakkette bestaan terwyl alles anders die fisiese netwerk behou; 'n weierlys vang alles behalwe die genoemde pakkette, wat 'n kliënt as gesplete tonneling bied. Voor API 21 is daar glad geen platformmeganisme nie, en toepassinggedrag het gekom van derdeparty-kliënte wat volgens UID binne hul eie aanstuurder filter. Die onderskeid maak saak wanneer jy ontfout, want 'n toepassingtonnel met 'n toelaatlys van een pakket produseer byna geen verkeer nie en dit is korrekte gedrag, nie 'n gebroke roete nie.
Wat die bereik ook al is, die sokkel wat jou app na die VPN-bediener oopmaak, mag nie deur die tonnel reis wat dit bou nie. VpnService.protect(socket) bind daardie sokkel aan die onderliggende netwerk sodat sy pakkette die tun-toestel oorslaan. Slaan jy die oproep oor, dan word die handdruk ingesluk deur die koppelvlak wat die handdruk veronderstel is om op te bring.
VpnService.setUnderlyingNetworks sluit die lus deur die stelsel te vertel watter fisiese netwerk die tonnel dra. Daardie waarde bepaal hoe die VPN verbinding aan ander apps rapporteer, en 'n nul- of verouderde waarde is 'n gereelde oorsaak van 'n gekoppelde tonnel wat die res van die foon as vanlyn beskou. Werk dit by wanneer die onderliggende netwerk verander, nie net by die opstart nie.
Kontrolesomme en MTU: waar 'n korrekte roete steeds misluk
Sodra pakkette wel aankom, besluit twee besonderhede op pakketvlak of enigiets van punt tot punt werk. Die eerste is die bronadres: met verskeie koppelvlakadresse kan die kernel pakkette uitstuur wat die eerste een dra, so 'n aanstuurder wat kopstukke herskryf, moet die adres en die kontrolesom wat dit dek, regstel.
Die tweede is kontrolesomomvang. Wanneer die app self TCP- of UDP-pakkette bou, dek die kontrolesom 'n pseudo-kopstuk met die bronadres, die bestemmingsadres, die protokolnommer en die vervoerlengte, en om enige van daardie weg te laat, lewer pakkette wat aankom en laat val word. Daardie faling lyk soos 'n tydsverloop ná 'n antwoord wat nooit kom nie, wat die meeste mense terug na die roetes stuur. setMtu stel die koppelvlak-MTU vas, en elke lees gee presies een volledige IP-pakket terug, so 'n buffer wat vir 'n greiestroom geskryf is, sal jou ontleding fragmenteer eerder as die pakket.
'n Verifikasieronde wat die lae skei
Om te vind waar die bereik verkeerd geloop het, toets die lae in volgorde. Vra die toestel watter roetes die VPN-netwerk werklik hou, kyk dan of 'n vloei na 'n bekende adres as 'n lees op die beskrywer verskyn, en kyk dan of die pakket wat jou aanstuurder uitstuur, goed gevorm is. 'n Roeteprobleem wys niks by die beskrywer nie, terwyl 'n kontrolesomprobleem 'n pakket wys wat aankom en verdwyn.
As niks die beskrywer bereik nie, is die roetestel die verdagte eerder as die leser: bevestig die voorvoegsels, bevestig dat daar 'n adres in dieselfde familie is, en bevestig dat die app binne die bereik is wat jy gestel het. As pakkette die beskrywer bereik maar niks terugkom, ondersoek protect() en die onderliggende netwerkwaarde voordat jy weer aan 'n roete raak. As die verre kant wanvormige pakkette rapporteer, is die kontrolesom en die MTU waar jy moet kyk. Een ondersoek per laag spaar 'n middag van raaiwerk.