Jy het 'n domein op die toelatingslys gesit, die navraag bereik jou app, die vergelyker gee toegelaat terug, en die bladsy laai steeds nooit nie. Op daardie punt begin die meeste mense die vergelyker herskryf en wildcard-vergelykings byvoeg. Volgens my ervaring is die vergelyker gewoonlik reg, en die fout lê een laag later: in die DNS-antwoord wat jy gesintetiseer het, in die roete wat jy geïnstalleer het, of in die sok wat jy gebruik het om die navraag deur te stuur. Die lys is die maklike deel; die pakketpad is waar toelatingslyste breek.

Die vergelyker is selde die fout

Die eerste ding om te skei is geblokkeer van stukkend. 'n Geblokkeerde naam behoort vinnig en sigbaar te misluk, want die blaaier kry 'n antwoord wat sê die naam bestaan nie en stop. 'n Stukkende naam hang, probeer weer oor IPv6, val terug op 'n ander vervoer, en laat jou met 'n draaiende laaier. As jy 'n draaiende laaier sien, antwoord jou toelatingslys waarskynlik iets waarop die kliënt nie kan reageer nie.

'n Leë A-rekord is die klassieke fout. Om NOERROR met nul antwoorde terug te gee lyk soos 'n geldige antwoord, so die stub-resolver aanvaar dit, die blaaier probeer weer, probeer AAAA, probeer 'n ander resolver, en gee baie later op. 'n Antwoordkode van 3, NXDOMAIN, met die vraagafdeling weerspieël en die transaksie-ID gekopieer, beëindig die gesprek onmiddellik. Gebruik dit vir elke naam wat jy doelbewus weier.

IPv6 verdien dieselfde besluit eerder as 'n verstek. As jy NXDOMAIN vir A antwoord en AAAA deurlaat, kan die kliënt die geblokkeerde naam oor IPv6 bereik en die filter lek. Sommige implementerings antwoord geblokkeerde AAAA-navrae met 'n loopback-adres sodat die verbinding dadelik misluk eerder as om terug te val. Kies een beleid, pas dit op beide rekordtipes toe, en teken beide aan.

'n Roete wat alles vang, besit alles

'n Ontwerp met net DNS voeg nooit addRoute("0.0.0.0", 0) by nie, so net navrae gaan die TUN-koppelvlak binne en alles anders bly op die onderliggende netwerk. Dit is die veilige vorm, en dit verduidelik ook hoekom sommige toelatingslyste op Wi-Fi werk en op sellulêr faal.

Die oomblik wanneer 'n verstekroete bestaan, is elke vloei joune. 'n TCP-pakket wat by die koppelvlak aankom en nie deurgestuur of beantwoord word nie, sit in die tou totdat die kliënt uittel, en daar is geen fout om aan te teken nie want niks het gefaal nie. Ek het gesien hoe iemand 'n middag spandeer op 'n stukkende toelatingslys wat eintlik 'n ontbrekende deurstuurder vir poort 443 was. Teken die protokol en bestemming van elke pakket aan wat jy besluit om te laat val.

Die resolver-sok moet die tonnel verlaat

Deurstuur is waar die volgende lokval sit. Draer-resolvers woon dikwels op 'n private adres wat die tonnel nie kan bereik nie, so die navraag wat jy deurstuur, gaan nêrens heen en die app rapporteer 'n lees-tyduit. Stuur goedgekeurde navrae na 'n resolver waarvan jy weet dit is bereikbaar, en gee daardie sok eerste aan VpnService.protect(). 'n Onbeskermde sok stuur die navraag terug in jou eie tonnel, waar dit weer by die app aankom en loop totdat die tyduit afgaan.

Die fout lyk identies aan 'n netwerkonderbreking, en daarom oorleef dit so lank in foutverslae. Hou tellers vir navrae gestuur en antwoorde ontvang: as die eerste getal klim en die tweede op nul bly, kyk jy na die sok, nie die lys nie.

