libp2p / libp2p/py-libp2p

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

Open
#1,437 20 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Python
Stars
624
Forks
256
Avg merge
1d 34m
Merged PRs (30d)
47

Description

Status (2026-09-14)

libp2p/specs#715 MERGED (2026-09-11, merge 78e75c6 by @johannamoran). WebRTC-Direct v2 is on specs master (webrtc-direct.md, r2 / Candidate Recommendation). Approvals: @lidel, @seetadev, @tabcat.

v1 STUN-dispatch listener + v1 dialer on main via #1449 (merge 1d0876da; stack #1446–#1448).

v2 flow + framing/SCTP fix on main via #1459 (merge 1ba536d3, 2026-09-03). Listener accepts libp2p+webrtc+v2/; dialer opt-in webrtc_direct_dial_version=2.

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

Interop (#1471 + #1495): pinned go-libp2p v0.49 harness in CI. py ↔ go v1 and v2 both directions green. #1470 closed.

Docs (#1513, merged 82f23996, 2026-09-09): STUN vs /sdp harness; v1 vs v2 dial guidance. Closes #1511.

Dialer default still webrtc_direct_dial_version=1. Docs / config comments said to flip to v2 once specs#715 lands — that follow-up is now due (refresh "unmerged" wording too).

Still open on this issue: flip dialer default to v2; true ICE-Lite (#1512 / PR #1532 — open); optional UdpMux upstream; js-libp2p interop when #3480 is ready.


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; v2 text live on specs master).

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

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).

Internal note / roadmap: downloads/AI-PR-REVIEWS/1309/WebRTC_NewSpecs.md (local maintainer doc; refreshed 2026-09-14).

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 — partial on main (#1512 / #1532):
    • DTLS server / setup:passive on listener answer
    • True ICE-Lite controlled agent (aioice has no native local lite mode; #1532 in review)
  • 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 now that specs#715 is merged; refresh README / package docs that still say "while specs#715 is unmerged"
  • 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; still need dialer-default flip + link refresh as above

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#715merged 2026-09-11 (78e75c6); 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 #1512 / #1532 — open
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. Flip dialer default to v2 + refresh stale "unmerged" docs.
  8. True ICE-Lite (#1532); js interop when ready; then claim browser-dial support.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the WebRTC-Direct dialer configuration and the README/package documentation mentioned in the issue; confirm where webrtc_direct_dial_version defaults to v1 and where the stale specs#715 wording remains. Update the default and documentation, then run the existing WebRTC-Direct interoperability tests to verify v2 behavior. True ICE-Lite and JavaScript interop are separate follow-ups already in progress.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
audio-video-rtc, networking
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.