Wêrom Android VpnService in part fan it ferkear fangt en net alles
Rûtes, DNS-yngongen en it berik per app beslisse hokker pakketten it tun-apparaat berikke, wêrom lokale apparaten ferdwine en wat de bouwer wegeret.
Neat yn VpnService ûnderskept ferkear fan himsels. It freget it systeem om in tun-ynterface, jout dy ynterface in set adressen en rûtes, en fan dat momint kopiearret de kernel elk pakket dat by dy rûtes past yn in bestânsdeskriptor dy't de app lêze kin. De koade fan de app sjocht nea de pakketten dy't de rûtes net keazen hawwe, dus it berik fan in tunnel is in fraach fan 'e rûtingstabel foardat it in programmeurfraach is. Dêrom kin deselde tsjinstymplemintaasje op ien telefoan elke stream opslokke en op in oare mar in part, en dêrom reparearret it tafoegjen fan in rûte soms in tunnel dy't brutsen like. Wat jo krije is wat jo ferklearre hawwe, minus alles wat de bouwer stil wegeret.
Rûtes beslisse hokker pakketten oankomme
Builder.addRoute(prefix, prefixLength) ynstallearret in prefiks yn 'e rûtingstabel fan it VPN-netwurk. It systeem behannelet dat netwurk as standert foar de apps yn it berik, dus syn yngongen wurde besjoen foar de standertrûte fan it fysike netwurk en in passend prefiks is genôch om in stream om te lieden. Dêrom nimt in rûte foar 0.0.0.0/0 IPv4 folslein, ynklusyf de printer, it cast-doel en de admin-side fan 'e router.
Klanten dy't dy dekking wolle sûnder de fysike standertyngong te wiskjen, brûke ynstee it pear 0.0.0.0/1 en 128.0.0.0/1. Twa mear spesifike rûtes ferslaan in standertrûte, tegearre beslaan se de hiele adresromte, en de eigen standertyngong fan 'e telefoan bliuwt yn 'e tabel foar de sockets dy't noch oan it fysike netwurk bûn binne.
Adressen en DNS-yngongen komme fan deselde bouwer en beantwurdzje in oare fraach. addAddress jout de ynterface in adres mei in prefikslange, en addDnsServer ynstallearret in oplosser dy't apps yn it berik fia de ynterface befreegje. Beide famyljes kinne op ien ynterface sitte, dus in set rûtes allinnich IPv4 njonken in IPv6-adres is in konfiguraasje dy't korrekt lêst en dochs lekket. As jo in famylje rûtsje dêr't de ynterface gjin adres yn hat, hat de kernel gjin boarne-adres foar dy pakketten en se ferskine nea by de deskriptor.
Wat establish() weromjout
establish() jout in ParcelFileDescriptor werom, of null as de app net autorisearre is. Null is in tastimmingstastân en gjin netwurkflater: VpnService.prepare() moat al null weromjûn hawwe, of de brûker moat de systeemdialooch foar de oprop goedkard hawwe. Tastimming kin ynlutsen wurde wylst de tsjinst rint, en de ynterface slút ûnder jo fuotten sûnder in weromrop yn jo lêslus.
De deskriptor blokket net, útsein as jo oars sizze, dus in lêzing komt daliks werom sûnder gegevens ynstee fan 'e tried te parkearjen. In lus skreaun foar in blokkearjende socket baarnt in kearn, en in lus dy't in lege lêzing as fataal sjocht skuort de tunnel del yn in idle sekonde. Builder.setBlocking(true) feroaret dat gedrach, en de priis is in tried dy't yn 'e lêzing wachtet.
Rûte- en adresarguminten wurde falidearre as LinkAddress-wearden, en multicast-bestimmingen lykas 224.0.0.0/4 wurde daliks wegere. In punt-nei-punt tun-ynterface hat ek gjin broadcast-domein, dus multicast-ûntdekking dertroch freget in oar ûntwerp ynstee fan noch in rûte. De VpnService.Builder-ferwizing is de list om te kontrolearjen foardat jo konkludearje dat in oprop negearre waard.
It berik per app makket de set lytser, net de tunnel
Fan API 21 ôf akseptearret de bouwer addAllowedApplication en addDisallowedApplication, en de twa listen slute inoar út binnen ien bouwer. In list fan tastiene makket de tunnel besteand foar dy pakketten wylst al it oare it fysike netwurk hâldt; in list fan ferbeane fangt alles behalve de neamde pakketten, wat in klant as splitst tunnele biedt. Foar API 21 is der hielendal gjin platfoarmmeganisme, en gedrach per app kaam fan tredepartijklanten dy't op UID filteren binnen har eigen trochstjoerder. It ferskil is wichtich by it debuggen, want in app-tunnel mei in list fan tastiene fan ien pakket produsearret hast gjin ferkear en dat is korrekt gedrach, gjin brutsen rûte.
Wat it berik ek is, de socket dy't jo app nei de VPN-tsjinner iepenet mei net troch de tunnel reizgje dy't er bout. VpnService.protect(socket) bynt dy socket oan it ûnderlizzende netwurk sadat syn pakketten it tun-apparaat oerslaan. Slach de oprop oer en it hânskudden wurdt opslokt troch de ynterface dy't it hânskudden opbringe moast.
VpnService.setUnderlyingNetworks slút de lus troch it systeem te fertellen hokker fysyk netwurk de tunnel draacht. Dy wearde bepaalt hoe't de VPN ferbining oan oare apps rapportearret, en in null- of ferâldere wearde is in gewoane oarsaak fan in ferbûne tunnel dy't de rest fan 'e telefoan as offline behannelet. Wurkje it by as it ûnderlizzende netwurk feroaret, net allinnich by it starten.
Kontrôlesommen en MTU: wêr't in korrekte rûte dochs mislearret
As pakketten ienris oankomme, beslisse twa details op pakketnivo oft eat fan ein oant ein wurket. It earste is it boarne-adres: by ferskate ynterface-adressen kin de kernel pakketten stjoere dy't it earste drage, dus in trochstjoerder dy't kopteksten oerskriuwt moat it adres en de kontrôlesom dy't it dekt reparearje.
It twadde is it berik fan 'e kontrôlesom. As de app sels TCP- of UDP-pakketten bout, dekt de kontrôlesom in pseudo-koptekst mei it boarne-adres, it bestimmingsadres, it protokolnûmer en de lingte fan it ferfier, en ien dêrfan weilitten jout pakketten dy't oankomme en fuortgoaid wurde. Dy flater liket op in time-out nei in antwurd dat nea komt, wat de measte minsken weromstjoert nei de rûtes. setMtu fêstiget de MTU fan 'e ynterface, en elke lêzing jout krekt ien folslein IP-pakket werom, dus in buffer skreaun foar in bytestream fragmintearret jo parsen, net it pakket.
In ferifikaasje-omgong dy't de lagen skiedt
Om te finen wêr't it berik ferkeard gie, test de lagen yn folchoarder. Freegje it apparaat hokker rûtes it VPN-netwurk echt hâldt, kontrolearje dan oft in stream nei in bekend adres as in lêzing by de deskriptor ferskynt, kontrolearje dan oft it pakket dat jo trochstjoerder stjoert goed foarme is. In rûteprobleem lit neat by de deskriptor sjen, wylst in kontrôlesomprobleem in pakket lit sjen dat oankomt en ferdwynt.
As neat de deskriptor berikt, is de rûteset de fertochte en net de lêzer: befêstigje de prefiksen, befêstigje dat der in adres yn deselde famylje is, en befêstigje dat de app binnen it berik sit dat jo ynsteld hawwe. As pakketten de deskriptor berikke mar der komt neat werom, ûndersykje dan protect() en de wearde fan it ûnderlizzende netwurk foardat jo wer in rûte oanreitsje. As de fiere kant misfoarme pakketten rapportearret, binne de kontrôlesom en de MTU de plakken om te sjen. Ien probe per laach sparret in middei fan rieden.