Skip to content

feat(webrtc): track WebRTC-Direct STUN listener + v1/v2 (specs#715) after UdpMux #1437

Description

@acul71

Summary

Tracking issue for a spec-aligned /webrtc-direct listener that demuxes concurrent inbound dials on one advertised UDP port via STUN (no HTTP /sdp harness), including WebRTC-Direct v1 and v2 version-prefix dispatch per libp2p/specs#715.

This is the next step after the ICE-mux primitive in #1397 / spike #1352. Umbrella: #546. Scaffolding from #1309 remains v1 / experimental and still uses the HTTP SDP harness for node-to-node.

Background

WebRTC-Direct v1 and v2 are no-signaling transports. The listener reconstructs the dialer's offer from the inbound STUN connectivity check:

  • Read USERNAME = server_ufrag:client_ufrag
  • Dispatch on version prefix (libp2p+webrtc+v1/ vs libp2p+webrtc+v2/)
  • For v2: recover client_pwd by stripping libp2p+webrtc+v2/ from server_ufrag, then set the server's own ICE ufrag/pwd to server_ufrag before answering (critical for ICE)

v2 exists because Chromium is removing SDP ICE-credential munging (libp2p/specs#672). Spec PR libp2p/specs#715 is approved but not yet merged; Go reference support has landed (go-libp2p#3520); JS is in progress (js-libp2p#3480).

Internal note / roadmap compiled from the spec: downloads/AI-PR-REVIEWS/1309/WebRTC_NewSpecs.md (local maintainer doc).

Prerequisites

  • Spike: aiortc / aioice ICE mux + STUN USERNAME exposure — #1352
  • In-tree UdpMux shared-port demux — #1397 (merge when CI is green)
  • (Optional follow-up) Upstream UdpMux to aioice / pin tested aioice versions

Scope (checklist)

Listener (server) — primary

  • Wire UdpMux into listener.py (replace HTTP /sdp harness for the spec path; keep harness only if still useful for py↔py experiments, clearly marked)
  • First-contact path via set_unknown_stun_handler: parse USERNAME, validate both ufrag halves (RFC 8839 ice-char / length), reject malformed input
  • Version dispatch on server_ufrag prefix:
    • libp2p+webrtc+v1/ → v1 flow
    • libp2p+webrtc+v2/ → v2 flow (recover client_pwd, set local ICE creds to server_ufrag before answer)
    • unknown / missing prefix → reject (do not assume v1)
  • Infer dialer offer from STUN (ufrag/pwd, source IP for c= line — IP only, not port, fingerprint handling per spec)
  • ICE Lite / DTLS roles per spec (server: ICE controlled + ICE Lite, DTLS server / setup:passive)
  • register_addr after ICE nomination; teardown unregister order documented and tested
  • Rate-limit / bound unknown-STUN handling (CPU DoS from parse floods)

Dialer / SDP seam

  • Evolve _apply_ice_credentials() into explicit v1 vs v2 behavior (v2: no local offer munging; embed client_pwd in synthetic answer ufrag/pwd)
  • Document that browser dial requires v2 once NoSdpMangleUfrag ships widely

Interop and docs

  • Interop tests against go-libp2p (and js-libp2p when ready) for v2 browser→server and node→node where applicable
  • Module / README / newsfragments clearly distinguish experimental HTTP harness vs spec STUN listener, and v1 (migration) vs v2 (recommended)
  • Track libp2p/specs#715 merge; refresh links when the v2 text lands on master

Non-goals (for this issue)

References

Resource Link
Spec PR (webrtc-direct v2) libp2p/specs#715
Chrome munging issue libp2p/specs#672
Current webrtc-direct.md https://github.com/libp2p/specs/blob/master/webrtc/webrtc-direct.md
Umbrella #546
Scaffolding #1309
ICE mux spike #1352
UdpMux PR #1397
Go v2 libp2p/go-libp2p#3520
JS v2 libp2p/js-libp2p#3480

Suggested sequencing

  1. Merge feat(webrtc): add UdpMux for shared-port WebRTC-Direct inbound dispatch #1397 (UdpMux).
  2. Implement STUN-dispatch listener on top of UdpMux (v1 acceptance + v2 path).
  3. Add Go (then JS) interop vectors.
  4. Only then claim browser-dial support.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions