Kial Android VpnService kaptas iom da trafiko kaj ne ĉion
Itineroj, DNS-rikordoj kaj la amplekso laŭ aplikaĵo decidas, kiuj pakaĵoj atingas la tun-aparaton, kial lokaj aparatoj malaperas, kaj kion la konstruilo rifuzas.
Nenio en VpnService kaptas trafikon per si mem. Ĝi petas de la sistemo tun-interfacon, donas al tiu interfaco aron da adresoj kaj itineroj, kaj de tiu momento la kerno kopias ĉiun pakaĵon kongruan kun tiuj itineroj en dosierpriskribilon, kiun la aplikaĵo povas legi. La kodo de la aplikaĵo neniam vidas la pakaĵojn, kiujn la itineroj ne elektis, do la amplekso de tunelo estas demando pri itinertabelo antaŭ ol ĝi estas demando pri programado. Tial la sama serva efektivigo povas engluti ĉiun fluon sur unu telefono kaj nur pecon sur alia, kaj tial aldoni itineron foje riparas tunelon, kiu ŝajnis rompita. Kion vi ricevas, estas kion vi deklaris, minus ĉio, kion la konstruilo silente rifuzis.
Itineroj decidas, kiuj pakaĵoj alvenas
Builder.addRoute(prefix, prefixLength) instalas prefikson en la itinertabelon de la VPN-reto. La sistemo traktas tiun reton kiel defaŭltan por la aplikaĵoj en la amplekso, do ĝiaj rikordoj estas konsultataj antaŭ la defaŭlta itinero de la fizika reto, kaj kongrua prefikso sufiĉas por deturni fluon. Tial itinero por 0.0.0.0/0 prenas IPv4 tute, inkluzive la printilon, la cast-celon kaj la administran paĝon de la enkursigilo.
Klientoj, kiuj volas tiun kovron sen forigi la fizikan defaŭltan rikordon, uzas anstataŭe la paron 0.0.0.0/1 kaj 128.0.0.0/1. Du pli specifaj itineroj venkas defaŭltan itineron, kune ili kovras la tutan adresspacon, kaj la propra defaŭlta rikordo de la telefono restas en la tabelo por la ingoj ankoraŭ ligitaj al la fizika reto.
Adresoj kaj DNS-rikordoj venas de la sama konstruilo kaj respondas al alia demando. addAddress donas al la interfaco adreson kun prefiksa longo, kaj addDnsServer instalas solvilon, kiun aplikaĵoj en la amplekso demandos tra la interfaco. Ambaŭ familioj povas sidi sur unu interfaco, do itinara aro nur por IPv4 apud IPv6-adreso estas agordo, kiu legiĝas ĝuste kaj tamen likas. Se vi itineras familion, en kiu la interfaco ne havas adreson, la kerno ne havas fontadreson por tiuj pakaĵoj kaj ili neniam aperas ĉe la priskribilo.
Kion establish() redonas
establish() redonas ParcelFileDescriptor, aŭ null kiam la aplikaĵo ne estas rajtigita. Null estas stato de konsento, ne reta eraro: VpnService.prepare() devis jam redoni null, aŭ la uzanto devis aprobi la sistemdialogon antaŭ la voko. Konsento povas esti revokita dum la servo funkcias, kaj la interfaco fermiĝas sub vi sen iu ajn retrovoko en vian legan buklon.
La priskribilo ne blokas krom se vi diras alie, do legado tuj redonas sen datumoj anstataŭ parki la fadenon. Buklo skribita por blokanta ingo bruligas unu kernon, kaj buklo, kiu traktas malplenan legadon kiel mortal, disŝiras la tunelon dum senokupa sekundo. Builder.setBlocking(true) ŝanĝas tiun konduton, kaj la prezo estas fadeno, kiu atendas ene de la legado.
Itineraj kaj adresaj argumentoj validiĝas kiel valoroj LinkAddress, kaj multicast-celoj kiel 224.0.0.0/4 estas tute rifuzataj. Punkto-al-punkta tun-interfaco ankaŭ ne havas dissendan domajnon, do multicast-malkovro tra ĝi bezonas alian dezajnon anstataŭ ankoraŭ unu itineron. La VpnService.Builder-referenco estas la listo kontrolenda antaŭ ol konkludi, ke voko estis ignorita.
La amplekso laŭ aplikaĵo mallarĝigas la aron, ne la tunelon
De API 21 la konstruilo akceptas addAllowedApplication kaj addDisallowedApplication, kaj la du listoj estas reciproke ekskluzivaj ene de unu konstruilo. Permesa listo igas la tunelon ekzisti por tiuj pakaĵoj, dum ĉio alia konservas la fizikan reton; malpermesa listo kaptas ĉion krom la nomitaj pakaĵoj, kion kliento proponas kiel dividitan tuneladon. Antaŭ API 21 entute ne ekzistas platforma mekanismo, kaj konduto laŭ aplikaĵo venis de triapartaj klientoj, kiuj filtris laŭ UID ene de sia propra plusendilo. La distingo gravas dum sencimigado, ĉar aplikaĵa tunelo kun permesa listo de unu pakaĵo preskaŭ ne produktas trafikon, kaj tio estas ĝusta konduto, ne rompita itinero.
Kia ajn estas la amplekso, la ingo, kiun via aplikaĵo malfermas al la VPN-servilo, ne rajtas vojaĝi tra la tunelo, kiun ĝi konstruas. VpnService.protect(socket) ligas tiun ingon al la suba reto tiel, ke ĝiaj pakaĵoj preterpasas la tun-aparaton. Se vi preterlasas la vokon, la manpremo estas englutita de la interfaco, kiu devis ĝin levi.
VpnService.setUnderlyingNetworks fermas la buklon dirante al la sistemo, kiu fizika reto portas la tunelon. Tiu valoro regas, kiel la VPN raportas konektecon al aliaj aplikaĵoj, kaj null aŭ kaduka valoro estas rutina kaŭzo de konektita tunelo, kiun la resto de la telefono traktas kiel eksterrete. Ĝisdatigu ĝin, kiam la suba reto ŝanĝiĝas, ne nur ĉe lanĉo.
Kontrolsumoj kaj MTU: kie ĝusta itinero tamen fiaskas
Post kiam pakaĵoj alvenas, du detaloj ĉe la pakaĵa nivelo decidas, ĉu io funkcias de fino al fino. La unua estas la fontadreso: kun pluraj interfacaj adresoj la kerno povas elsendi pakaĵojn portantajn la unuan, do plusendilo, kiu reskribas kapliniojn, devas ripari la adreson kaj la kontrolsumon, kiu kovras ĝin.
La dua estas la amplekso de la kontrolsumo. Kiam la aplikaĵo mem konstruas TCP- aŭ UDP-pakaĵojn, la kontrolsumo kovras pseŭdokaplinion kun la fontadreso, la celadreso, la protokolnombro kaj la transporta longo, kaj preterlasi iun ajn el tiuj donas pakaĵojn, kiuj alvenas kaj estas forĵetitaj. Tiu fiasko aspektas kiel tempolimo post respondo, kiu neniam venas, kio resendas la plej multajn al la itineroj. setMtu fiksas la MTU de la interfaco, kaj ĉiu legado redonas precize unu kompletan IP-pakaĵon, do bufro skribita por bajta fluo fragmentigos vian analizadon, ne la pakaĵon.
Kontrola trapaso, kiu apartigas la tavolojn
Por trovi, kie la amplekso eraris, testu la tavolojn laŭ ordo. Demandu la aparaton, kiujn itinerojn la VPN-reto efektive tenas, poste kontrolu, ĉu fluo al konata adreso aperas kiel legado ĉe la priskribilo, poste kontrolu, ĉu la pakaĵo, kiun via plusendilo elsendas, estas bone formita. Itinera problemo montras nenion ĉe la priskribilo, dum kontrolsuma problemo montras pakaĵon, kiu alvenas kaj malaperas.
Se nenio atingas la priskribilon, la itinara aro estas la suspektato, ne la leganto: konfirmu la prefiksojn, konfirmu, ke ekzistas adreso en la sama familio, kaj konfirmu, ke la aplikaĵo estas ene de la amplekso, kiun vi agordis. Se pakaĵoj atingas la priskribilon sed nenio revenas, ekzamenu protect() kaj la valoron de la suba reto antaŭ ol denove tuŝi itineron. Se la fora flanko raportas misformitajn pakaĵojn, la kontrolsumo kaj la MTU estas la lokoj por rigardi. Unu sondado por tavolo ŝparas posttagmezon da divenado.