Kāpēc Android VpnService uztver daļu trafika, nevis visu
Maršruti, DNS ieraksti un katras lietotnes tvērums nosaka, kuras paketes sasniedz tun ierīci, kāpēc vietējās ierīces pazūd un no kā atsakās veidotājs.
Nekas VpnService nepārtver trafiku pats no sevis. Tas lūdz sistēmai tun saskarni, nodod šai saskarnei adrešu un maršrutu kopu, un no tā brīža kodols kopē katru paketi, kas atbilst šiem maršrutiem, faila deskriptorā, ko lietotne var lasīt. Lietotnes kods nekad neredz paketes, kuras maršruti nav izvēlējušies, tāpēc tuneļa tvērums ir maršrutēšanas tabulas jautājums pirms tas kļūst par programmēšanas jautājumu. Tāpēc viena un tā pati pakalpojuma implementācija vienā telefonā var aprīt visu plūsmu, bet citā tikai daļu, un tāpēc maršruta pievienošana dažkārt salabo tuneli, kas izskatījās salūzis. Jūs iegūstat to, ko esat deklarējis, atskaitot visu, no kā veidotājs klusi atteicās.
Maršruti nosaka, kuras paketes ierodas
Builder.addRoute(prefix, prefixLength) instalē prefiksu VPN tīkla maršrutēšanas tabulā. Sistēma uzskata šo tīklu par noklusējumu tvēruma lietotnēm, tāpēc tā ieraksti tiek skatīti pirms fiziskā tīkla noklusējuma maršruta, un atbilstošs prefikss ir pietiekams, lai novirzītu plūsmu. Tāpēc maršruts 0.0.0.0/0 paņem IPv4 pilnībā, ieskaitot printeri, cast mērķi un maršrutētāja administrēšanas lapu.
Klienti, kas vēlas šo pārklājumu, neizdzēšot fizisko noklusējuma ierakstu, tā vietā izmanto pāri 0.0.0.0/1 un 128.0.0.0/1. Diviem konkrētākiem maršrutiem ir priekšroka pret noklusējuma maršrutu, kopā tie nosedz visu adrešu telpu, un paša telefona noklusējuma ieraksts paliek tabulā tām ligzdām, kas joprojām ir piesaistītas fiziskajam tīklam.
Adreses un DNS ieraksti nāk no tā paša veidotāja un atbild uz citu jautājumu. addAddress piešķir saskarnei adresi ar prefiksa garumu, un addDnsServer instalē atrisinātāju, ko tvēruma lietotnes jautās caur saskarni. Abas saimes var atrasties vienā saskarnē, tāpēc tikai IPv4 maršrutu kopa blakus IPv6 adresei ir konfigurācija, kas lasās pareizi un tomēr noplūst. Ja maršrutējat saimi, kurā saskarnei nav adreses, kodolam nav avota adreses šīm paketēm, un tās nekad neparādās deskriptorā.
Ko atgriež establish()
establish() atgriež ParcelFileDescriptor, vai null, kad lietotne nav autorizēta. Null ir piekrišanas stāvoklis, nevis tīkla kļūda: VpnService.prepare() jau ir jābūt atgriezušam null, vai lietotājam pirms izsaukuma jābūt apstiprinājušam sistēmas dialogu. Piekrišanu var atsaukt pakalpojuma darbības laikā, un saskarne aizveras zem jūsu kājām bez jebkāda atzvanījuma jūsu lasīšanas cilpā.
Deskriptors nebloķē, ja vien nenorādāt citādi, tāpēc lasīšana atgriežas uzreiz bez datiem, nevis novieto pavedienu gaidīšanā. Cilpa, kas rakstīta bloķējošai ligzdai, sadedzina vienu kodolu, un cilpa, kas tukšu lasīšanu uzskata par nāvējošu, tukšā sekundē saplēš tuneli. Builder.setBlocking(true) maina šo uzvedību, un cena ir pavediens, kas gaida lasīšanas iekšienē.
Maršruta un adreses argumenti tiek validēti kā LinkAddress vērtības, un multicast galamērķi, piemēram, 224.0.0.0/4, tiek noraidīti uzreiz. Punkts-punktam tun saskarnei arī nav apraides domēna, tāpēc multicast atklāšanai caur to vajadzīgs cits dizains, nevis vēl viens maršruts. Atsauce VpnService.Builder ir saraksts, kas jāpārbauda, pirms secināt, ka izsaukums tika ignorēts.
Tvērums katrā lietotnē sašaurina kopu, nevis tuneli
No API 21 veidotājs pieņem addAllowedApplication un addDisallowedApplication, un abi saraksti vienā veidotājā viens otru izslēdz. Atļauto saraksts padara tuneli eksistējošu šīm paketēm, kamēr viss pārējais saglabā fizisko tīklu; aizliegto saraksts uztver visu, izņemot nosauktās paketes, ko klients piedāvā kā sadalītu tunelēšanu. Pirms API 21 platformas mehānisma vispār nav, un uzvedība katrā lietotnē nāca no trešo pušu klientiem, kas filtrēja pēc UID savā pāradresētājā. Šī atšķirība ir svarīga atkļūdošanā, jo lietotnes tunelis ar vienas paketes atļauto sarakstu gandrīz neveido trafiku, un tā ir pareiza uzvedība, nevis salūzis maršruts.
Lai kāds būtu tvērums, ligzdai, ko jūsu lietotne atver uz VPN serveri, nav jāiet cauri tunelim, ko tā būvē. VpnService.protect(socket) piesaista šo ligzdu apakšējam tīklam, lai tās paketes izlaistu tun ierīci. Ja izlaižat izsaukumu, rokas spiedienu aprīs saskarne, kurai tas bija jāpaceļ.
VpnService.setUnderlyingNetworks noslēdz loku, pasakot sistēmai, kurš fiziskais tīkls nes tuneli. Šī vērtība nosaka, kā VPN ziņo par savienojamību citām lietotnēm, un null vai novecojusi vērtība ir ierasts iemesls pievienotam tunelim, ko pārējais telefons uzskata par bezsaistē. Atjauniniet to, kad mainās apakšējais tīkls, ne tikai palaišanas laikā.
Kontrolsummas un MTU: kur pareizs maršruts tomēr neizdodas
Kad paketes ir ieradušās, divas detaļas paketes līmenī izšķir, vai kaut kas darbojas no gala līdz galam. Pirmā ir avota adrese: ar vairākām saskarnes adresēm kodols var izsūtīt paketes, kas nes pirmo, tāpēc pāradresētājam, kas pārraksta galvenes, jāizlabo adrese un to aptverošā kontrolsumma.
Otrā ir kontrolsummas tvērums. Kad lietotne pati būvē TCP vai UDP paketes, kontrolsumma aptver pseidogalveni ar avota adresi, galamērķa adresi, protokola numuru un transporta garumu, un jebkuras no tām izlaišana dod paketes, kas ierodas un tiek izmestas. Šī kļūme izskatās kā taimauts pēc atbildes, kas nekad nenāk, un tas lielāko daļu cilvēku sūta atpakaļ pie maršrutiem. setMtu fiksē saskarnes MTU, un katra lasīšana atgriež tieši vienu pilnu IP paketi, tāpēc baitu straumei rakstīts buferis sadalīs jūsu analīzi, nevis paketi.
Pārbaudes gājiens, kas atdala slāņus
Lai atrastu, kur tvērums nogāja greizi, pārbaudiet slāņus pēc kārtas. Pajautājiet ierīcei, kādus maršrutus VPN tīkls patiešām tur, pēc tam pārbaudiet, vai plūsma uz zināmu adresi parādās kā lasīšana deskriptorā, pēc tam pārbaudiet, vai pakete, ko izsūta jūsu pāradresētājs, ir labi veidota. Maršruta problēma deskriptorā neko nerāda, savukārt kontrolsummas problēma rāda paketi, kas ierodas un pazūd.
Ja deskriptoru nesasniedz nekas, aizdomās turamais ir maršrutu kopa, nevis lasītājs: apstipriniet prefiksus, apstipriniet, ka tajā pašā saimē ir adrese, un apstipriniet, ka lietotne ir jūsu noteiktā tvēruma iekšienē. Ja paketes sasniedz deskriptoru, bet nekas neatgriežas, pārbaudiet protect() un apakšējā tīkla vērtību, pirms atkal aiztiecat maršrutu. Ja tālā puse ziņo par bojātām paketēm, kontrolsumma un MTU ir vietas, kur skatīties. Viens pārbaudījums uz slāni ietaupa pēcpusdienu minējumu.