Breve historia de cómo IPv6 casi me deja sin comer
Internet es de esas cosas que son maravillosas mientras funcionan o el peor infierno cuando no lo hacen. Si alguna vez sufriste esto en tus dias de home office acercate a conocer algunas herramientas que te pueden interesar...
Esta es la historia de los pasos que seguí para debuggear unos problemas muy raros en la red de mi casa. Espero que al leerla aprendan algo que les sirva en esta época de home office y aislamiento.
Hace poco me mudé, por lo que mi proveedor de internet (ISP) mudó a su vez la conexión de internet. Durante la instalación me ofrecieron actualizar el modem/router que venía usando desde hacía años. Accedí, a pesar de que en realidad no tenía ningún problema con el mismo. Qué mala decisión que tomé…
Terminó la instalación y corrí pruebas básicas:
- Test de velocidad con fast.com y dslreports.com,
- Ping a los servidores DNS de Google y/o Cloudflare para medir la latencia y estabilidad de la conexión,
- Ping al load balancer de Steam en Brasil…. si, quiero jugar jueguitos sin problemas.
Todo perfecto, así que firme el papel y me despedí.
Acababa de mudarme así que esa noche no iba a cocinar, entonces busqué una app en mi celular para pedir comida. Por alguna razón, no pasaba de la pantalla inicial donde se ve el logo. Primero pensé que se había caído ese servicio, pero probé con otra app y pasó lo mismo. Se me ocurrió probar con el servicio 4G de mi celular, y la aplicación cargaba muy rápidamente. Claramente había un problema en mi casa.
En mi experiencia, intentar reportar esto a soporte técnico es difícil, porque el proceso normal de reiniciar el modem y verificar el enlace no es suficiente. Así que me propuse primero debuggear el problema y recién después reportarlo.
Primer teoría: ¿Será que el DNS de mi ISP no está resolviendo la dirección IP?
Pruebas que hice:
- Abrir la web de la app desde chrome en el celular: Funcionaba bien ✅
- Abrir la web de la app desde mi pc: Funcionaba bien ✅
- Mirar si alguien se quejaba en twitter: Ninguna queja ✅
- Probar resolver el nombre de dominio usando otro servidor DNS: Funcionaba bien ✅
Esto último se puede hacer con el comando “dig” (que viene incluido en algunos sistemas operativos y hay que instalarlo en otros) para solicitarle una resolución de nombres a un DNS puntual.
Ejemplo donde resolvemos el dominio de google usando los DNS de Cloudflare:
dig @1.1.1.1 www.google.com.ar
; <<>> DiG 9.10.6 <<>> @1.1.1.1 www.google.com.ar
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 36721
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;www.google.com.ar. IN A
;; ANSWER SECTION:
www.google.com.ar. 260 IN A 172.217.172.99
;; Query time: 11 msec
;; SERVER: 1.1.1.1#53(1.1.1.1)
;; WHEN: Wed Jan 20 14:28:17 -03 2021
;; MSG SIZE rcvd: 62
Podemos ver que no hubo error (status: NOERROR) y además nos devuelve una IP (172.217.172.99)
Probé con varios DNS y todos funcionaron sin problema (incluido el DNS por defecto que es el de mi ISP).
Conclusión: No es un problema de DNS.
Segunda teoría: Problema interno de mi wifi (porque tengo mi propio access point)
Eliminemos posibles puntos de falla:
- Desconecté todo lo que no sea el modem/router del ISP
- Desconecté y conecté el modem de la alimentación
- Reinicié el celular
- Conecté el celular a la red wifi del modem/router
- Probé la app
Probé esto con dos celulares diferentes, en ningún caso logre que la app funcione.
Conclusión: El problema no está en mis equipos.
Tercer teoría: Quizás la app usa otro dominio que no es el de la versión web
¿Cómo puedo saber qué requests está haciendo la app?. ¿Puedo inspeccionar ese tráfico?
Primer prueba: Inspeccionar el tráfico de la app remotamente con Wireshark
Para esto hacen falta dos cosas:
- Una app en el celular que intercepte el tráfico de red
- Una PC en la misma red con Wireshark para capturar estas trazas y poder analizarlas
A grandes rasgos los pasos son:
- Instalar PCAP Remote para Android (https://play.google.com/store/apps/details?id=com.egorovandreyrm.pcapremote&hl=es_AR&gl=US)
- Instalar Wireshark en una PC: https://www.wireshark.org/
- Usar alguna guía de cómo configurar Wireshark para conectarse a un servidor SSH remoto para capturar los paquetes. Algo como esto: https://www.youtube.com/watch?v=YodIWG0N8_0
- Activar el monitoreo de UNA app puntual dentro de PCAP Remote (eligiendo la app que queremos interceptar)
- Abrir la app en el celular y mirar en Wireshark (en la PC) que es lo que está pasando
Una vez que hacen eso, en Wireshark van a ver algo como esto:
Como el tráfico es HTTPS, y por ende está encriptado, no puedo mirar los detalles de los paquetes que están dando timeout o respondiendo lento. Me di cuenta que esto no me iba a servir. Necesitaba poder inspeccionar el tráfico seguro 🕵🏻♂️
Segunda prueba: Metámonos un poco más adentro
Para poder inspeccionar tráfico seguro hay que usar una técnica llamada Man In The Middle (MITM). Esto implica ponerse entre el cliente (que manda cosas encriptadas) y el servidor real (que va a desencriptar las cosas). Entonces el MITM desencripta y luego re-encripta el tráfico.
Como el cliente quiere estar seguro que le habla al servidor real, va a validar el certificado que ese servidor le provea, por lo tanto no podemos simplemente poner un MITM sin que el cliente se entere. Tenemos que decirle al cliente que el certificado que emitimos en el servidor MITM es “de confianza”. Como no estoy hackeando a nadie sino que es mi propia red, tengo acceso al dispositivo cliente.
En Android se pueden instalar certificados creados por uno mismo y decirle al sistema operativo que son “de confianza”. De hecho, la app PCAP Remote puede hacer eso por nosotros si se lo pedimos. Así que le pedí a la app que instale un certificado especial para poder desencriptar el tráfico HTTPS desde las settings.
⚠️ ATENCIÓN ⚠️ Aviso muy importante: En el instante en que instalamos ese certificado en nuestro celular no solo le estamos dando permiso a PCAP Remote a desencriptar el tráfico HTTPS de la app que queramos inspeccionar, sino que, en esencia, estamos dejando que cualquier servidor que quiera ejecutar un MITM usando ese certificado lo pueda hacer. Esto nos deja expuestos a problemas de seguridad muy graves. Lo que hice fue únicamente instalar el certificado para monitorear esta aplicación, y luego lo desinstalé en el instante en que terminé las pruebas.
Una vez hecho esto, repetí las pruebas anteriores. Pero seguía sin poder ver el tráfico HTTPS. Entonces descubrí que Android le permite a cada aplicación definir su perfil de seguridad de red específico. Por ejemplo, le permite a los desarrolladores de la app desactivar la posibilidad de confiar en certificados instalados por el usuario. Ouch!
Tercer prueba: Parcheemos la app
El proceso manual está explicado acá: https://egorovandreyrm.com/pcap-remote-tutorial/#decrypting_https_tls_traffic y se resume en:
- Desempaquetar la aplicación (archivo .apk)
- Modificar la configuración de networking
- Volver a empaquetar la app
- Firmar el APK
Sin embargo, me topé con varios problemas por lo que la termine parcheando (cambiando la configuración de networking) de forma automática usando: https://github.com/shroudedcode/apk-mitm
Una cosa a tener en cuenta es que quizás la app se compone de varias APKs y entonces tal vez necesiten descargar el XAPK de Apkpure y luego instalar la App parcheada usando la app de Apkpure.
Una vez hecho esto volví a probar.
Pude ver el tráfico HTTPS y comprobar si era lento o no:
Sin embargo, no vi nada raro ahí. Lo que sí me llamó la atención fueron todos estos TCP Retransmits (paquetes que fallaron en entregarse y se retransmitieron):
Lo raro era que todas las IPs de destino con retransmisiones eran IPs versión 6.
Acá se puede ver como no recibí ningún paquete desde ningún servidor con IP versión 6:
Nota: “Tx Packets” son los paquetes enviados “desde” la IP listada en la tabla hacia mi celular. Como se puede ver, no recibí ningún paquete desde ninguna de esas IPs versión 6 (Tx Packets es cero en todos los casos).
Y además, todos los paquetes que fallaban en transmitirse correspondían al primer paso de la negociación de la conexión (TCP 3-way handshake), el paquete SYN. Como nunca se logra enviar el paquete, solo se sigue re-intentando establecer la conexión TCP eternamente.
Nota: Es interesante como se ve el “retraso exponencial” (exponential backoff) en los reintentos (1 segundo, 2 segundos, 4 segundos, 8 segundos.... etc).
Cuarta teoría: ¿Tendrá IPv6 algo que ver con todo esto?
Primer prueba: ¿Quién es esa IP?
Usando nslookup podemos resolver la IP a un dominio:
nslookup 2a03:2880:f0ff:e:face:b00c:0:2
Server: 192.168.100.1
Address: 192.168.100.1#53
Non-authoritative answer:
2.0.0.0.0.0.0.0.c.0.0.b.e.c.a.f.e.0.0.0.f.f.0.f.0.8.8.2.3.0.a.2.ip6.arpa name = edge-star6-shv-01-any2.facebook.com.
mmmmm 🤔 Facebook? Pero yo no abrí Facebook! Supongo que lo que está pasando es que la app tiene la SDK de facebook instalada y por eso el problema lo tengo con varias apps.
Fun-fact: Facebook tiene una IPv6 donde hace un juego de palabras:
Segunda prueba: Diagnostiquemos la conectividad IPV6
Después de googlear un rato, encontré esta página que permite hacer una auditoría/diagnóstico de IPv6 en tu conexión, con información útil que uno podría (en teoría) facilitarle al ISP: http://isp.test-ipv6.com/
En mi caso, aparecía esto como resultado:
Después de investigar un poco, encontré que el comportamiento “normal” cuando una app trata de acceder a un server por IPv6 es:
- Intento hacer una request por IPv6
- Si IPv6 no está disponible en la red, usar IPv4
Sin embargo, lo que me pasaba a mí era:
- Intento hacer una request por IPv6
- Espero una respuesta….
- Un tiempo después → Error de timeout
- Reintento por las dudas
- Espero una respuesta….
- Un tiempo después ---> Error de timeout
- Me canso, paso a IPv4
Este no es el comportamiento correcto. Había algo mal configurado en mi ISP que le hacía creer a mi router que podía usar IPv6, cuando en realidad yo no tengo una IP versión 6 asignada a mi conexión, por lo que termina dando timeout luego de un rato.
Solución
Llamé a mi ISP explicándole el problema, y después de dos intentos con personas diferentes me pudieron solucionar el problema. Resulta que en la VLAN a la que yo estaba asignado todavía no habían terminado de implementar soporte para “dual stack” (IPv4 + IPv6) sin embargo no me habían desactivado explícitamente el ruteo IPv6.
Ahora el diagnóstico de IPv6 se ve así:
Resumen
Recapitulando, el proceso en general fue este:
- Verificar si los DNS están funcionando correctamente
- Simplificar las pruebas eliminando posibles puntos de falla
- Inspeccionar el tráfico de red de la app
- Inspeccionar el tráfico encriptado de red (parcheando la app Android)
- Correr pruebas para detectar problemas con IPv6
Conclusiones
Por suerte hay muchas herramientas disponibles para hacer diferentes verificaciones y ahondar en la raíz de los problemas de conectividad que tenemos. En general es necesario investigar para poder entender qué pasa, y el soporte técnico de los ISP lamentablemente no suele ser el mejor.
En este caso, como siempre que uno tiene que resolver problemas desconocidos, hay una serie de tips que son útiles:
- Reducir la cantidad de variables (simplificar el problema)
- Verificar una cosa por vez
- Buscar las herramientas que nos permitan “visualizar” lo que está pasando
- Tener paciencia y seguir intentando
Espero que esto les sirva para conocer algunas herramientas que son muy útiles para debuggear problemas de red.