Grootte en kontrolesomme faal sonder 'n boodskap

Stille druppels kom ook van grootte. 'n DNS-antwoord met 'n groot antwoordversameling, of 'n TCP-handdruk met ruim opsies, kan 'n pad-MTU oorskry wat jy nooit eksplisiet gestel het nie; die fragment verdwyn stroomop en die kliënt probeer weer kleiner of hou op probeer. Om die koppelvlak-MTU op 1280 te stel is 'n konserwatiewe keuse wat die meeste sellulêre paaie oorleef, en om eksplisiet te wees is beter as om 'n verstek te erf wat niemand gemeet het nie.

As jy self pakkette bou, is die kontrolesom die ander stille moordenaar. 'n UDP-kontrolesom bereken oor 'n pseudo-opskrif wat die UDP-lengte of die protokolveld uitlaat, lewer 'n pakket wat aan jou kant goed gevorm lyk en deur die ontvanger sonder 'n spoor weggegooi word. Vergelyk jou pseudo-opskrif veld vir veld met die spesifikasie, en druk die berekende kontrolesom vir een bekende vloei terwyl jy ontfout.

Wat 'n VpnService nie vir jou sal doen nie

Twee beperkings is die moeite werd om te ken voordat jy rondom hulle ontwerp. Geen gewone app kan 'n stelselwye proxy of PAC-lêer buite Wi-Fi installeer nie, en daardie deel het nie verander nie. Die per-app-pad het wel: voor API 29 kon VpnService.Builder glad nie 'n proxy dra nie, en vanaf API 29 gee setHttpProxy(ProxyInfo.buildPacProxy(uri)) die platform 'n PAC-skrip om vir die VPN-netwerk te evalueer. Evalueer reëls in jou eie kode wanneer jy ouer API's teiken of wanneer die PAC-model die reël nie kan uitdruk nie. UDP is ook nie verniet nie: blaaie stuur slegs TCP deur 'n SOCKS-proxy, en die meeste SOCKS5-kliënte implementeer nooit UDP ASSOCIATE nie, so 'n proxy-gebaseerde ontwerp laat UDP val of lek terwyl TCP gesond lyk.

Daardie tweede beperking is die rede hoekom 'n UDP-gebaseerde protokol op 'n gewone netwerk kan werk en faal die oomblik wanneer jou VPN koppel. As die tonnel verwag word om UDP te dra, moet die deurstuurder die deurstuurpad daarvoor implementeer, nie net die TCP-pad met 'n ander soktipe nie.

Gaan in hierdie volgorde na

Werk die lys in volgorde deur en stop by die eerste stadium wat faal, want elke latere kontrole is geraas totdat die vroeëre een hou.

  1. Lys die geïnstalleerde roetes en bevestig of nie-DNS-pakkette die TUN-koppelvlak hoegenaamd binnegaan.
  2. Teken die navraagnaam, die besluit en die antwoordkode aan vir een geblokkeerde en een goedgekeurde naam.
  3. Bevestig dat die resolver-sok beskerm is en dat die gekose resolver van binne die tonnel antwoord.
  4. Bevestig die koppelvlak-MTU en die kontrolesom van een antwoord wat jy met die hand gebou het.
  5. Herhaal dieselfde bladsy op Wi-Fi en sellulêr, want draer-resolvers en pad-MTU verskil.

As al vyf hou en die bladsy hang steeds, is die volgende verdagte die deurstuurder self: vergelyk 'n vasgevangde navraag met 'n vasgevangde antwoord en soek na 'n ontbrekende greptelling of 'n halfgeslote sok. Die VpnService.Builder-verwysing dek die roete-, DNS- en MTU-kontrakte, en protect() is 'n aparte VpnService-oproep eerder as 'n bouer-opsie; 'n gekoppelde koppelvlak beteken net dat die eerste kontrak geslaag het.

Verwante artikels