Android VpnService verbënnt, awer keng Pakete erreechen d'Netzwierk
Tunnel steet a Säiten nach ëmmer feelen: kontrolléiert de Liesmodus, de Socket-Schutz, d'TCP-Ënnerstëtzung an d'Routelëscht ier Dir dem VPN-Server d'Schold gitt.
Den Tunnel geet erop, de Schlëssel-Ikon erschéngt, an all Ufro am Browser leeft nach ëmmer of. An enger VpnService-App heescht dës Kombinatioun meeschtens, datt d'Lies-Schleef lieft an d'Halschent vum Ausgang futti ass, net datt de Server de Handshake ofgeleent huet. Android huet d'Interface scho gemaach, den Traffic vun der App dran geplënnert an Ärem Prozess en Dateideskriptor ginn. Alles nom Descriptor ass Äre Code, an ee fehlenden Opruff duerch fir de ganze Stroum ze verschlécken.
Wat de System gëtt an wat net
establish() gëtt en ParcelFileDescriptor fir eng tun-Interface zréck. De System schreift erausgehend IP-Paketen dran an erwaart, datt Äre Prozess se liest, entscheet wou se higinn an se iwwer en normale Socket schéckt. Drënner gëtt et keng Kernel-Weiderleitung, also wann keen liest, gi Pakete verworf an d'Zieler vun der Interface beweege sech ni.
Fänkt mat zielen un amplaz ze roden. Erhéicht en Ziler bei all gelungener Liesung an loggt d'Destinatioun an de Protokoll vun den éischte Paketen. Wann den Ziler op Null bleift, während Traffic generéiert gëtt, sëtzt de Feeler uewen iwwert Ärem Weiderleitungscode, wat d'Sich op d'Builder-Konfiguratioun an de Liesmodus agrenzt. Wann den Ziler sech beweegt an de Browser nach ëmmer feelt, ass de Feeler am Send- oder am Retourwee.
Blockéierend Liesung entscheet, ob d'Schleef sech beweegt
setBlocking(true) setzt den Descriptor an de blockéierende Modus an et gëtt et zënter API 21. Op eelere Versioune ass d'Léisung en klengen JNI-Helfer, deen O_NONBLOCK mat fcntl um rohen Descriptor läscht. De Modus ass wichteg, well en entscheet, wat eng Liesung ouni waartende Paket däerf.
Am net-blockéierende Modus kënnt déi Liesung direkt mat engem negative Wäert zréck, an eng Schleef, déi d'Resultat ignoréiert, dréint en Kär ouni Traffic ze beweegen. Am blockéierende Modus waart d'Liesung, wat en Weiderleitungs-Thread wëll, awer den Thread kann dann net méi ënnerbrach ginn. Den Descriptor zoumaachen ass dee gestäipte Wee fir d'Liesung feelen ze loossen, sou datt d'Schleef erauskann. De Prozess ëmzebréngen oder den Thread z'ënnerbriechen kann de nächsten Start mat engem Descriptor hannerloossen, deen net méi zur Interface passt.
Liest ee Paket pro Opruff an en Puffer an der Gréisst vun der MTU vun der Interface, a behandelt Null oder en negativen Retour als Feeler, net als eidele Paket.
protect() virun der éischter Sendung, net duerno
All Socket, deen en agepakte Paket dréit, muss als éischt geschützt ginn. En ongeschützte Socket befollegt déi selwecht Routing-Regelen, déi Dir just installéiert hutt, also ginn seng Paketen zréck an den Tunnel an Är eege Lies-Schleef hëlt se erëm op. Dann leet den Tunnel säin eegenen Ausgang onendlech weider, an vun dobaussen gesäit et aus wéi eng Verbindung, déi sech opmaacht an ni äntwert.
D'Reiefolleg ass protect, dann connect oder bind, dann send. protect no connect opzeruffe kann déi fréier Routen-Entscheedung stoen loossen, also benotzt de Socket weider de falsche Wee, och wann den Opruff true zréckginn huet. Kontrolléiert de Boolean, deen en zréckgëtt, a feelt haart wann en false ass, amplaz an eng Sendung ze goen, déi net ka funktionéieren.
E Berechtegungsfeeler vu sendto op engem Socket, deen ni protect() beréiert huet, ass déi üblech Ënnerschrëft vun dësem Feeler.
D'UDP-Beispill dréit keen HTTPS
D'Weiderleitungs-Beispill, dat déi meescht Tutorials kopéieren, behandelt UDP an soss näischt. TCP brauch en Handshake, Sequenznummeren, Bestätegungen an Neisendung, an eng Schleef, déi Belaaschtung tëscht engem tun-Descriptor an engem Socket kopéiert, bitt dovun näischt. Dofir kann eng UDP-DNS-Ufro duerchkommen, während all HTTPS-Ufro stoppt. Entweder bedreift en TCP-Stack am Benotzerraum oder gitt d'Verbindungen un e lokale Proxy, deen TCP um Apparat ofschléisst an de Stroum weiderleet.
Test d'Deelung ier Dir eppes ëmschreift: schéckt eng UDP-Ufro an opmaacht eng TCP-Verbindung zum selwechten Host. Wann den UDP-Wee funktionéiert an den TCP-Wee beim éischten SYN hänkt, ass de Weiderleitungscode de Problem an net de Server. Dee eenzege Verglach spuert vill Zäit, déi mat Servers-Logs verbruecht gëtt, déi näischt Nëtzlech enthalen.
D'Routelëscht an d'App-Filter begrenzen wat Dir gesitt
addAddress, addRoute an addDns definéieren, wat de System an den Tunnel schéckt. En Zil baussent der Routelëscht erreecht Ären Descriptor ni, also kann egal wéi vill Weiderleitungslogik et net flécken. Loggt d'Builder-Opruff, déi Dir maacht, a vergläicht se mat den Adressen, déi d'App wierklech wëll erreechen.
D'Auswiel pro App huet hir eege Grenz: addAllowedApplication an addDisallowedApplication brauchen API 21, an op eelere Versioune feelen déi Methoden einfach. En Design, deen no Paket filtert, kann do guer net lafen.
Nei Opbau hannerléisst al Descriptoren
En neien Opruff vun establish() gëtt en neien Descriptor zréck a schléisst déi viregt Interface. Den alen Descriptor ass elo ongülteg, also kritt en Thread, deen nach drop blockéiert, e Feeler, an d'Sockelen, déi fir den ale Wee gemaach goufen, mussen eventuell ersat ginn. onRevoke ass de Callback fir en Tunnel, deen de Benotzer oder de System ewechgeholl huet. D'Liewenszyklus bei engem Besëtzer ze halen, deen de Lieser virum Neiopbau stoppt, verhënnert déi meescht verbonnen-awer-doud-Zoustänn.
Liest all Feeler no dem Schrëtt, zu deem en gehéiert. En Ënnerbrieche vun der Verbindung vu recvfrom heescht, datt déi wäit Säit zougemaach huet, während Äre Code nach gelies huet. E Feeler iwwer eng falsch Adress weist op Header-Parsing oder en Offset-Fehler, net op d'Netzwierk.
Aarbechts-Reiefolleg: blockéierende Modus un, ee Paket pro Liesung, Header geparst, Socket geschützt, Belaaschtung geschéckt, propper Zoumaache bei der Iwwergab an eng Routelëscht, déi d'Zil deckt.