Android VpnService-titeliste: wêrom tastean side noch altyd hingje
Dyn titeliste is wierskynlik yn oarder. Seiten hingje fanwegen it DNS-antwurd, de rûtetabel, de resolver-socket of de MTU. Hjir is de folchoarder fan kontrôle.
Jo hawwe in domein op de titeliste set, de fraach berikt jo app, de matcher jout tastean werom, en de side laadt noch altyd nea. Op dat punt begjinne de measte minsken de matcher te werôverjen en wildcard-fergelikingen ta te foegjen. Neffens myn ûnderfining is de matcher meastentiids korrekt, en leit de flater ien laach leger: yn it DNS-antwurd dat jo syntetisearre hawwe, yn 'e rûte dy't jo ynstallearre hawwe, of yn 'e socket dy't jo brûkten om de fraach troch te stjoeren. De list is it maklike part; it pakketpaad is wêr't titelisten brekke.
De matcher is selden de skuldige
It earste dat skieden wurde moat is blokkearre fan stikken. In blokkearre namme heart fluch en sichtber te mislearjen, want de browser krijt in antwurd dat de namme net bestiet en stoppet. In stikken namme hinget, besiket opnij oer IPv6, falt werom op in oar ferfier, en lit jo efter mei in draaiende yndikator. As jo in draaiende yndikator sjogge, antwurdet jo titeliste wierskynlik mei iets dêr't de klant neat mei kin.
In leech A-record is de klassike flater. NOERROR weromjaan mei nul antwurden liket in jildich antwurd, dus de stub-resolver akseptearret it, de browser besiket opnij, besiket AAAA, besiket in oare resolver en jout folle letter op. In antwurdkoade 3, NXDOMAIN, mei de fraachseksje werhelle en de transaksje-ID kopiearre, einiget it petear daliks. Brûk it foar elke namme dy't jo bewust wegerje.
IPv6 fertsjinnet deselde beslissing yn plak fan in standertwearde. As jo NXDOMAIN antwurdzje foar A en AAAA trochlitte, kin de klant de blokkearre namme oer IPv6 berikke en lekt it filter. Guon ymplemintaasjes antwurdzje op blokkearre AAAA-fragen mei in loopback-adres sadat de ferbining daliks mislearret yn plak fan werom te fallen. Kies ien belied, pas it ta op beide recordtypen, en log beide.
In rûte dy't alles fangt, besit alles
In ûntwerp mei allinnich DNS foeget nea addRoute("0.0.0.0", 0) ta, dus allinnich fragen komme de TUN-ynterface yn en al it oare bliuwt it ûnderlizzende netwurk brûken. Dat is de feilige foarm, en it ferklearret ek wêrom't guon titelisten op Wi-Fi lykje te wurkjen en op it mobile netwurk mislearje.
It momint dat der in standertrûte bestiet, is elke stream fan jo. In TCP-pakket dat by de ynterface oankomt en noch trochstjoerd noch beantwurde wurdt, sit yn 'e wachtrige oant de klant in time-out krijt, en der is gjin flater om te loggen om't der neat mislearre. Ik seach immen in middei trochbringe op in stikken titeliste dy't eins in ûntbrekkende trochstjoerder foar poarte 443 wie. Log it protokol en de bestemming fan elk pakket dat jo beslute te fallen.
De resolver-socket moat de tunnel ferlitte
Trochstjoeren is wêr't de folgjende falstrik sit. Resolvers fan 'e provider wenje faak op in privee-adres dat de tunnel net berikke kin, dus de fraach dy't jo trochstjoere giet nearne hinne en de app rapportearret in lês-time-out. Stjoer goedkarde fragen nei in resolver dêr't jo fan witte dat er berikber is, en jou dy socket earst oan VpnService.protect(). In ûnbeskerme socket stjoert de fraach werom yn jo eigen tunnel, wêr't er wer by de app komt en rûnset oant de time-out ôfgiet.
De flater liket identyk oan in netwurkûnderbrekking, en dêrom oerlibbet er sa lang yn flaterrapporten. Hâld tellers by foar stjoerde fragen en ûntfongen antwurden: as it earste getal klimt en it twadde op nul bliuwt, sjogge jo nei de socket, net nei de list.
Grutte en kontrôlesommen mislearje sûnder berjocht
Stille drippen komme ek fan grutte. In DNS-antwurd mei in grutte antwurdset, of in TCP-hânskodding mei romme opsjes, kin in paad-MTU oergean dy't jo nea eksplisyt ynsteld hawwe; it fragmint ferdwynt streamop en de klant besiket óf lytser opnij óf hâldt op mei besykjen. It ynstellen fan 'e ynterface-MTU op 1280 is in konservative kar dy't de measte mobile paden oerlibbet, en eksplisyt wêze is better as in standert ervje dy't nimmen metten hat.
As jo sels pakketten bouwe, is de kontrôlesom de oare stille moardner. In UDP-kontrôlesom berekkene oer in pseudokop dy't de UDP-lange of it protokolfjild weilitten hat, leveret in pakket dat by jo goed foarme liket en troch de ûntfanger sûnder spoar fuortsmiten wurdt. Fergelykje jo pseudokop mei de spesifikaasje fjild foar fjild, en printsje de berekkene kontrôlesom foar ien bekend stream wylst jo debugge.
Wat in VpnService net foar jo docht
Twa grinzen binne it wurdich om te witten foardat jo deromhinne ûntwerpe. Gjin gewoane app kin in systeembreed proxy of PAC-bestân bûten Wi-Fi ynstallearje, en dat part is net feroare. It paad per app wol: foar API 29 koe VpnService.Builder hielendal gjin proxy drage, en fan API 29 ôf jout setHttpProxy(ProxyInfo.buildPacProxy(uri)) it platfoarm in PAC-skript om te evaluearjen foar it VPN-netwurk. Evaluearje regels yn jo eigen koade as jo âldere API's rjochtsje of as it PAC-model de regel net útdrukke kin. UDP is ek net fergees: browsers stjoere allinnich TCP fia in SOCKS-proxy, en de measte SOCKS5-klanten ymplemintearje nea UDP ASSOCIATE, dus in ûntwerp op basis fan proxy lit UDP falle of lekke wylst TCP sûn liket.
Dy twadde grins is de reden dat in protokol op basis fan UDP op in gewoan netwurk wurkje kin en mislearret op it momint dat jo VPN ferbynt. As fan 'e tunnel ferwachte wurdt dat er UDP draacht, moat de trochstjoerder it trochstjoerpaad dêrfoar ymplemintearje, net allinnich it TCP-paad mei in oar sockettype.
Kontrolearje yn dizze folchoarder
Wurkje de list yn folchoarder ôf en stop by de earste stap dy't mislearret, want elke lettere kontrôle is lûd oant de eardere hâldt.
- Lis de ynstallearre rûtes op en befestigje oft pakketten dy't gjin DNS binne de TUN-ynterface überhaupt ynkomme.
- Log de fraachnamme, de beslissing en de antwurdkoade foar ien blokkearre en ien goedkard namme.
- Befestigje dat de resolver-socket beskerme is en dat de keazen resolver fan binnen de tunnel antwurdet.
- Befestigje de ynterface-MTU en de kontrôlesom fan ien antwurd dat jo mei de hân boud hawwe.
- Werhelje deselde side op Wi-Fi en op it mobile netwurk, om't resolvers fan 'e provider en paad-MTU ferskille.
As alle fiif hâlde en de side hinget noch, is de folgjende fertochte de trochstjoerder sels: fergelykje in fêstleine oanfraach mei in fêstlein antwurd en sykje nei in ûntbrekkend byte-oantal of in heal sletten socket. De VpnService.Builder-referinsje behannelet de kontrakten foar rûte, DNS en MTU, en protect() is in aparte VpnService-oprop en gjin builder-opsje; in ferbûne ynterface betsjut allinnich dat it earste kontrakt foldien is.