← На главную

Редкий баг webrtc-rs и Tailscale ломает IPv6 на iPad

10.06.2026 15:13 · hackernews

Одно из приложений на iPad внезапно показывало пустую страницу. На Mac, Linux и телефоне всё работало — на том же Wi-Fi, в том же браузере. А на iPad висело. Обновления страницы иногда помогали, но ненадолго.

Первым делом проверили размер сообщений в WebRTC. iPad и Mac показывали одинаковый лимит (maxMessageSize — 64 КБ), а данные шли кусками по 7-8 КБ. Причина отпала. Заподозрили Wi-Fi — но tcpdump был чист, а телефон на той же сети грузился нормально.

После долгих мучений заметили: в отличие от Mac, на iPad включён Tailscale. VPN оборачивает трафик, оставляя меньше места в каждом пакете. Крупные ответы дробятся на большее число мелких фрагментов. Сработала гипотеза, и когда ограничили chunks до 800 байт (каждый влезает в один пакет), iPad загрузился мгновенно. Но вывод о дефекте в WebKit оказался преждевременным — getStats() показал, что транспортный счётчик на iPad застыл на 2144 байтах, а пакеты на приёмник просто не доходили. Это не сборка сообщений в браузере — это потеря на уровне сети.

Оказалось, webrtc-rs (Rust-стек, которым пользуется агент в коробке) режет исходящие сообщения пакетами по 1228 байт. С шифрованием и заголовками это даёт 1265 байт на проводе. Tailscale же держит MTU туннеля в 1280 байт — и крупные IPv6 пакеты вынуждены фрагментироваться. Проблема выяснилась пингами: ping -s 1400 по IPv6 через Tailscale показывал 100% потерь. tailscale metrics print выдал tailscaled_inbound_dropped_packets_total{reason="acl"} — пакеты отбрасывал фильтр. В коде Tailscale нашёлся комментарий: «мы не поддерживаем фрагментацию в IPv6, потому что IPv6 запрещает роутерам фрагментировать». Но отправитель фрагментировать может, и спецификация требует собирать фрагменты на приёмнике. Tailscale же просто выкидывал их.

Ошибка проявлялась только на iPad, потому что в WebRTC-рукопожатии он стабильно выбирал IPv6-пару через Tailscale. Mac сидел без VPN, Linux — попадал на IPv4 или локальную сеть. Обычный HTTPS-трафик не страдает — там работает TCP MSS. А WebRTC шлёт большие UDP-пакеты без проверки MTU.

В итоге две разумные в отдельности вещи — константа INITIAL_MTU = 1228 в webrtc-rs и решение Tailscale не парсить IPv6 фрагменты — сложились в ловушку без единой ошибки. Единственный симптом — пустая страница на одном конкретном устройстве. Баги уже заведены: webrtc-rs/webrtc#806 и tailscale/tailscale#20083.

Читать оригинал →