Skip to content

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

Description

@acul71

Status (2026-10-02)

libp2p/specs#715 MERGED (2026-09-11, 78e75c6). WebRTC-Direct v2 is on specs master (webrtc-direct.md).

Core stack on main:

  • v1 STUN listener + dialer — #1449 (1d0876da)
  • v2 listener + opt-in dialer — #1459 (1ba536d3)
  • go-libp2p interop (py ↔ go v1+v2 both ways) — #1471 + #1495
  • Docs (STUN vs /sdp, v1/v2) — #1513
  • True ICE-Lite listener — #1532 merged 2026-10-02 (758328c4); closes #1512

Default path: spec STUN on a shared UDP port. HTTP POST /sdp remains opt-in (enable_sdp_http_harness=True) for py↔py experiments only.

Dialer default stays webrtc_direct_dial_version=1. Per @tabcat (2026-09-14): wait for wider network support; js-libp2p keeps dialing v1 when munging is possible. Flip to v2 later (stale "while specs#715 is unmerged" wording in config/docs is a small cleanup).

Remaining (optional / deferred): dialer-default flip when the network is ready; js-libp2p interop when #3480 lands; optional UdpMux upstream to aioice. Spec-aligned STUN v1/v2 + ICE-Lite listener track is otherwise complete on main.


Summary

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

