Un depurador de heisenbugs: la MTU fija de webrtc-rs y un túnel Tailscale que se comía los fragmentos

Fuentes: The iPad was on Tailscale
Imagen generada por IA con el prompt: Split-screen technical illustration: on the left a stylised tablet with a frozen loading spinner, on the right a network diagram of small packets crossing a tunnel into a black hole
Imagen generada con IA

Este artículo relata un caso real de depuración en p2claw, la app del autor, en el que un iPad con Tailscale activada no cargaba la página mientras el Mac, Linux y el móvil funcionaban sin problemas. La aplicación pintaba el estado de carga, completaba el handshake de WebRTC y abría el data channel, pero el primer GET sobre el canal quedaba colgado para siempre. La respuesta estaba enviada y empujada al canal, pero nunca llegaba al navegador.

En una primera investigación los autores sospecharon del iPad, de WebKit y de Tailscale por separado. Probaron tamaños de mensaje, descartaron el reensamblado de WebKit e incluso acotaron los mensajes a 800 bytes, lo que hacía que la página cargase al instante. La hipótesis inicial fue un bug de Safari en iOS que no reensamblaba mensajes grandes, pero una reproducción aislada con un emisor JavaScript y otro en Rust basado en webrtc-rs no consiguió reproducir el fallo.

La clave llegó al releer los contadores de getStats() de WebRTC capturados en fotos la noche del incidente: la candidate pair del iPad se había quedado en 2.144 bytes y 18 paquetes, mientras que el data channel solo había entregado un único mensaje. El paquete grande nunca llegaba. El culpable era una constante hardcodeada en webrtc-rs: INITIAL_MTU = 1228. Con las cabeceras de cifrado, UDP e IPv6, el paquete resultante es de 1.313 bytes, superior a los 1.280 que tolera el túnel de Tailscale. El kernel fragmenta el paquete y, en condiciones normales, el receptor lo reensambla; sin embargo, en este caso los fragmentos se retransmitían según la backoff de SCTP sin llegar a entregarse. Para los autores la lección es clara: cuando el navegador parece culpable, hay que mirar también la red.