Llista permesa d'Android VpnService: per què les pàgines permeses encara es pengen
La teva llista permesa probablement està bé. Les pàgines es pengen per la resposta DNS, la taula de rutes, el sòcol del resolutor o l'MTU. Aquí tens l'ordre de comprovació.
Has afegit un domini a la llista permesa, la consulta arriba a la teva aplicació, el comparador retorna permès i la pàgina encara no es carrega mai. En aquest punt la majoria de la gent comença a reescriure el comparador i a afegir comparacions amb comodins. Per la meva experiència, el comparador sol ser correcte i la fallada és una capa més avall: en la resposta DNS que has sintetitzat, en la ruta que has instal·lat o en el sòcol que has fet servir per reenviar la consulta. La llista és la part fàcil; el camí del paquet és on es trenquen les llistes permeses.
El comparador poques vegades és el culpable
El primer que cal separar és bloquejat de trencat. Un nom bloquejat hauria de fallar de pressa i visiblement, perquè el navegador rep una resposta que diu que el nom no existeix i s'atura. Un nom trencat es penja, reintenta per IPv6, cau a un altre transport i et deixa amb un indicador que gira. Si veus un indicador que gira, la teva llista permesa probablement respon amb alguna cosa que el client no pot aprofitar.
El registre A buit és l'error clàssic. Retornar NOERROR amb zero respostes sembla una resposta vàlida, així que el resolutor stub l'accepta, el navegador torna a provar, prova AAAA, prova un altre resolutor i es rendeix molt més tard. Un codi de resposta 3, NXDOMAIN, amb la secció de pregunta repetida i l'identificador de transacció copiat, acaba la conversa immediatament. Fes-lo servir per a cada nom que rebutges deliberadament.
IPv6 mereix la mateixa decisió i no un valor per defecte. Si respons NXDOMAIN per a A i deixes passar AAAA, el client pot arribar al nom bloquejat per IPv6 i el filtre té una fuita. Algunes implementacions responen les consultes AAAA bloquejades amb una adreça de loopback perquè la connexió falli de seguida en comptes de caure a una alternativa. Tria una política, aplica-la als dos tipus de registre i registra els dos.
Una ruta que ho captura tot ho posseeix tot
Un disseny només de DNS no afegeix mai addRoute("0.0.0.0", 0), així que només les consultes entren a la interfície TUN i tota la resta continua fent servir la xarxa subjacent. Aquesta és la forma segura, i també explica per què algunes llistes permeses semblen funcionar al Wi-Fi i fallen a la xarxa mòbil.
En el moment que existeix una ruta per defecte, cada flux és teu. Un paquet TCP que arriba a la interfície i ni es reenvia ni es respon queda a la cua fins que el client esgota el temps, i no hi ha cap error per registrar perquè res no ha fallat. He vist algú passar-se una tarda en una llista permesa trencada que en realitat era un reenviador que faltava per al port 443. Registra el protocol i la destinació de cada paquet que decideixis descartar.
El sòcol del resolutor ha de sortir del túnel
El reenviament és on hi ha la següent trampa. Els resolutors de l'operador solen viure en una adreça privada que el túnel no pot assolir, així que la consulta que reenvies no va enlloc i l'aplicació informa d'un temps d'espera de lectura. Envia les consultes aprovades a un resolutor que sàpigues que és accessible, i passa primer aquest sòcol a VpnService.protect(). Un sòcol no protegit torna la consulta al teu propi túnel, on arriba una altra vegada a l'aplicació i fa voltes fins que salta el temps d'espera.
La fallada sembla idèntica a una caiguda de xarxa, i per això sobreviu tants anys als informes d'errors. Mantingues comptadors de consultes enviades i respostes rebudes: si el primer nombre puja i el segon queda a zero, estàs mirant el sòcol, no la llista.
La mida i les sumes de verificació fallen sense missatge
Els descarts silenciosos també vénen de la mida. Una resposta DNS amb un conjunt gran de respostes, o un intercanvi TCP amb opcions generoses, poden superar una MTU de camí que mai has fixat explícitament; el fragment desapareix més amunt i el client o bé reintenta més petit o bé deixa de reintentar. Fixar l'MTU de la interfície a 1280 és una elecció conservadora que sobreviu a la majoria de camins mòbils, i ser explícit és millor que heretar un valor per defecte que ningú no ha mesurat.
Si construeixes els paquets tu mateix, la suma de verificació és l'altre assassí silenciós. Una suma UDP calculada sobre una pseudo-capçalera que deixa fora la longitud UDP o el camp de protocol produeix un paquet que a la teva banda sembla ben format i que el receptor descarta sense cap rastre. Compara la teva pseudo-capçalera amb l'especificació camp per camp, i imprimeix la suma calculada per a un flux conegut mentre depures.
Què no farà un VpnService per tu
Val la pena conèixer dos límits abans de dissenyar-hi al voltant. Cap aplicació ordinària pot instal·lar un proxy o un fitxer PAC a tot el sistema fora del Wi-Fi, i aquesta part no ha canviat. El camí per aplicació sí: abans de l'API 29 VpnService.Builder no podia portar cap proxy, i a partir de l'API 29 setHttpProxy(ProxyInfo.buildPacProxy(uri)) lliura a la plataforma un script PAC per avaluar per a la xarxa VPN. Avalua les regles al teu propi codi quan apuntes a API més antigues o quan el model PAC no pot expressar la regla. UDP tampoc és gratuït: els navegadors només envien TCP a través d'un proxy SOCKS, i la majoria de clients SOCKS5 no implementen mai UDP ASSOCIATE, així que un disseny basat en proxy descarta o filtra UDP mentre el TCP sembla sa.
Aquest segon límit és la raó per la qual un protocol basat en UDP pot funcionar en una xarxa normal i fallar en el moment que la teva VPN es connecta. Si s'espera que el túnel porti UDP, el reenviador ha d'implementar el camí de reenviament per a UDP, no només el camí TCP amb un altre tipus de sòcol.
Comprova en aquest ordre
Recorre la llista en ordre i atura't a la primera etapa que falli, perquè tota comprovació posterior és soroll fins que l'anterior aguanti.
- Llista les rutes instal·lades i confirma si els paquets que no són DNS entren a la interfície TUN.
- Registra el nom de la consulta, la decisió i el codi de resposta per a un nom bloquejat i un d'aprovat.
- Confirma que el sòcol del resolutor està protegit i que el resolutor triat respon des de dins del túnel.
- Confirma l'MTU de la interfície i la suma de verificació d'una resposta que hagis construït a mà.
- Repeteix la mateixa pàgina al Wi-Fi i a la xarxa mòbil, perquè els resolutors de l'operador i l'MTU del camí difereixen.
Si els cinc es compleixen i la pàgina encara es penja, el següent sospitós és el reenviador mateix: compara una petició capturada amb una resposta capturada i busca un recompte de bytes que falta o un sòcol mig tancat. La referència de VpnService.Builder cobreix els contractes de ruta, DNS i MTU, i protect() és una crida separada de VpnService i no una opció del builder; una interfície connectada només vol dir que el primer contracte s'ha complert.