fix: browser ping timeout — gVisor MTU below IPv6 minimum

Merged
KN
17d ago
+130-16

Symptom

Browser demo at https://knowlet.github.io/MasqueCat/ failed every dial with ping: context deadline exceeded, while CLI (native) through the same relay worked (pong via relay-masque).

Root cause

The browser (js/wasm) gVisor stack used MTU 1000, below the IPv6 minimum link MTU of 1280 (RFC 8200). gVisor calculateNetworkMTU rejects every outbound IPv6 packet with ErrInvalidEndpointState in that case.

Evidence from an instrumented wasm build:

  • tcpActiveOpen=1 tcpSegsSent=0 tcpSegSendErr=3 ipSent=0 ipOutErr=3 — SYNs created, all dropped at IP write
  • relay datagram counter stayed 0 — nothing ever left the browser, even though WebTransport registration succeeded
  • reproduced natively with identical stack setup: MTU 1000 fails, MTU 1280 emits

Fix

  • browserMasqueMTU 1000 -> 1280 (moved to untagged masquecat_mtu.go so native tests reference the exact value). Small WebTransport datagrams still ensured by browserFragmentChunkSize=1000.
  • Verified E2E in headless Chrome against live relay: tailcatDial OK in ~8s, bidirectional relay forwarding confirmed.

Also included

  • Relay logs drops for unknown destinations (was silent).
  • Browser pingUntil logs each failed attempt.
  • TestBrowserStackEmitsIPv6 native regression test.

Verification

  • go build ./..., js/wasm build of ./web, go test ./... all pass.

Summary by Sourcery

Restore browser connectivity by using an IPv6-compliant MTU while preserving small WebTransport datagram fragmentation.

Bug Fixes:

  • Fix browser connection timeouts by raising the gVisor browser stack MTU to the IPv6 minimum of 1280 bytes.
  • Add relay diagnostics for unknown destinations and log failed browser ping attempts.

Tests:

  • Add a native regression test verifying that the browser-equivalent stack emits IPv6 TCP packets without IP errors.

Summary by cubic

Fixes the browser (js/wasm) demo dial failures where ping always timed out, even though the native CLI worked through the same relay. The browser gVisor stack used an MTU of 1000, below the IPv6 minimum link MTU of 1280 (RFC 8200), causing gVisor to reject every outbound IPv6 packet and never send a datagram.

Bug Fixes

  • Raised browser MTU to 1280; small WebTransport datagrams are still ensured by browserFragmentChunkSize.
  • Added logging for relay drops of unknown destinations and for each failed browser ping attempt.
  • Added a native regression test rebuilding the browser-equivalent stack to verify IPv6 TCP SYNs are emitted.