v1 (#1449), v2 (#1459), go interop (#1471 + #1495), docs (#1513), and true ICE-Lite (#1532) are on main.

Built on the ICE-mux primitive (#1397 / spike #1352). Umbrella: #546. Earlier scaffolding (#1309) is superseded for node-to-node by the spec STUN path.

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 merged (2026-09-11); Go reference support has landed (go-libp2p#3520); JS is in progress (js-libp2p#3480).

Prerequisites

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

Scope (checklist)

Listener (server) — primary

  • Wire UdpMux into listener.py (spec path default; HTTP /sdp harness opt-in — #1449)
  • First-contact path via set_unknown_stun_handler: parse USERNAME, validate both ufrag halves, reject malformed input
  • Version dispatch — v1 + v2 + reject path (#1459):
    • libp2p+webrtc+v1/ → v1 flow
    • libp2p+webrtc+v2/ → v2 flow — #1459
    • unknown / missing prefix → reject
  • Infer dialer offer from STUN; go → py inbound completes (#1495; closes #1470)
  • ICE Lite / DTLS roles per spec:
    • DTLS server / setup:passive on listener answer
    • True ICE-Lite controlled agent — #1532 (closes #1512); respond-only Lite over aioice despite no native lite flag
  • register_addr after ICE nomination; rate-limit unknown-STUN handling

Dialer / SDP seam

  • v1 dialer: make_v1_credential + build_synthetic_answer
  • v2 dialer: opt-in via webrtc_direct_dial_version=2 — #1459
  • Flip dialer default to v2 — deferred until wider network support (@tabcat); optional cleanup of stale "while specs#715 is unmerged" comments
  • Document that browser dial requires v2 once NoSdpMangleUfrag ships widely — #1513

Interop and docs

  • Interop tests against go-libp2p (#1471 + #1495) — py ↔ go v1+v2; js-libp2p when ready still open
  • Module / README distinguish experimental HTTP harness vs spec STUN listener (#1513)
  • README/docs: v1 (migration) vs v2 (recommended) — #1513
  • Track libp2p/specs#715 merge — done 2026-09-11

Non-goals (for this issue)

  • Full production WebRTC private-to-private (/webrtc via relay) polish — see #773 / umbrella #546
  • Replacing aiortc entirely (Path B from #1352) unless mux/credential gaps force it

References

Resource Link
Spec (webrtc-direct v2) libp2p/specs#715 — merged 2026-09-11; live on master
Merged stack (v1 listener + dialer) #1449 (+ #1446–#1448)
v2 flow (merged) #1459 — merged 2026-09-03
go-libp2p interop + inbound fix #1471, #1495 (closes #1470)
Docs (STUN vs harness, v1/v2) #1513 — merged 2026-09-09 (closes #1511)
True ICE-Lite (merged) #1532 — merged 2026-10-02 (758328c4); closes #1512
Chrome munging issue libp2p/specs#672
Umbrella #546
Scaffolding #1309
UdpMux PR #1397
Go v2 libp2p/go-libp2p#3520 — merged
JS v2 libp2p/js-libp2p#3480 — open

Suggested sequencing

  1. Merge #1397 (UdpMux).
  2. STUN-dispatch listener v1 + v1 dialer — #1449.
  3. v2 listener/dialer — #1459.
  4. Go interop + go → py inbound — #1471, #1495.
  5. Docs — #1513.
  6. specs#715 merge — 2026-09-11.
  7. True ICE-Lite — #1532 (2026-10-02).
  8. Deferred: flip dialer default to v2 when network support is wider; js interop when js-libp2p#3480 is ready; optional UdpMux upstream.

Activity

  1. acul71 commented on Aug 15, 2026

    @acul71
    CollaboratorAuthor
  2. yashksaini-coder commented on Aug 16, 2026

    @yashksaini-coder
    Contributor

    @yashksaini-coder

    Taking on this issue

  3. 79 remaining items

  4. acul71 commented on Sep 3, 2026

    @acul71
    CollaboratorAuthor

    Status update (2026-09-03 evening): Issue body refreshed after merges.

  5. acul71 commented on Sep 3, 2026

    @acul71
    CollaboratorAuthor

    Triage note (2026-09-04): Keeping open as the WebRTC-Direct umbrella.

    On main:

    Still open:

    Close this tracker once inbound interop and the remaining checklist items are done (or split into focused issues).

  6. acul71 commented on Sep 6, 2026

    @acul71
    CollaboratorAuthor

    Status update (2026-09-06): #1471 (go-libp2p WebRTC-Direct interop harness) is merged (b4343c3f). py → go v1/v2 is green in CI; go → py stays strict xfail pending #1470. Issue body checklist / sequencing updated accordingly.

  7. acul71 commented on Sep 6, 2026

    @acul71
    CollaboratorAuthor

    Hi @yashksaini-coder — thanks again for landing the go interop harness in #1471. That closes a big chunk of the #1437 tracking work.

    What’s still open before we can call the WebRTC-Direct STUN / v1+v2 track done:

    1. #1470 — go → py inbound teardown (highest priority)
      ICE completes, then the py listener drops the connection. The interop suite already has strict xfails for this; once fixed they should flip to pass.

    2. True ICE-Lite in aioice
      Spec expects a Lite controlled agent on the listener; we still run a full controlled agent today (DTLS server role is already in place).

    3. Docs
      README / module docs: v1 as migration vs v2 as recommended, plus a note that browser dial needs v2 once NoSdpMangleUfrag is widespread.

    4. Later / optional
      Track libp2p/specs#715 merge and refresh links; js-libp2p interop when js-libp2p#3480 is ready; optional UdpMux upstream to aioice.

    Would you be willing to keep going on this, starting with #1470? If yes, we can scope that first and leave ICE-Lite / docs as follow-ups. If bandwidth is tight, just say so and we’ll reassign or split the work.

  8. yashksaini-coder commented on Sep 7, 2026

    @yashksaini-coder
    Contributor

    @acul71 yeah sure, I will start with it and get a PR up, I am free so you can assign more stuff to me, I already have a PR up #1486 a seperate side quest issue I discovered while I was testing something.

  9. acul71 commented on Sep 7, 2026

    @acul71
    CollaboratorAuthor

    Status update (2026-09-07): Issue body refreshed after #1495.

  10. yashksaini-coder commented on Sep 8, 2026

    @yashksaini-coder
    Contributor

    Thanks @acul71 — matches on my side: #1471 + #1495 merged, py↔go v1/v2 green both directions, and the go→py xfails are now real assertions.

    I'll take docs next since it's self-contained: a webrtc package-docstring section separating the STUN listener (spec path) from the /sdp harness (dev-only), plus a README note — v1 as migration, v2 recommended, and that browser dial needs v2 once NoSdpMangleUfrag is widespread. I'll open a PR for it.

    On true ICE-Lite: the listener is currently a full aioice agent in the controlled role (aioice has no lite mode), which interoperates because the dialer nominates. A real Lite agent is an aioice-side change — happy to pursue it upstream if you think it's worth it, otherwise I'd leave it as a documented ceiling for now.

    specs#715 / js-libp2p#3480 I'll keep watching and refresh links when they move. Anything else you'd like me to prioritize?

  11. yashksaini-coder commented on Sep 8, 2026

    @yashksaini-coder
    Contributor

    @acul71 @seetadev — update on the docs + ICE-Lite follow-ups:

  12. acul71 commented on Sep 10, 2026

    @acul71
    CollaboratorAuthor

    Status update (2026-09-10): Issue body refreshed against main.

  13. acul71 commented on Sep 14, 2026

    @acul71
    CollaboratorAuthor

    Status update (2026-09-14): Issue body refreshed after libp2p/specs#715 merged.

  14. tabcat commented on Sep 14, 2026

    @tabcat
    Member

    might be good to wait on setting default dial version to 2 until network has wider support. js-libp2p will keep using v1 to dial if munging is possible in the environment.

  15. acul71 commented on Oct 2, 2026

    @acul71
    CollaboratorAuthor

    Status update (2026-10-02): Issue body refreshed after #1532.

  16. acul71 commented on Oct 2, 2026

    @acul71
    CollaboratorAuthor

    @tabcat thanks — agreed. We'll keep the dialer default at webrtc_direct_dial_version=1 until there's wider network support (js and others still preferring v1 when munging works). v2 stays opt-in; listener already accepts both. Issue body updated to mark the default flip as deferred rather than due.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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