From 58acd82697357fde20883689818e5445516d3a39 Mon Sep 17 00:00:00 2001 From: Max Inden Date: Thu, 15 Dec 2022 13:10:21 +0100 Subject: [PATCH 01/57] webrtc/: Initialize browser-to-browser specification --- webrtc/browser-to-browser.md | 74 ++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 webrtc/browser-to-browser.md diff --git a/webrtc/browser-to-browser.md b/webrtc/browser-to-browser.md new file mode 100644 index 000000000..959d30d5a --- /dev/null +++ b/webrtc/browser-to-browser.md @@ -0,0 +1,74 @@ +# WebRTC browser-to-browser + +| Lifecycle Stage | Maturity | Status | Latest Revision | +|-----------------|---------------|--------|-----------------| +| 1A | Working Draft | Active | r0, 2022-12-15 | + +## Motivation + +1. **Hole punching in the browser**: Enable two browsers or a browser and a + server node to connect even though one or both are behind a NAT / firewall. + + TODO: Doucment use-case where A is a browser and B is a non-browser but behind firewall and/or NAT. + +## Connection Establishment + +### Browser to Browser + +Scenario: Browser _A_ wants to connect to Browser node _B_ with the help of +server node _R_. + +1. _B_ runs inside a browser and can thus not listen for incoming connections. + _B_ connects to a public server node _R_ and uses the Circuit Relay v2 + protocol to make a reservation. + +2. _B_ advertises its relayed address through some external mechanism. + +3. _A_ discovers _B_'s relayed address. _A_ connects to _R_ and establishes a + relayed connection to _B_ via the Circtui Relay v2 protocol. + +4. _A_ and _B_ both create a `RTCPeerConnection` and generate an _offer_ and an + _answer_ respectively. See `icegatheringstatechange` below on how these may + already contain the addresses of the loca node. + +5. _A_ and _B_ exchange the generated _offer_ and _answer_ through some protocol + (e.g. an altered DCUtR) via the relayed connection. + + - One could alter DCUtR or identify-push. + - We should support ICE trickle candidates. + - We can design our own protocol catered for SDP offer and answer. + - Contrary to what browser-to-server does, ideally we would exchange ufrag (username + password). + +6. _A_ and _B_ set the exchanged _offer_ and _answer_ and thus initiate the + connection establishment. + +7. Messages on the established `RTCDataChannel` are framed using the message + framing mechanism described in [Multiplexing](#multiplexing). + +8. The remote is authenticated via an additional Noise handshake. See + [Connection Security](#connection-security). + +The above browser-to-browser WebRTC connection establishment replaces the +existing [libp2p WebRTC star](https://github.com/libp2p/js-libp2p-webrtc-star) +and [libp2p WebRTC direct](https://github.com/libp2p/js-libp2p-webrtc-direct) +protocols. + +#### Open Questions + +- Instead of using trickle ICE, we could as well wait for the candidate + gathering. See + https://github.com/pion/webrtc/blob/c1467e4871c78ee3f463b50d858d13dc6f2874a4/examples/insertable-streams/main.go#L141-L142 + as one example. In the browser, one can wait for the + [`icegatheringstatechange` + event](https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/icegatheringstatechange_event). + +## FAQ + +- Can _Browser_ control the lifecycle of its local TLS certificate, i.e. can + _Browser_ use the same TLS certificate for multiple WebRTC connections? + + Yes. For the lifetime of the page, one can generate a certificate once and + reuse it across connections. See also + https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/RTCPeerConnection#using_certificates + + TODO: Reference privacy considerations. From 35841c3be6b44e3a93d9982838f6eda4e571b9ef Mon Sep 17 00:00:00 2001 From: Max Inden Date: Wed, 4 Jan 2023 13:30:48 +0100 Subject: [PATCH 02/57] Document that Noise handshake is not required --- webrtc/browser-to-browser.md | 39 +++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/webrtc/browser-to-browser.md b/webrtc/browser-to-browser.md index 959d30d5a..f0a679483 100644 --- a/webrtc/browser-to-browser.md +++ b/webrtc/browser-to-browser.md @@ -16,22 +16,19 @@ ### Browser to Browser Scenario: Browser _A_ wants to connect to Browser node _B_ with the help of -server node _R_. +server node _R_. Both _A_ and _B_ can not listen for incoming connections due to +the restriction of the browser platform and being behind a NAT and/or firewall. -1. _B_ runs inside a browser and can thus not listen for incoming connections. - _B_ connects to a public server node _R_ and uses the Circuit Relay v2 - protocol to make a reservation. +1. _A_ and _B_ establish a relayed connection through some protocol, e.g. the + Circuit Relay v2 protocol. Note that further steps depend on the relayed + connection to be authenticated, i.e. that data send on the relayed connection + can be trusted. -2. _B_ advertises its relayed address through some external mechanism. - -3. _A_ discovers _B_'s relayed address. _A_ connects to _R_ and establishes a - relayed connection to _B_ via the Circtui Relay v2 protocol. - -4. _A_ and _B_ both create a `RTCPeerConnection` and generate an _offer_ and an +2. _A_ and _B_ both create a `RTCPeerConnection` and generate an _offer_ and an _answer_ respectively. See `icegatheringstatechange` below on how these may already contain the addresses of the loca node. -5. _A_ and _B_ exchange the generated _offer_ and _answer_ through some protocol +3. _A_ and _B_ exchange the generated _offer_ and _answer_ through some protocol (e.g. an altered DCUtR) via the relayed connection. - One could alter DCUtR or identify-push. @@ -39,15 +36,12 @@ server node _R_. - We can design our own protocol catered for SDP offer and answer. - Contrary to what browser-to-server does, ideally we would exchange ufrag (username + password). -6. _A_ and _B_ set the exchanged _offer_ and _answer_ and thus initiate the +4. _A_ and _B_ set the exchanged _offer_ and _answer_ and thus initiate the connection establishment. -7. Messages on the established `RTCDataChannel` are framed using the message +5. Messages on the established `RTCDataChannel` are framed using the message framing mechanism described in [Multiplexing](#multiplexing). -8. The remote is authenticated via an additional Noise handshake. See - [Connection Security](#connection-security). - The above browser-to-browser WebRTC connection establishment replaces the existing [libp2p WebRTC star](https://github.com/libp2p/js-libp2p-webrtc-star) and [libp2p WebRTC direct](https://github.com/libp2p/js-libp2p-webrtc-direct) @@ -64,6 +58,19 @@ protocols. ## FAQ +- Why is there no additional Noise handshake needed? + + This specification (browser-to-browser) requires _A_ and _B_ to exchange their + SDP offer and answer over an authenticated channel. Offer and answer contain + the TLS certificate fingerprint. The browser validates the TLS certificate + fingerprint through the TLS handshake on the direct connection. + + In contrast, the browser-to-server specification allows exchange of the + server's multiaddr, containing the server's TLS certificate fingerprint, over + unauthenticated channels. In other words, the browser-to-server specification + does not consider the TLS certificate fingerprint in the server's multiaddr to + be trusted. + - Can _Browser_ control the lifecycle of its local TLS certificate, i.e. can _Browser_ use the same TLS certificate for multiple WebRTC connections? From c41007e006a48b6f56487c163c89b35a0da2bd35 Mon Sep 17 00:00:00 2001 From: Max Inden Date: Thu, 5 Jan 2023 18:31:24 +0100 Subject: [PATCH 03/57] Discourage certificate reuse --- webrtc/browser-to-browser.md | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/webrtc/browser-to-browser.md b/webrtc/browser-to-browser.md index f0a679483..572c2aba1 100644 --- a/webrtc/browser-to-browser.md +++ b/webrtc/browser-to-browser.md @@ -28,6 +28,10 @@ the restriction of the browser platform and being behind a NAT and/or firewall. _answer_ respectively. See `icegatheringstatechange` below on how these may already contain the addresses of the loca node. + _A_ and _B_ SHOULD NOT reuse certificates across `RTCPeerConnection`s. + Reusing the certificate can be used to identify a node across connections by + on-path observers given that WebRTC uses TLS 1.2. + 3. _A_ and _B_ exchange the generated _offer_ and _answer_ through some protocol (e.g. an altered DCUtR) via the relayed connection. @@ -70,12 +74,3 @@ protocols. unauthenticated channels. In other words, the browser-to-server specification does not consider the TLS certificate fingerprint in the server's multiaddr to be trusted. - -- Can _Browser_ control the lifecycle of its local TLS certificate, i.e. can - _Browser_ use the same TLS certificate for multiple WebRTC connections? - - Yes. For the lifetime of the page, one can generate a certificate once and - reuse it across connections. See also - https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/RTCPeerConnection#using_certificates - - TODO: Reference privacy considerations. From 29d166b92b6fa4b446a1c11fcc0e0d127086232f Mon Sep 17 00:00:00 2001 From: Max Inden Date: Thu, 5 Jan 2023 19:36:48 +0100 Subject: [PATCH 04/57] Draft signaling protocol --- webrtc/browser-to-browser.md | 52 ++++++++++++++++++++++++------------ 1 file changed, 35 insertions(+), 17 deletions(-) diff --git a/webrtc/browser-to-browser.md b/webrtc/browser-to-browser.md index 572c2aba1..cecbbd885 100644 --- a/webrtc/browser-to-browser.md +++ b/webrtc/browser-to-browser.md @@ -24,27 +24,27 @@ the restriction of the browser platform and being behind a NAT and/or firewall. connection to be authenticated, i.e. that data send on the relayed connection can be trusted. -2. _A_ and _B_ both create a `RTCPeerConnection` and generate an _offer_ and an - _answer_ respectively. See `icegatheringstatechange` below on how these may - already contain the addresses of the loca node. +2. _A_ creates an `RTCPeerConnection`. See [#STUN] on what STUN servers to + configure at creation time. _A_ creates an SDP offer via + `RTCPeerConnection.createOffer()`. _A_ initiates the signaling protocol to _B_ + via the relayed connection from (1), see [#Signaling protocol] and sends the + offer to _B_. - _A_ and _B_ SHOULD NOT reuse certificates across `RTCPeerConnection`s. - Reusing the certificate can be used to identify a node across connections by - on-path observers given that WebRTC uses TLS 1.2. +3. _B_ creates an `RTCPeerConnection`. Again see [#STUN] on what STUN servers to + configure at creation time. _B_ receives _A_'s offer send in (2) via the + signaling protocol stream and provides the offer to its `RTCPeerConnection` + via `RTCPeerConnection.setRemoteDescription`. _B_ then creates an answer via + `RTCPeerConnection.createAnswer` and sends it to _A_ via the existing + signaling protocol stream (see [#signaling protocol]). -3. _A_ and _B_ exchange the generated _offer_ and _answer_ through some protocol - (e.g. an altered DCUtR) via the relayed connection. +4. _A_ receives _B_'s answer via the signaling protocol stream and sets it + locally via `RTCPeerConnection.setRemoteDescription`. - - One could alter DCUtR or identify-push. - - We should support ICE trickle candidates. - - We can design our own protocol catered for SDP offer and answer. - - Contrary to what browser-to-server does, ideally we would exchange ufrag (username + password). +5. TODO: Define ICE candidate exchange. -4. _A_ and _B_ set the exchanged _offer_ and _answer_ and thus initiate the - connection establishment. - -5. Messages on the established `RTCDataChannel` are framed using the message - framing mechanism described in [Multiplexing](#multiplexing). +5. Messages on `RTCDataChannel`s on the established `RTCPeerConnection` are + framed using the message framing mechanism described in + [Multiplexing](#multiplexing). The above browser-to-browser WebRTC connection establishment replaces the existing [libp2p WebRTC star](https://github.com/libp2p/js-libp2p-webrtc-star) @@ -60,6 +60,24 @@ protocols. [`icegatheringstatechange` event](https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/icegatheringstatechange_event). +## STUN + +TODO: Specify + +## Signaling protocol + +TODO: Extend + +Protocol id `/webrtc-direct` + +Messages are sent prefixed with the message length in bytes, encoded as an +unsigned variable length integer as defined by the [multiformats unsigned-varint +spec][uvarint-spec]. + +``` protobuf +// TODO: Support for offer, answer and ICE candidates +``` + ## FAQ - Why is there no additional Noise handshake needed? From 5615e2fb8d53681fa7b1c1053671ee6f53e0d4e5 Mon Sep 17 00:00:00 2001 From: Max Inden Date: Thu, 5 Jan 2023 19:40:36 +0100 Subject: [PATCH 05/57] Document outstanding role assignment --- webrtc/browser-to-browser.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/webrtc/browser-to-browser.md b/webrtc/browser-to-browser.md index cecbbd885..cabfd7809 100644 --- a/webrtc/browser-to-browser.md +++ b/webrtc/browser-to-browser.md @@ -19,6 +19,9 @@ Scenario: Browser _A_ wants to connect to Browser node _B_ with the help of server node _R_. Both _A_ and _B_ can not listen for incoming connections due to the restriction of the browser platform and being behind a NAT and/or firewall. +TODO: Define which node on a relayed connection is _A_ and which one is _B_, +i.e. which one initiates (offer) and which one responds (answer). + 1. _A_ and _B_ establish a relayed connection through some protocol, e.g. the Circuit Relay v2 protocol. Note that further steps depend on the relayed connection to be authenticated, i.e. that data send on the relayed connection From cc1a8f17622072ddf026ad270a3e196c7df9062b Mon Sep 17 00:00:00 2001 From: Max Inden Date: Thu, 5 Jan 2023 19:44:45 +0100 Subject: [PATCH 06/57] Change format to one line per sentence Experimenting with whether this makes reviewing and git diffs simpler. --- webrtc/browser-to-browser.md | 75 +++++++++++++----------------------- 1 file changed, 26 insertions(+), 49 deletions(-) diff --git a/webrtc/browser-to-browser.md b/webrtc/browser-to-browser.md index cabfd7809..8b6a2ec08 100644 --- a/webrtc/browser-to-browser.md +++ b/webrtc/browser-to-browser.md @@ -6,8 +6,7 @@ ## Motivation -1. **Hole punching in the browser**: Enable two browsers or a browser and a - server node to connect even though one or both are behind a NAT / firewall. +1. **Hole punching in the browser**: Enable two browsers or a browser and a server node to connect even though one or both are behind a NAT / firewall. TODO: Doucment use-case where A is a browser and B is a non-browser but behind firewall and/or NAT. @@ -15,53 +14,37 @@ ### Browser to Browser -Scenario: Browser _A_ wants to connect to Browser node _B_ with the help of -server node _R_. Both _A_ and _B_ can not listen for incoming connections due to -the restriction of the browser platform and being behind a NAT and/or firewall. +Scenario: Browser _A_ wants to connect to Browser node _B_ with the help of server node _R_. +Both _A_ and _B_ can not listen for incoming connections due to the restriction of the browser platform and being behind a NAT and/or firewall. -TODO: Define which node on a relayed connection is _A_ and which one is _B_, -i.e. which one initiates (offer) and which one responds (answer). +TODO: Define which node on a relayed connection is _A_ and which one is _B_, i.e. which one initiates (offer) and which one responds (answer). -1. _A_ and _B_ establish a relayed connection through some protocol, e.g. the - Circuit Relay v2 protocol. Note that further steps depend on the relayed - connection to be authenticated, i.e. that data send on the relayed connection - can be trusted. +1. _A_ and _B_ establish a relayed connection through some protocol, e.g. the Circuit Relay v2 protocol. + Note that further steps depend on the relayed connection to be authenticated, i.e. that data send on the relayed connection can be trusted. -2. _A_ creates an `RTCPeerConnection`. See [#STUN] on what STUN servers to - configure at creation time. _A_ creates an SDP offer via - `RTCPeerConnection.createOffer()`. _A_ initiates the signaling protocol to _B_ - via the relayed connection from (1), see [#Signaling protocol] and sends the - offer to _B_. +2. _A_ creates an `RTCPeerConnection`. + See [#STUN] on what STUN servers to configure at creation time. + _A_ creates an SDP offer via `RTCPeerConnection.createOffer()`. + _A_ initiates the signaling protocol to _B_ via the relayed connection from (1), see [#Signaling protocol] and sends the offer to _B_. -3. _B_ creates an `RTCPeerConnection`. Again see [#STUN] on what STUN servers to - configure at creation time. _B_ receives _A_'s offer send in (2) via the - signaling protocol stream and provides the offer to its `RTCPeerConnection` - via `RTCPeerConnection.setRemoteDescription`. _B_ then creates an answer via - `RTCPeerConnection.createAnswer` and sends it to _A_ via the existing - signaling protocol stream (see [#signaling protocol]). +3. _B_ creates an `RTCPeerConnection`. + Again see [#STUN] on what STUN servers to configure at creation time. + _B_ receives _A_'s offer send in (2) via the signaling protocol stream and provides the offer to its `RTCPeerConnection` via `RTCPeerConnection.setRemoteDescription`. + _B_ then creates an answer via `RTCPeerConnection.createAnswer` and sends it to _A_ via the existing signaling protocol stream (see [#signaling protocol]). -4. _A_ receives _B_'s answer via the signaling protocol stream and sets it - locally via `RTCPeerConnection.setRemoteDescription`. +4. _A_ receives _B_'s answer via the signaling protocol stream and sets it locally via `RTCPeerConnection.setRemoteDescription`. 5. TODO: Define ICE candidate exchange. -5. Messages on `RTCDataChannel`s on the established `RTCPeerConnection` are - framed using the message framing mechanism described in - [Multiplexing](#multiplexing). +5. Messages on `RTCDataChannel`s on the established `RTCPeerConnection` are framed using the message framing mechanism described in [Multiplexing](#multiplexing). -The above browser-to-browser WebRTC connection establishment replaces the -existing [libp2p WebRTC star](https://github.com/libp2p/js-libp2p-webrtc-star) -and [libp2p WebRTC direct](https://github.com/libp2p/js-libp2p-webrtc-direct) -protocols. +The above browser-to-browser WebRTC connection establishment replaces the existing [libp2p WebRTC star](https://github.com/libp2p/js-libp2p-webrtc-star) and [libp2p WebRTC direct](https://github.com/libp2p/js-libp2p-webrtc-direct) protocols. #### Open Questions -- Instead of using trickle ICE, we could as well wait for the candidate - gathering. See - https://github.com/pion/webrtc/blob/c1467e4871c78ee3f463b50d858d13dc6f2874a4/examples/insertable-streams/main.go#L141-L142 - as one example. In the browser, one can wait for the - [`icegatheringstatechange` - event](https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/icegatheringstatechange_event). +- Instead of using trickle ICE, we could as well wait for the candidate gathering. + See https://github.com/pion/webrtc/blob/c1467e4871c78ee3f463b50d858d13dc6f2874a4/examples/insertable-streams/main.go#L141-L142 as one example. + In the browser, one can wait for the [`icegatheringstatechange` event](https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/icegatheringstatechange_event). ## STUN @@ -73,9 +56,7 @@ TODO: Extend Protocol id `/webrtc-direct` -Messages are sent prefixed with the message length in bytes, encoded as an -unsigned variable length integer as defined by the [multiformats unsigned-varint -spec][uvarint-spec]. +Messages are sent prefixed with the message length in bytes, encoded as an unsigned variable length integer as defined by the [multiformats unsigned-varint spec][uvarint-spec]. ``` protobuf // TODO: Support for offer, answer and ICE candidates @@ -85,13 +66,9 @@ spec][uvarint-spec]. - Why is there no additional Noise handshake needed? - This specification (browser-to-browser) requires _A_ and _B_ to exchange their - SDP offer and answer over an authenticated channel. Offer and answer contain - the TLS certificate fingerprint. The browser validates the TLS certificate - fingerprint through the TLS handshake on the direct connection. + This specification (browser-to-browser) requires _A_ and _B_ to exchange their SDP offer and answer over an authenticated channel. + Offer and answer contain the TLS certificate fingerprint. + The browser validates the TLS certificate fingerprint through the TLS handshake on the direct connection. - In contrast, the browser-to-server specification allows exchange of the - server's multiaddr, containing the server's TLS certificate fingerprint, over - unauthenticated channels. In other words, the browser-to-server specification - does not consider the TLS certificate fingerprint in the server's multiaddr to - be trusted. + In contrast, the browser-to-server specification allows exchange of the server's multiaddr, containing the server's TLS certificate fingerprint, over unauthenticated channels. + In other words, the browser-to-server specification does not consider the TLS certificate fingerprint in the server's multiaddr to be trusted. From 78fae2669f726da0b123e7c838e3e00b0f6eabd2 Mon Sep 17 00:00:00 2001 From: Max Inden Date: Mon, 16 Jan 2023 09:04:00 +0100 Subject: [PATCH 07/57] Document open question on advertising support in Multiaddr --- webrtc/browser-to-browser.md | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/webrtc/browser-to-browser.md b/webrtc/browser-to-browser.md index 8b6a2ec08..c5cc454c1 100644 --- a/webrtc/browser-to-browser.md +++ b/webrtc/browser-to-browser.md @@ -40,12 +40,6 @@ TODO: Define which node on a relayed connection is _A_ and which one is _B_, i.e The above browser-to-browser WebRTC connection establishment replaces the existing [libp2p WebRTC star](https://github.com/libp2p/js-libp2p-webrtc-star) and [libp2p WebRTC direct](https://github.com/libp2p/js-libp2p-webrtc-direct) protocols. -#### Open Questions - -- Instead of using trickle ICE, we could as well wait for the candidate gathering. - See https://github.com/pion/webrtc/blob/c1467e4871c78ee3f463b50d858d13dc6f2874a4/examples/insertable-streams/main.go#L141-L142 as one example. - In the browser, one can wait for the [`icegatheringstatechange` event](https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/icegatheringstatechange_event). - ## STUN TODO: Specify @@ -62,6 +56,24 @@ Messages are sent prefixed with the message length in bytes, encoded as an unsig // TODO: Support for offer, answer and ICE candidates ``` +## Open Questions + +- Do we need a mechanism for browsers to advertise support for WebRTC browser-to-browser? + + Say that browser B supports WebRTC browser-to-browser. + B listens via a relay and advertises its relayed address. + A discovers B's relayed address. + At this point A does not know whether B is a browser and thus supports WebRTC browser-to-browser, or whether B is e.g. a laptop potentially supporting TCP and QUIC hole punching via DCUtR but not WebRTC browser-to-browser. + In the latter case, A can not establish a direct connection to B. + + Potential solution would be for B to advertise some protocol after the `/p2p-circuit` within its Multiaddr, e.g. `/ip6//udp/4001/p2p//p2p-circuit/webrtc-direct/p2p/`. + As an alternative, A can discover B's support via the identify protocol on the relayed connection or by optimistically opening a stream using the signaling protocol. + Both of the latter options would on failure happen at the expense of a wasted relayed connection. + +- Instead of using trickle ICE, we could as well wait for the candidate gathering. + See https://github.com/pion/webrtc/blob/c1467e4871c78ee3f463b50d858d13dc6f2874a4/examples/insertable-streams/main.go#L141-L142 as one example. + In the browser, one can wait for the [`icegatheringstatechange` event](https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/icegatheringstatechange_event). + ## FAQ - Why is there no additional Noise handshake needed? From 4fa8da49f20e52552209ccf42efe6cf7b29c6564 Mon Sep 17 00:00:00 2001 From: Max Inden Date: Mon, 16 Jan 2023 10:21:33 +0100 Subject: [PATCH 08/57] Extend signaling protocol section and process --- webrtc/browser-to-browser.md | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/webrtc/browser-to-browser.md b/webrtc/browser-to-browser.md index c5cc454c1..de576faa0 100644 --- a/webrtc/browser-to-browser.md +++ b/webrtc/browser-to-browser.md @@ -34,9 +34,13 @@ TODO: Define which node on a relayed connection is _A_ and which one is _B_, i.e 4. _A_ receives _B_'s answer via the signaling protocol stream and sets it locally via `RTCPeerConnection.setRemoteDescription`. -5. TODO: Define ICE candidate exchange. +5. _A_ and _B_ send their local ICE candidates via the existing signaling protocol stream. + Both nodes continuously read from the stream, adding incoming remote candidates via `RTCPeerConnection.addIceCandidate()`. -5. Messages on `RTCDataChannel`s on the established `RTCPeerConnection` are framed using the message framing mechanism described in [Multiplexing](#multiplexing). +6. On successful establishment or failure of the direct connection, _A_ and _B_ close the signaling protocol stream. + TODO: Is there value in retrying on failure? + +7. Messages on `RTCDataChannel`s on the established `RTCPeerConnection` are framed using the message framing mechanism described in [Multiplexing](#multiplexing). The above browser-to-browser WebRTC connection establishment replaces the existing [libp2p WebRTC star](https://github.com/libp2p/js-libp2p-webrtc-star) and [libp2p WebRTC direct](https://github.com/libp2p/js-libp2p-webrtc-direct) protocols. @@ -46,14 +50,27 @@ TODO: Specify ## Signaling protocol -TODO: Extend - -Protocol id `/webrtc-direct` - +The protocol id is `/webrtc-direct`. Messages are sent prefixed with the message length in bytes, encoded as an unsigned variable length integer as defined by the [multiformats unsigned-varint spec][uvarint-spec]. ``` protobuf -// TODO: Support for offer, answer and ICE candidates +syntax = "proto2"; + +message Message { + // Specifies type in `data` field. + enum Type { + // String of `RTCSessionDescription.sdp` + OFFER = 0; + // String of `RTCSessionDescription.sdp` + ANSWER = 1; + // String of `RTCIceCandidate.toJSON()` + CANDIDATE = 2; + } + + // TODO: Consider removal of `required` for future compatibility. + required Type type = 1; + required string data = 2; +} ``` ## Open Questions From 7da600406a7d11162bdbdee006a4614c3dc62603 Mon Sep 17 00:00:00 2001 From: Max Inden Date: Wed, 18 Jan 2023 12:19:58 +0100 Subject: [PATCH 09/57] Define role distribution among A and B Done in consistency with DCUtR protocol. --- webrtc/browser-to-browser.md | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/webrtc/browser-to-browser.md b/webrtc/browser-to-browser.md index de576faa0..4f585aee4 100644 --- a/webrtc/browser-to-browser.md +++ b/webrtc/browser-to-browser.md @@ -17,27 +17,26 @@ Scenario: Browser _A_ wants to connect to Browser node _B_ with the help of server node _R_. Both _A_ and _B_ can not listen for incoming connections due to the restriction of the browser platform and being behind a NAT and/or firewall. -TODO: Define which node on a relayed connection is _A_ and which one is _B_, i.e. which one initiates (offer) and which one responds (answer). - 1. _A_ and _B_ establish a relayed connection through some protocol, e.g. the Circuit Relay v2 protocol. + The relayed connection is established from _A_ to _B_ (see same role distribution in [DCUtR] protocol). Note that further steps depend on the relayed connection to be authenticated, i.e. that data send on the relayed connection can be trusted. -2. _A_ creates an `RTCPeerConnection`. +2. _B_ (inbound side of relayed connection) creates an `RTCPeerConnection`. See [#STUN] on what STUN servers to configure at creation time. - _A_ creates an SDP offer via `RTCPeerConnection.createOffer()`. - _A_ initiates the signaling protocol to _B_ via the relayed connection from (1), see [#Signaling protocol] and sends the offer to _B_. + _B_ creates an SDP offer via `RTCPeerConnection.createOffer()`. + _B_ initiates the signaling protocol to _A_ via the relayed connection from (1), see [#Signaling protocol] and sends the offer to _A_. -3. _B_ creates an `RTCPeerConnection`. +3. _A_ (outbound side of relayed connection) creates an `RTCPeerConnection`. Again see [#STUN] on what STUN servers to configure at creation time. - _B_ receives _A_'s offer send in (2) via the signaling protocol stream and provides the offer to its `RTCPeerConnection` via `RTCPeerConnection.setRemoteDescription`. - _B_ then creates an answer via `RTCPeerConnection.createAnswer` and sends it to _A_ via the existing signaling protocol stream (see [#signaling protocol]). + _A_ receives _B_'s offer send in (2) via the signaling protocol stream and provides the offer to its `RTCPeerConnection` via `RTCPeerConnection.setRemoteDescription`. + _A_ then creates an answer via `RTCPeerConnection.createAnswer` and sends it to _B_ via the existing signaling protocol stream (see [#signaling protocol]). -4. _A_ receives _B_'s answer via the signaling protocol stream and sets it locally via `RTCPeerConnection.setRemoteDescription`. +4. _B_ receives _A_'s answer via the signaling protocol stream and sets it locally via `RTCPeerConnection.setRemoteDescription`. -5. _A_ and _B_ send their local ICE candidates via the existing signaling protocol stream. +5. _B_ and _A_ send their local ICE candidates via the existing signaling protocol stream. Both nodes continuously read from the stream, adding incoming remote candidates via `RTCPeerConnection.addIceCandidate()`. -6. On successful establishment or failure of the direct connection, _A_ and _B_ close the signaling protocol stream. +6. On successful establishment or failure of the direct connection, _B_ and _A_ close the signaling protocol stream. TODO: Is there value in retrying on failure? 7. Messages on `RTCDataChannel`s on the established `RTCPeerConnection` are framed using the message framing mechanism described in [Multiplexing](#multiplexing). @@ -101,3 +100,5 @@ message Message { In contrast, the browser-to-server specification allows exchange of the server's multiaddr, containing the server's TLS certificate fingerprint, over unauthenticated channels. In other words, the browser-to-server specification does not consider the TLS certificate fingerprint in the server's multiaddr to be trusted. + +[DCUtR]: ./../relay/DCUtR.md From badcb1fafb3cfa04e3a133c1236be6e696569844 Mon Sep 17 00:00:00 2001 From: Max Inden Date: Wed, 18 Jan 2023 13:12:22 +0100 Subject: [PATCH 10/57] Detail STUN section --- webrtc/browser-to-browser.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/webrtc/browser-to-browser.md b/webrtc/browser-to-browser.md index 4f585aee4..9111d76ed 100644 --- a/webrtc/browser-to-browser.md +++ b/webrtc/browser-to-browser.md @@ -45,7 +45,19 @@ The above browser-to-browser WebRTC connection establishment replaces the existi ## STUN -TODO: Specify +A node needs to discover its public IP and port, which is forwarded to the remote node in order to connect to the local node. +On non-browser libp2p nodes doing a hole punch with TCP or QUIC, the libp2p node discovers its public address via the [identify] protocol. +One can not use the [identify] protocol on browser nodes to discover ones public IP and port given that the browser uses a new port for each connection. +For example say that the local browser node establishes a WebRTC connection C1 via browser-to-server to a server node and runs the [identify] protocol. +The returned observed public port P1 will most likely (depending on the NAT) be a different port than the port observed on another connection C2. +The only browser supported mechanism to discover ones public IP and port for a given connection is the non-libp2p protocol STUN. +This is why this specification depends on STUN, and thus the availability of one or more STUN servers for _A_ and _B_ to discovery their public addresses. + +There are various publicly available STUN servers. +As an alternative one may operate dedicated STUN servers for a given libp2p network. +Further specification of the usage of STUN is out of scope for this specifitcation. + +As an aside, note that _A_ and _B_ do not need to use the same STUN server in order to establish a direct WebRTC connection. ## Signaling protocol @@ -102,3 +114,4 @@ message Message { In other words, the browser-to-server specification does not consider the TLS certificate fingerprint in the server's multiaddr to be trusted. [DCUtR]: ./../relay/DCUtR.md +[identify]: ./../identify/README.md From d92e6736b1e7b7723cc6a9e636fb75eb92b3ea1d Mon Sep 17 00:00:00 2001 From: Max Inden Date: Wed, 18 Jan 2023 13:15:50 +0100 Subject: [PATCH 11/57] Document relaying on failure to be out of scope --- webrtc/browser-to-browser.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/webrtc/browser-to-browser.md b/webrtc/browser-to-browser.md index 9111d76ed..fbb63b2b2 100644 --- a/webrtc/browser-to-browser.md +++ b/webrtc/browser-to-browser.md @@ -37,7 +37,8 @@ Both _A_ and _B_ can not listen for incoming connections due to the restriction Both nodes continuously read from the stream, adding incoming remote candidates via `RTCPeerConnection.addIceCandidate()`. 6. On successful establishment or failure of the direct connection, _B_ and _A_ close the signaling protocol stream. - TODO: Is there value in retrying on failure? + + Behavior for transferring data on a relayed connection, in the case where the direct connection failed, is out of scope for this specification. 7. Messages on `RTCDataChannel`s on the established `RTCPeerConnection` are framed using the message framing mechanism described in [Multiplexing](#multiplexing). From 1b86e62d5261de9e6fafd324657ffe5f18613d41 Mon Sep 17 00:00:00 2001 From: Max Inden Date: Wed, 18 Jan 2023 13:17:53 +0100 Subject: [PATCH 12/57] Remove trickle candidate alternative --- webrtc/browser-to-browser.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/webrtc/browser-to-browser.md b/webrtc/browser-to-browser.md index fbb63b2b2..68a093bac 100644 --- a/webrtc/browser-to-browser.md +++ b/webrtc/browser-to-browser.md @@ -99,10 +99,6 @@ message Message { As an alternative, A can discover B's support via the identify protocol on the relayed connection or by optimistically opening a stream using the signaling protocol. Both of the latter options would on failure happen at the expense of a wasted relayed connection. -- Instead of using trickle ICE, we could as well wait for the candidate gathering. - See https://github.com/pion/webrtc/blob/c1467e4871c78ee3f463b50d858d13dc6f2874a4/examples/insertable-streams/main.go#L141-L142 as one example. - In the browser, one can wait for the [`icegatheringstatechange` event](https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/icegatheringstatechange_event). - ## FAQ - Why is there no additional Noise handshake needed? From 79ee3b01cce8303225ec6f7e3f0a4aafdb971d36 Mon Sep 17 00:00:00 2001 From: Max Inden Date: Wed, 18 Jan 2023 13:20:45 +0100 Subject: [PATCH 13/57] Document non-browser behind NAT and/or firewall --- webrtc/browser-to-browser.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/webrtc/browser-to-browser.md b/webrtc/browser-to-browser.md index 68a093bac..90c0f138b 100644 --- a/webrtc/browser-to-browser.md +++ b/webrtc/browser-to-browser.md @@ -8,14 +8,13 @@ 1. **Hole punching in the browser**: Enable two browsers or a browser and a server node to connect even though one or both are behind a NAT / firewall. - TODO: Doucment use-case where A is a browser and B is a non-browser but behind firewall and/or NAT. - ## Connection Establishment ### Browser to Browser Scenario: Browser _A_ wants to connect to Browser node _B_ with the help of server node _R_. Both _A_ and _B_ can not listen for incoming connections due to the restriction of the browser platform and being behind a NAT and/or firewall. +Note that _A_ or _B_ may as well be a non-browser node behind a NAT and/or firewall trying to connect to a browser node. 1. _A_ and _B_ establish a relayed connection through some protocol, e.g. the Circuit Relay v2 protocol. The relayed connection is established from _A_ to _B_ (see same role distribution in [DCUtR] protocol). From e3848393012f8cb757ed47a0456e9a180394824f Mon Sep 17 00:00:00 2001 From: Max Inden Date: Wed, 18 Jan 2023 13:23:25 +0100 Subject: [PATCH 14/57] Minor edits --- webrtc/browser-to-browser.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/webrtc/browser-to-browser.md b/webrtc/browser-to-browser.md index 90c0f138b..c724738a2 100644 --- a/webrtc/browser-to-browser.md +++ b/webrtc/browser-to-browser.md @@ -6,7 +6,7 @@ ## Motivation -1. **Hole punching in the browser**: Enable two browsers or a browser and a server node to connect even though one or both are behind a NAT / firewall. +**Hole punching in the browser** - Enable two browsers or a browser and a non-browser node to connect even though one or both are behind a NAT / firewall. ## Connection Establishment @@ -27,7 +27,7 @@ Note that _A_ or _B_ may as well be a non-browser node behind a NAT and/or firew 3. _A_ (outbound side of relayed connection) creates an `RTCPeerConnection`. Again see [#STUN] on what STUN servers to configure at creation time. - _A_ receives _B_'s offer send in (2) via the signaling protocol stream and provides the offer to its `RTCPeerConnection` via `RTCPeerConnection.setRemoteDescription`. + _A_ receives _B_'s offer sent in (2) via the signaling protocol stream and provides the offer to its `RTCPeerConnection` via `RTCPeerConnection.setRemoteDescription`. _A_ then creates an answer via `RTCPeerConnection.createAnswer` and sends it to _B_ via the existing signaling protocol stream (see [#signaling protocol]). 4. _B_ receives _A_'s answer via the signaling protocol stream and sets it locally via `RTCPeerConnection.setRemoteDescription`. @@ -37,9 +37,9 @@ Note that _A_ or _B_ may as well be a non-browser node behind a NAT and/or firew 6. On successful establishment or failure of the direct connection, _B_ and _A_ close the signaling protocol stream. - Behavior for transferring data on a relayed connection, in the case where the direct connection failed, is out of scope for this specification. + Behavior for transferring data on a relayed connection, in the case where the direct connection failed, is out of scope for this specification and dependent on the application. -7. Messages on `RTCDataChannel`s on the established `RTCPeerConnection` are framed using the message framing mechanism described in [Multiplexing](#multiplexing). +7. Messages on `RTCDataChannel`s on the established `RTCPeerConnection` are framed using the message framing mechanism described in [multiplexing]. The above browser-to-browser WebRTC connection establishment replaces the existing [libp2p WebRTC star](https://github.com/libp2p/js-libp2p-webrtc-star) and [libp2p WebRTC direct](https://github.com/libp2p/js-libp2p-webrtc-direct) protocols. @@ -111,3 +111,4 @@ message Message { [DCUtR]: ./../relay/DCUtR.md [identify]: ./../identify/README.md +[multiplexing]: ./README.md#multiplexing From b5d82c41e2493a0eee59e77f2c707d7de55a672d Mon Sep 17 00:00:00 2001 From: Max Inden Date: Wed, 18 Jan 2023 13:25:05 +0100 Subject: [PATCH 15/57] Mark proto fields as optional Allows future versions to deprecate and remove fields in a two step process. For more details see https://github.com/libp2p/specs/issues/465#issuecomment-1267496542 --- webrtc/browser-to-browser.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/webrtc/browser-to-browser.md b/webrtc/browser-to-browser.md index c724738a2..ebbd3f8c9 100644 --- a/webrtc/browser-to-browser.md +++ b/webrtc/browser-to-browser.md @@ -78,9 +78,8 @@ message Message { CANDIDATE = 2; } - // TODO: Consider removal of `required` for future compatibility. - required Type type = 1; - required string data = 2; + optional Type type = 1; + optional string data = 2; } ``` From 6c139b6ee7f8a584f246fee2f8c9dada614e3532 Mon Sep 17 00:00:00 2001 From: Max Inden Date: Wed, 18 Jan 2023 13:30:11 +0100 Subject: [PATCH 16/57] Move mention of existing (deprecated) protocols --- webrtc/browser-to-browser.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/webrtc/browser-to-browser.md b/webrtc/browser-to-browser.md index ebbd3f8c9..b03c400b4 100644 --- a/webrtc/browser-to-browser.md +++ b/webrtc/browser-to-browser.md @@ -8,6 +8,8 @@ **Hole punching in the browser** - Enable two browsers or a browser and a non-browser node to connect even though one or both are behind a NAT / firewall. +On a historical note, this specification replaces the existing [libp2p WebRTC star](https://github.com/libp2p/js-libp2p-webrtc-star) and [libp2p WebRTC direct](https://github.com/libp2p/js-libp2p-webrtc-direct) protocols. + ## Connection Establishment ### Browser to Browser @@ -41,8 +43,6 @@ Note that _A_ or _B_ may as well be a non-browser node behind a NAT and/or firew 7. Messages on `RTCDataChannel`s on the established `RTCPeerConnection` are framed using the message framing mechanism described in [multiplexing]. -The above browser-to-browser WebRTC connection establishment replaces the existing [libp2p WebRTC star](https://github.com/libp2p/js-libp2p-webrtc-star) and [libp2p WebRTC direct](https://github.com/libp2p/js-libp2p-webrtc-direct) protocols. - ## STUN A node needs to discover its public IP and port, which is forwarded to the remote node in order to connect to the local node. From 74c1bc0198758b1eeeb0f5a6cd67a3f939d6251b Mon Sep 17 00:00:00 2001 From: Max Inden Date: Wed, 18 Jan 2023 13:34:46 +0100 Subject: [PATCH 17/57] Document not using DCUtR --- webrtc/browser-to-browser.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/webrtc/browser-to-browser.md b/webrtc/browser-to-browser.md index b03c400b4..41277953e 100644 --- a/webrtc/browser-to-browser.md +++ b/webrtc/browser-to-browser.md @@ -108,6 +108,14 @@ message Message { In contrast, the browser-to-server specification allows exchange of the server's multiaddr, containing the server's TLS certificate fingerprint, over unauthenticated channels. In other words, the browser-to-server specification does not consider the TLS certificate fingerprint in the server's multiaddr to be trusted. +- Why use a custom signaling protocol? Why not use [DCUtR]? + + DCUtR offers time synchronization through a two-step protocol (first `Connect`, then `Sync`). + This is not needed for WebRTC. + + DCUtR does not provide a mechanism to trickle local address candidates to the remote as they are discovered. + Trickling candidates just-in-time allows for faster WebRTC connection establishment. + [DCUtR]: ./../relay/DCUtR.md [identify]: ./../identify/README.md [multiplexing]: ./README.md#multiplexing From 619e4e673d5cab9aa2e5889e5201791f68acdb6d Mon Sep 17 00:00:00 2001 From: Max Inden Date: Wed, 18 Jan 2023 14:08:59 +0100 Subject: [PATCH 18/57] Fix STUN section link --- webrtc/browser-to-browser.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/webrtc/browser-to-browser.md b/webrtc/browser-to-browser.md index 41277953e..d794ae508 100644 --- a/webrtc/browser-to-browser.md +++ b/webrtc/browser-to-browser.md @@ -23,12 +23,12 @@ Note that _A_ or _B_ may as well be a non-browser node behind a NAT and/or firew Note that further steps depend on the relayed connection to be authenticated, i.e. that data send on the relayed connection can be trusted. 2. _B_ (inbound side of relayed connection) creates an `RTCPeerConnection`. - See [#STUN] on what STUN servers to configure at creation time. + See [STUN](#stun) section on what STUN servers to configure at creation time. _B_ creates an SDP offer via `RTCPeerConnection.createOffer()`. _B_ initiates the signaling protocol to _A_ via the relayed connection from (1), see [#Signaling protocol] and sends the offer to _A_. 3. _A_ (outbound side of relayed connection) creates an `RTCPeerConnection`. - Again see [#STUN] on what STUN servers to configure at creation time. + Again see [STUN](#stun) section on what STUN servers to configure at creation time. _A_ receives _B_'s offer sent in (2) via the signaling protocol stream and provides the offer to its `RTCPeerConnection` via `RTCPeerConnection.setRemoteDescription`. _A_ then creates an answer via `RTCPeerConnection.createAnswer` and sends it to _B_ via the existing signaling protocol stream (see [#signaling protocol]). From aa62e929060e08e02c99a94974b7e0a418254362 Mon Sep 17 00:00:00 2001 From: Max Inden Date: Wed, 18 Jan 2023 14:10:16 +0100 Subject: [PATCH 19/57] Fix signaling protocol link --- webrtc/browser-to-browser.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/webrtc/browser-to-browser.md b/webrtc/browser-to-browser.md index d794ae508..6958dd5f9 100644 --- a/webrtc/browser-to-browser.md +++ b/webrtc/browser-to-browser.md @@ -25,12 +25,12 @@ Note that _A_ or _B_ may as well be a non-browser node behind a NAT and/or firew 2. _B_ (inbound side of relayed connection) creates an `RTCPeerConnection`. See [STUN](#stun) section on what STUN servers to configure at creation time. _B_ creates an SDP offer via `RTCPeerConnection.createOffer()`. - _B_ initiates the signaling protocol to _A_ via the relayed connection from (1), see [#Signaling protocol] and sends the offer to _A_. + _B_ initiates the signaling protocol to _A_ via the relayed connection from (1), see [Signaling Protocol](#signaling-protocol) and sends the offer to _A_. 3. _A_ (outbound side of relayed connection) creates an `RTCPeerConnection`. Again see [STUN](#stun) section on what STUN servers to configure at creation time. _A_ receives _B_'s offer sent in (2) via the signaling protocol stream and provides the offer to its `RTCPeerConnection` via `RTCPeerConnection.setRemoteDescription`. - _A_ then creates an answer via `RTCPeerConnection.createAnswer` and sends it to _B_ via the existing signaling protocol stream (see [#signaling protocol]). + _A_ then creates an answer via `RTCPeerConnection.createAnswer` and sends it to _B_ via the existing signaling protocol stream (see [Signaling Protocol](#signaling-protocol)). 4. _B_ receives _A_'s answer via the signaling protocol stream and sets it locally via `RTCPeerConnection.setRemoteDescription`. @@ -59,7 +59,7 @@ Further specification of the usage of STUN is out of scope for this specifitcati As an aside, note that _A_ and _B_ do not need to use the same STUN server in order to establish a direct WebRTC connection. -## Signaling protocol +## Signaling Protocol The protocol id is `/webrtc-direct`. Messages are sent prefixed with the message length in bytes, encoded as an unsigned variable length integer as defined by the [multiformats unsigned-varint spec][uvarint-spec]. From fa79a134a6e936b8278b2d8a1e5e04d217a4df34 Mon Sep 17 00:00:00 2001 From: Max Inden Date: Wed, 18 Jan 2023 14:12:12 +0100 Subject: [PATCH 20/57] Add uvarint link --- webrtc/browser-to-browser.md | 1 + 1 file changed, 1 insertion(+) diff --git a/webrtc/browser-to-browser.md b/webrtc/browser-to-browser.md index 6958dd5f9..bac11cc8c 100644 --- a/webrtc/browser-to-browser.md +++ b/webrtc/browser-to-browser.md @@ -119,3 +119,4 @@ message Message { [DCUtR]: ./../relay/DCUtR.md [identify]: ./../identify/README.md [multiplexing]: ./README.md#multiplexing +[uvarint-spec]: https://github.com/multiformats/unsigned-varint From f5ea2488f96e4a932acfa7c1d6e1419639870757 Mon Sep 17 00:00:00 2001 From: Max Inden Date: Mon, 23 Jan 2023 15:36:46 +0100 Subject: [PATCH 21/57] refactor(proto): Rename to SDP_{OFFER,ANSWER} and ICE_CANDIDATE Co-authored-by: Thomas Eizinger --- webrtc/browser-to-browser.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/webrtc/browser-to-browser.md b/webrtc/browser-to-browser.md index bac11cc8c..766867283 100644 --- a/webrtc/browser-to-browser.md +++ b/webrtc/browser-to-browser.md @@ -71,11 +71,11 @@ message Message { // Specifies type in `data` field. enum Type { // String of `RTCSessionDescription.sdp` - OFFER = 0; + SDP_OFFER = 0; // String of `RTCSessionDescription.sdp` - ANSWER = 1; + SDP_ANSWER = 1; // String of `RTCIceCandidate.toJSON()` - CANDIDATE = 2; + ICE_CANDIDATE = 2; } optional Type type = 1; From 39ed4582a2171c634da60b17a0e71ac1f07cc487 Mon Sep 17 00:00:00 2001 From: Max Inden Date: Mon, 23 Jan 2023 15:46:44 +0100 Subject: [PATCH 22/57] Update webrtc/browser-to-browser.md Co-authored-by: Marco Munizaga --- webrtc/browser-to-browser.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webrtc/browser-to-browser.md b/webrtc/browser-to-browser.md index 766867283..7aa32e5b2 100644 --- a/webrtc/browser-to-browser.md +++ b/webrtc/browser-to-browser.md @@ -20,7 +20,7 @@ Note that _A_ or _B_ may as well be a non-browser node behind a NAT and/or firew 1. _A_ and _B_ establish a relayed connection through some protocol, e.g. the Circuit Relay v2 protocol. The relayed connection is established from _A_ to _B_ (see same role distribution in [DCUtR] protocol). - Note that further steps depend on the relayed connection to be authenticated, i.e. that data send on the relayed connection can be trusted. + Note that further steps depend on the relayed connection to be authenticated, i.e. that data sent on the relayed connection can be trusted. 2. _B_ (inbound side of relayed connection) creates an `RTCPeerConnection`. See [STUN](#stun) section on what STUN servers to configure at creation time. From 2408db97f0d8883916486d08ae2720c286fa946b Mon Sep 17 00:00:00 2001 From: Max Inden Date: Tue, 24 Jan 2023 14:08:58 +0100 Subject: [PATCH 23/57] Use proto3 See recommendation change with https://github.com/libp2p/specs/pull/506 --- webrtc/browser-to-browser.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webrtc/browser-to-browser.md b/webrtc/browser-to-browser.md index 7aa32e5b2..ded92a4c2 100644 --- a/webrtc/browser-to-browser.md +++ b/webrtc/browser-to-browser.md @@ -65,7 +65,7 @@ The protocol id is `/webrtc-direct`. Messages are sent prefixed with the message length in bytes, encoded as an unsigned variable length integer as defined by the [multiformats unsigned-varint spec][uvarint-spec]. ``` protobuf -syntax = "proto2"; +syntax = "proto3"; message Message { // Specifies type in `data` field. From e1e6a0c0a8144118bf13e733ca2b0678987dde89 Mon Sep 17 00:00:00 2001 From: Max Inden Date: Tue, 24 Jan 2023 14:20:28 +0100 Subject: [PATCH 24/57] Make explicit that A and B might as well be non-browser --- webrtc/browser-to-browser.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webrtc/browser-to-browser.md b/webrtc/browser-to-browser.md index ded92a4c2..6ec412584 100644 --- a/webrtc/browser-to-browser.md +++ b/webrtc/browser-to-browser.md @@ -16,7 +16,7 @@ On a historical note, this specification replaces the existing [libp2p WebRTC st Scenario: Browser _A_ wants to connect to Browser node _B_ with the help of server node _R_. Both _A_ and _B_ can not listen for incoming connections due to the restriction of the browser platform and being behind a NAT and/or firewall. -Note that _A_ or _B_ may as well be a non-browser node behind a NAT and/or firewall trying to connect to a browser node. +Note that _A_ and/or _B_ may as well be non-browser nodes behind NATs and/or firewalls. 1. _A_ and _B_ establish a relayed connection through some protocol, e.g. the Circuit Relay v2 protocol. The relayed connection is established from _A_ to _B_ (see same role distribution in [DCUtR] protocol). From 30b0d53562e641490da881f93a091dd86bbaf834 Mon Sep 17 00:00:00 2001 From: Max Inden Date: Tue, 24 Jan 2023 14:36:46 +0100 Subject: [PATCH 25/57] Document reset on failure --- webrtc/browser-to-browser.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/webrtc/browser-to-browser.md b/webrtc/browser-to-browser.md index 6ec412584..67f8fcc70 100644 --- a/webrtc/browser-to-browser.md +++ b/webrtc/browser-to-browser.md @@ -37,7 +37,8 @@ Note that _A_ and/or _B_ may as well be non-browser nodes behind NATs and/or fir 5. _B_ and _A_ send their local ICE candidates via the existing signaling protocol stream. Both nodes continuously read from the stream, adding incoming remote candidates via `RTCPeerConnection.addIceCandidate()`. -6. On successful establishment or failure of the direct connection, _B_ and _A_ close the signaling protocol stream. +6. On successful establishment of the direct connection, _A_ and _B_ close the signaling protocol stream. + On failure _A_ and _B_ reset the signaling protocol stream. Behavior for transferring data on a relayed connection, in the case where the direct connection failed, is out of scope for this specification and dependent on the application. From ebc3d5c21f9f84ce625102ea72d2befff9678bad Mon Sep 17 00:00:00 2001 From: Max Inden Date: Tue, 24 Jan 2023 14:40:42 +0100 Subject: [PATCH 26/57] Remove sub heading implied by document title --- webrtc/browser-to-browser.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/webrtc/browser-to-browser.md b/webrtc/browser-to-browser.md index 67f8fcc70..f9e66a9ec 100644 --- a/webrtc/browser-to-browser.md +++ b/webrtc/browser-to-browser.md @@ -12,8 +12,6 @@ On a historical note, this specification replaces the existing [libp2p WebRTC st ## Connection Establishment -### Browser to Browser - Scenario: Browser _A_ wants to connect to Browser node _B_ with the help of server node _R_. Both _A_ and _B_ can not listen for incoming connections due to the restriction of the browser platform and being behind a NAT and/or firewall. Note that _A_ and/or _B_ may as well be non-browser nodes behind NATs and/or firewalls. From 6406947e69fe02d58bad7efe8200ec8f0fd4ab8a Mon Sep 17 00:00:00 2001 From: Max Inden Date: Tue, 24 Jan 2023 14:44:49 +0100 Subject: [PATCH 27/57] Document latency of relayed connection --- webrtc/browser-to-browser.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webrtc/browser-to-browser.md b/webrtc/browser-to-browser.md index f9e66a9ec..4f6579372 100644 --- a/webrtc/browser-to-browser.md +++ b/webrtc/browser-to-browser.md @@ -94,7 +94,7 @@ message Message { Potential solution would be for B to advertise some protocol after the `/p2p-circuit` within its Multiaddr, e.g. `/ip6//udp/4001/p2p//p2p-circuit/webrtc-direct/p2p/`. As an alternative, A can discover B's support via the identify protocol on the relayed connection or by optimistically opening a stream using the signaling protocol. - Both of the latter options would on failure happen at the expense of a wasted relayed connection. + Both of the latter options imply long latency (direct connection + relayed connection + stream establishment / identify exchange) on success and on failure happen at the expense of a wasted relayed connection. ## FAQ From 5a9e553927e4d4309067e8246da0b49d2b8b11e5 Mon Sep 17 00:00:00 2001 From: Max Inden Date: Wed, 15 Feb 2023 14:35:14 +0100 Subject: [PATCH 28/57] Rename signaling protocol to `/webrtc-signaling` --- webrtc/browser-to-browser.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webrtc/browser-to-browser.md b/webrtc/browser-to-browser.md index 4f6579372..dee9ce013 100644 --- a/webrtc/browser-to-browser.md +++ b/webrtc/browser-to-browser.md @@ -60,7 +60,7 @@ As an aside, note that _A_ and _B_ do not need to use the same STUN server in or ## Signaling Protocol -The protocol id is `/webrtc-direct`. +The protocol id is `/webrtc-signaling`. Messages are sent prefixed with the message length in bytes, encoded as an unsigned variable length integer as defined by the [multiformats unsigned-varint spec][uvarint-spec]. ``` protobuf From 2d6ef305ec7a146b372edd3fcaad44d3efa564fa Mon Sep 17 00:00:00 2001 From: Max Inden Date: Wed, 15 Feb 2023 14:41:11 +0100 Subject: [PATCH 29/57] Contrast to DCUtR protocol for two non-browsers --- webrtc/browser-to-browser.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/webrtc/browser-to-browser.md b/webrtc/browser-to-browser.md index dee9ce013..063b84945 100644 --- a/webrtc/browser-to-browser.md +++ b/webrtc/browser-to-browser.md @@ -15,6 +15,8 @@ On a historical note, this specification replaces the existing [libp2p WebRTC st Scenario: Browser _A_ wants to connect to Browser node _B_ with the help of server node _R_. Both _A_ and _B_ can not listen for incoming connections due to the restriction of the browser platform and being behind a NAT and/or firewall. Note that _A_ and/or _B_ may as well be non-browser nodes behind NATs and/or firewalls. +However, for two non-browser nodes using TCP or QUIC hole punching with [DCUtR] will be the more efficient way to establish a direct connection. + 1. _A_ and _B_ establish a relayed connection through some protocol, e.g. the Circuit Relay v2 protocol. The relayed connection is established from _A_ to _B_ (see same role distribution in [DCUtR] protocol). From 4255246b0d6e252666055bcc8a234e65cc12cbea Mon Sep 17 00:00:00 2001 From: Max Inden Date: Wed, 15 Feb 2023 14:43:30 +0100 Subject: [PATCH 30/57] Reword TLS certificate validation sentence --- webrtc/browser-to-browser.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webrtc/browser-to-browser.md b/webrtc/browser-to-browser.md index 063b84945..528a97cb5 100644 --- a/webrtc/browser-to-browser.md +++ b/webrtc/browser-to-browser.md @@ -104,7 +104,7 @@ message Message { This specification (browser-to-browser) requires _A_ and _B_ to exchange their SDP offer and answer over an authenticated channel. Offer and answer contain the TLS certificate fingerprint. - The browser validates the TLS certificate fingerprint through the TLS handshake on the direct connection. + The browser validates the TLS certificate fingerprint through the DTLS handshake during the WebRTC connection establishment. In contrast, the browser-to-server specification allows exchange of the server's multiaddr, containing the server's TLS certificate fingerprint, over unauthenticated channels. In other words, the browser-to-server specification does not consider the TLS certificate fingerprint in the server's multiaddr to be trusted. From e99d582134ec5a43fb69be8229ebfa3aaf91fe8c Mon Sep 17 00:00:00 2001 From: Max Inden Date: Tue, 21 Feb 2023 16:46:24 +0100 Subject: [PATCH 31/57] Have A initiate the signaling protocol See rational in the FAQ. --- webrtc/browser-to-browser.md | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/webrtc/browser-to-browser.md b/webrtc/browser-to-browser.md index 528a97cb5..52f0c1cb2 100644 --- a/webrtc/browser-to-browser.md +++ b/webrtc/browser-to-browser.md @@ -17,28 +17,27 @@ Both _A_ and _B_ can not listen for incoming connections due to the restriction Note that _A_ and/or _B_ may as well be non-browser nodes behind NATs and/or firewalls. However, for two non-browser nodes using TCP or QUIC hole punching with [DCUtR] will be the more efficient way to establish a direct connection. - 1. _A_ and _B_ establish a relayed connection through some protocol, e.g. the Circuit Relay v2 protocol. - The relayed connection is established from _A_ to _B_ (see same role distribution in [DCUtR] protocol). + The relayed connection is established from _A_ to _B_. Note that further steps depend on the relayed connection to be authenticated, i.e. that data sent on the relayed connection can be trusted. -2. _B_ (inbound side of relayed connection) creates an `RTCPeerConnection`. +2. _A_ (outbound side of relayed connection) creates an `RTCPeerConnection`. See [STUN](#stun) section on what STUN servers to configure at creation time. - _B_ creates an SDP offer via `RTCPeerConnection.createOffer()`. - _B_ initiates the signaling protocol to _A_ via the relayed connection from (1), see [Signaling Protocol](#signaling-protocol) and sends the offer to _A_. + _A_ creates an SDP offer via `RTCPeerConnection.createOffer()`. + _A_ initiates the signaling protocol to _B_ via the relayed connection from (1), see [Signaling Protocol](#signaling-protocol) and sends the offer to _B_. -3. _A_ (outbound side of relayed connection) creates an `RTCPeerConnection`. +3. _B_ (inbound side of relayed connection) creates an `RTCPeerConnection`. Again see [STUN](#stun) section on what STUN servers to configure at creation time. - _A_ receives _B_'s offer sent in (2) via the signaling protocol stream and provides the offer to its `RTCPeerConnection` via `RTCPeerConnection.setRemoteDescription`. - _A_ then creates an answer via `RTCPeerConnection.createAnswer` and sends it to _B_ via the existing signaling protocol stream (see [Signaling Protocol](#signaling-protocol)). + _B_ receives _A_'s offer sent in (2) via the signaling protocol stream and provides the offer to its `RTCPeerConnection` via `RTCPeerConnection.setRemoteDescription`. + _B_ then creates an answer via `RTCPeerConnection.createAnswer` and sends it to _A_ via the existing signaling protocol stream (see [Signaling Protocol](#signaling-protocol)). -4. _B_ receives _A_'s answer via the signaling protocol stream and sets it locally via `RTCPeerConnection.setRemoteDescription`. +4. _A_ receives _B_'s answer via the signaling protocol stream and sets it locally via `RTCPeerConnection.setRemoteDescription`. -5. _B_ and _A_ send their local ICE candidates via the existing signaling protocol stream. +5. _A_ and _B_ send their local ICE candidates via the existing signaling protocol stream. Both nodes continuously read from the stream, adding incoming remote candidates via `RTCPeerConnection.addIceCandidate()`. -6. On successful establishment of the direct connection, _A_ and _B_ close the signaling protocol stream. - On failure _A_ and _B_ reset the signaling protocol stream. +6. On successful establishment of the direct connection, _B_ and _A_ close the signaling protocol stream. + On failure _B_ and _A_ reset the signaling protocol stream. Behavior for transferring data on a relayed connection, in the case where the direct connection failed, is out of scope for this specification and dependent on the application. @@ -117,6 +116,14 @@ message Message { DCUtR does not provide a mechanism to trickle local address candidates to the remote as they are discovered. Trickling candidates just-in-time allows for faster WebRTC connection establishment. +- Why does _A_ and not _B_ initiate the signaling protocol? + + In [DCUtR] _B_ (inbound side of the relayed connection) initiates the [DCUtR] protocol by opening the [DCUtR] protocol stream. + The reason is that in case _A_ is publicly reachable, _B_ might be able to use connection reversal to connect to _A_ directly. + This reason does not apply to the WebRTC browser-to-browser protocol. + Given that _A_ and _B_ at this point already have a relayed connection established, they might as well use it to exchange SDP, instead of using connection reversal and WebRTC browser-to-server. + Thus, for the WebRTC browser-to-browser protocol, _A_ initiates the signaling protocol by opening the signaling protocol stream. + [DCUtR]: ./../relay/DCUtR.md [identify]: ./../identify/README.md [multiplexing]: ./README.md#multiplexing From c09392bbcff61017c7fa67fba0c3048135f25706 Mon Sep 17 00:00:00 2001 From: Max Inden Date: Tue, 21 Feb 2023 17:46:21 +0100 Subject: [PATCH 32/57] Document advertisement via /webrtc-direct --- webrtc/browser-to-browser.md | 43 ++++++++++++++---------------------- 1 file changed, 16 insertions(+), 27 deletions(-) diff --git a/webrtc/browser-to-browser.md b/webrtc/browser-to-browser.md index 52f0c1cb2..034581085 100644 --- a/webrtc/browser-to-browser.md +++ b/webrtc/browser-to-browser.md @@ -6,42 +6,45 @@ ## Motivation -**Hole punching in the browser** - Enable two browsers or a browser and a non-browser node to connect even though one or both are behind a NAT / firewall. +**Hole punching in the browser** + +Browser _A_ wants to connect to Browser node _B_ with the help of server node _R_. +Both _A_ and _B_ can not listen for incoming connections due to the restriction of the browser platform and being behind a NAT and/or firewall. +Note that _A_ and/or _B_ may as well be non-browser nodes behind NATs and/or firewalls. +However, for two non-browser nodes using TCP or QUIC hole punching with [DCUtR] will be the more efficient way to establish a direct connection. On a historical note, this specification replaces the existing [libp2p WebRTC star](https://github.com/libp2p/js-libp2p-webrtc-star) and [libp2p WebRTC direct](https://github.com/libp2p/js-libp2p-webrtc-direct) protocols. ## Connection Establishment -Scenario: Browser _A_ wants to connect to Browser node _B_ with the help of server node _R_. -Both _A_ and _B_ can not listen for incoming connections due to the restriction of the browser platform and being behind a NAT and/or firewall. -Note that _A_ and/or _B_ may as well be non-browser nodes behind NATs and/or firewalls. -However, for two non-browser nodes using TCP or QUIC hole punching with [DCUtR] will be the more efficient way to establish a direct connection. +1. _B_ advertises support for the WebRTC browser-to-browser protocol by appending `/webrtc-direct` to its relayed multiaddr e.g. `/ip6/fe80::883:a581:fff1:833/udp/4001/quic/p2p//p2p-circuit/webrtc-direct/p2p/`. + +2. Upon discovery of _B_'s multiaddress, _A_ knows that _B_ speaks the WebRTC browser-to-browser protocol and knows how to establish a relayed connection to _B_ to run the WebRTC browser-to-browser signaling protocol on top. -1. _A_ and _B_ establish a relayed connection through some protocol, e.g. the Circuit Relay v2 protocol. - The relayed connection is established from _A_ to _B_. +3. _A_ establish a relayed connection to _B_. Note that further steps depend on the relayed connection to be authenticated, i.e. that data sent on the relayed connection can be trusted. -2. _A_ (outbound side of relayed connection) creates an `RTCPeerConnection`. +4. _A_ (outbound side of relayed connection) creates an `RTCPeerConnection`. See [STUN](#stun) section on what STUN servers to configure at creation time. _A_ creates an SDP offer via `RTCPeerConnection.createOffer()`. _A_ initiates the signaling protocol to _B_ via the relayed connection from (1), see [Signaling Protocol](#signaling-protocol) and sends the offer to _B_. -3. _B_ (inbound side of relayed connection) creates an `RTCPeerConnection`. +5. _B_ (inbound side of relayed connection) creates an `RTCPeerConnection`. Again see [STUN](#stun) section on what STUN servers to configure at creation time. _B_ receives _A_'s offer sent in (2) via the signaling protocol stream and provides the offer to its `RTCPeerConnection` via `RTCPeerConnection.setRemoteDescription`. _B_ then creates an answer via `RTCPeerConnection.createAnswer` and sends it to _A_ via the existing signaling protocol stream (see [Signaling Protocol](#signaling-protocol)). -4. _A_ receives _B_'s answer via the signaling protocol stream and sets it locally via `RTCPeerConnection.setRemoteDescription`. +6. _A_ receives _B_'s answer via the signaling protocol stream and sets it locally via `RTCPeerConnection.setRemoteDescription`. -5. _A_ and _B_ send their local ICE candidates via the existing signaling protocol stream. +7. _A_ and _B_ send their local ICE candidates via the existing signaling protocol stream. Both nodes continuously read from the stream, adding incoming remote candidates via `RTCPeerConnection.addIceCandidate()`. -6. On successful establishment of the direct connection, _B_ and _A_ close the signaling protocol stream. +8. On successful establishment of the direct connection, _B_ and _A_ close the signaling protocol stream. On failure _B_ and _A_ reset the signaling protocol stream. Behavior for transferring data on a relayed connection, in the case where the direct connection failed, is out of scope for this specification and dependent on the application. -7. Messages on `RTCDataChannel`s on the established `RTCPeerConnection` are framed using the message framing mechanism described in [multiplexing]. +9. Messages on `RTCDataChannel`s on the established `RTCPeerConnection` are framed using the message framing mechanism described in [multiplexing]. ## STUN @@ -83,20 +86,6 @@ message Message { } ``` -## Open Questions - -- Do we need a mechanism for browsers to advertise support for WebRTC browser-to-browser? - - Say that browser B supports WebRTC browser-to-browser. - B listens via a relay and advertises its relayed address. - A discovers B's relayed address. - At this point A does not know whether B is a browser and thus supports WebRTC browser-to-browser, or whether B is e.g. a laptop potentially supporting TCP and QUIC hole punching via DCUtR but not WebRTC browser-to-browser. - In the latter case, A can not establish a direct connection to B. - - Potential solution would be for B to advertise some protocol after the `/p2p-circuit` within its Multiaddr, e.g. `/ip6//udp/4001/p2p//p2p-circuit/webrtc-direct/p2p/`. - As an alternative, A can discover B's support via the identify protocol on the relayed connection or by optimistically opening a stream using the signaling protocol. - Both of the latter options imply long latency (direct connection + relayed connection + stream establishment / identify exchange) on success and on failure happen at the expense of a wasted relayed connection. - ## FAQ - Why is there no additional Noise handshake needed? From 0a0a30ae678381e0bee29cbf521366ed2f85ea91 Mon Sep 17 00:00:00 2001 From: Max Inden Date: Mon, 27 Feb 2023 16:24:40 +0100 Subject: [PATCH 33/57] Rename to /webrtc-w3c and /webrtc-w3c-signaling --- webrtc/browser-to-browser.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/webrtc/browser-to-browser.md b/webrtc/browser-to-browser.md index 034581085..43bf73453 100644 --- a/webrtc/browser-to-browser.md +++ b/webrtc/browser-to-browser.md @@ -17,7 +17,7 @@ On a historical note, this specification replaces the existing [libp2p WebRTC st ## Connection Establishment -1. _B_ advertises support for the WebRTC browser-to-browser protocol by appending `/webrtc-direct` to its relayed multiaddr e.g. `/ip6/fe80::883:a581:fff1:833/udp/4001/quic/p2p//p2p-circuit/webrtc-direct/p2p/`. +1. _B_ advertises support for the WebRTC browser-to-browser protocol by appending `/webrtc-w3c` to its relayed multiaddr e.g. `/ip6/fe80::883:a581:fff1:833/udp/4001/quic/p2p//p2p-circuit/webrtc-w3c/p2p/`. 2. Upon discovery of _B_'s multiaddress, _A_ knows that _B_ speaks the WebRTC browser-to-browser protocol and knows how to establish a relayed connection to _B_ to run the WebRTC browser-to-browser signaling protocol on top. @@ -64,7 +64,7 @@ As an aside, note that _A_ and _B_ do not need to use the same STUN server in or ## Signaling Protocol -The protocol id is `/webrtc-signaling`. +The protocol id is `/webrtc-w3c-signaling`. Messages are sent prefixed with the message length in bytes, encoded as an unsigned variable length integer as defined by the [multiformats unsigned-varint spec][uvarint-spec]. ``` protobuf From 165bd5256794ac3171bd0e5f7d17caeef8488533 Mon Sep 17 00:00:00 2001 From: Max Inden Date: Mon, 27 Feb 2023 16:29:56 +0100 Subject: [PATCH 34/57] Use webtransport instead of plain quic for relay --- webrtc/browser-to-browser.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webrtc/browser-to-browser.md b/webrtc/browser-to-browser.md index 43bf73453..23d285283 100644 --- a/webrtc/browser-to-browser.md +++ b/webrtc/browser-to-browser.md @@ -17,7 +17,7 @@ On a historical note, this specification replaces the existing [libp2p WebRTC st ## Connection Establishment -1. _B_ advertises support for the WebRTC browser-to-browser protocol by appending `/webrtc-w3c` to its relayed multiaddr e.g. `/ip6/fe80::883:a581:fff1:833/udp/4001/quic/p2p//p2p-circuit/webrtc-w3c/p2p/`. +1. _B_ advertises support for the WebRTC browser-to-browser protocol by appending `/webrtc-w3c` to its relayed multiaddr e.g. `/ip6/fe80::883:a581:fff1:833/udp/4001/quic/webtransport/certhash//p2p//p2p-circuit/webrtc-w3c/p2p/`. 2. Upon discovery of _B_'s multiaddress, _A_ knows that _B_ speaks the WebRTC browser-to-browser protocol and knows how to establish a relayed connection to _B_ to run the WebRTC browser-to-browser signaling protocol on top. From ec68ec3959be2a0914efc4240d09782c62d4cd8e Mon Sep 17 00:00:00 2001 From: Max Inden Date: Thu, 2 Mar 2023 18:21:07 +0100 Subject: [PATCH 35/57] Rename title to WebRTC W3C --- webrtc/browser-to-browser.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webrtc/browser-to-browser.md b/webrtc/browser-to-browser.md index 23d285283..c26af3e77 100644 --- a/webrtc/browser-to-browser.md +++ b/webrtc/browser-to-browser.md @@ -1,4 +1,4 @@ -# WebRTC browser-to-browser +# WebRTC W3C | Lifecycle Stage | Maturity | Status | Latest Revision | |-----------------|---------------|--------|-----------------| From c5b36d21d62b3b5287e9e5a903fb9821d65a015a Mon Sep 17 00:00:00 2001 From: Max Inden Date: Thu, 2 Mar 2023 18:21:27 +0100 Subject: [PATCH 36/57] Introduce naming of w3c in motivation --- webrtc/browser-to-browser.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webrtc/browser-to-browser.md b/webrtc/browser-to-browser.md index c26af3e77..cafc48cda 100644 --- a/webrtc/browser-to-browser.md +++ b/webrtc/browser-to-browser.md @@ -6,7 +6,7 @@ ## Motivation -**Hole punching in the browser** +libp2p transport protocol using the W3C defined WebRTC connection establishment flow, among other things enabling **hole punching in the browser**. Browser _A_ wants to connect to Browser node _B_ with the help of server node _R_. Both _A_ and _B_ can not listen for incoming connections due to the restriction of the browser platform and being behind a NAT and/or firewall. From e119c1da2651a2c03473a7e6e7944b067b3a6bf0 Mon Sep 17 00:00:00 2001 From: Max Inden Date: Thu, 2 Mar 2023 18:24:16 +0100 Subject: [PATCH 37/57] Update webrtc/browser-to-browser.md Co-authored-by: Thomas Eizinger --- webrtc/browser-to-browser.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webrtc/browser-to-browser.md b/webrtc/browser-to-browser.md index cafc48cda..9781bca56 100644 --- a/webrtc/browser-to-browser.md +++ b/webrtc/browser-to-browser.md @@ -19,7 +19,7 @@ On a historical note, this specification replaces the existing [libp2p WebRTC st 1. _B_ advertises support for the WebRTC browser-to-browser protocol by appending `/webrtc-w3c` to its relayed multiaddr e.g. `/ip6/fe80::883:a581:fff1:833/udp/4001/quic/webtransport/certhash//p2p//p2p-circuit/webrtc-w3c/p2p/`. -2. Upon discovery of _B_'s multiaddress, _A_ knows that _B_ speaks the WebRTC browser-to-browser protocol and knows how to establish a relayed connection to _B_ to run the WebRTC browser-to-browser signaling protocol on top. +2. Upon discovery of _B_'s multiaddress, _A_ learns that _B_ supports the WebRTC transport through the (constrained) W3C API and knows how to establish a relayed connection to _B_ to run the `/webrtc-w3c-signaling` protocol on top. 3. _A_ establish a relayed connection to _B_. Note that further steps depend on the relayed connection to be authenticated, i.e. that data sent on the relayed connection can be trusted. From 5a48183236fa13f14e7178a2970e67ae2bfb8a87 Mon Sep 17 00:00:00 2001 From: Max Inden Date: Thu, 2 Mar 2023 18:25:59 +0100 Subject: [PATCH 38/57] Document the origin of `RTCPeerConnection --- webrtc/browser-to-browser.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webrtc/browser-to-browser.md b/webrtc/browser-to-browser.md index 9781bca56..7ceb180be 100644 --- a/webrtc/browser-to-browser.md +++ b/webrtc/browser-to-browser.md @@ -24,7 +24,7 @@ On a historical note, this specification replaces the existing [libp2p WebRTC st 3. _A_ establish a relayed connection to _B_. Note that further steps depend on the relayed connection to be authenticated, i.e. that data sent on the relayed connection can be trusted. -4. _A_ (outbound side of relayed connection) creates an `RTCPeerConnection`. +4. _A_ (outbound side of relayed connection) creates an `RTCPeerConnection` provided by a W3C compliant WebRTC implementation (e.g. a browser). See [STUN](#stun) section on what STUN servers to configure at creation time. _A_ creates an SDP offer via `RTCPeerConnection.createOffer()`. _A_ initiates the signaling protocol to _B_ via the relayed connection from (1), see [Signaling Protocol](#signaling-protocol) and sends the offer to _B_. From 3744342999d84ee68c6b54657bc8b11cd8686e2a Mon Sep 17 00:00:00 2001 From: Max Inden Date: Fri, 3 Mar 2023 14:54:09 +0100 Subject: [PATCH 39/57] Rephrase browser being one example of a constrained env --- webrtc/browser-to-browser.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webrtc/browser-to-browser.md b/webrtc/browser-to-browser.md index 7ceb180be..0a8db5a1a 100644 --- a/webrtc/browser-to-browser.md +++ b/webrtc/browser-to-browser.md @@ -9,7 +9,7 @@ libp2p transport protocol using the W3C defined WebRTC connection establishment flow, among other things enabling **hole punching in the browser**. Browser _A_ wants to connect to Browser node _B_ with the help of server node _R_. -Both _A_ and _B_ can not listen for incoming connections due to the restriction of the browser platform and being behind a NAT and/or firewall. +Both _A_ and _B_ can not listen for incoming connections due to running in a constrained environment (i.e. a browser) with its only transport capability being the W3C WebRTC `RTCPeerConnection` API and being behind a NAT and/or firewall. Note that _A_ and/or _B_ may as well be non-browser nodes behind NATs and/or firewalls. However, for two non-browser nodes using TCP or QUIC hole punching with [DCUtR] will be the more efficient way to establish a direct connection. From 4cca1f16ce898000b8aea8bffd88dfc38bdd31fa Mon Sep 17 00:00:00 2001 From: Max Inden Date: Fri, 3 Mar 2023 17:15:16 +0100 Subject: [PATCH 40/57] Restructure documents with browser-to-server and w3c subdocuments --- webrtc/README.md | 340 ++--------------------- webrtc/browser-to-server.md | 312 +++++++++++++++++++++ webrtc/{browser-to-browser.md => w3c.md} | 4 +- 3 files changed, 337 insertions(+), 319 deletions(-) create mode 100644 webrtc/browser-to-server.md rename webrtc/{browser-to-browser.md => w3c.md} (98%) diff --git a/webrtc/README.md b/webrtc/README.md index 65d2caa86..449c40487 100644 --- a/webrtc/README.md +++ b/webrtc/README.md @@ -2,7 +2,7 @@ | Lifecycle Stage | Maturity | Status | Latest Revision | |-----------------|---------------------------|--------|-----------------| -| 2A | Candidate Recommendation | Active | r0, 2022-10-14 | +| 2A | Candidate Recommendation | Active | r1, 2023-03-03 | Authors: [@mxinden] @@ -11,170 +11,28 @@ Interest Group: [@marten-seemann] [@marten-seemann]: https://github.com/marten-seemann [@mxinden]: https://github.com/mxinden/ - -**Table of Contents** - -- [WebRTC](#webrtc) - - [Motivation](#motivation) - - [Addressing](#addressing) - - [Connection Establishment](#connection-establishment) - - [Browser to public Server](#browser-to-public-server) - - [Multiplexing](#multiplexing) - - [Ordering](#ordering) - - [Head-of-line blocking](#head-of-line-blocking) - - [`RTCDataChannel` negotiation](#rtcdatachannel-negotiation) - - [`RTCDataChannel` label](#rtcdatachannel-label) - - [Connection Security](#connection-security) - - [Previous, ongoing and related work](#previous-ongoing-and-related-work) - - [Test vectors](#test-vectors) - - [Noise prologue](#noise-prologue) - - [Both client and server use SHA-256](#both-client-and-server-use-sha-256) -- [FAQ](#faq) +WebRTC flavors in libp2p: - +1. [WebRTC browser-to-server](./browser-to-server.md) -## Motivation + libp2p transport protocol **without the need for trusted TLS certificates.** + Enable browsers to connect to public server nodes without those server nodes + providing a TLS certificate within the browser's trustchain. Note that we can + not do this today with our Websocket transport as the browser requires the + remote to have a trusted TLS certificate. Nor can we establish a plain TCP or + QUIC connection from within a browser. We can establish a WebTransport + connection from the browser (see [WebTransport + specification](../webtransport)). -1. **No need for trusted TLS certificates.** Enable browsers to connect to - public server nodes without those server nodes providing a TLS certificate - within the browser's trustchain. Note that we can not do this today with our - Websocket transport as the browser requires the remote to have a trusted TLS - certificate. Nor can we establish a plain TCP or QUIC connection from within - a browser. We can establish a WebTransport connection from the browser (see - [WebTransport specification](../webtransport)). +2. [WebRTC W3C](./w3c.md) -## Addressing + libp2p transport protocol using the W3C defined WebRTC connection + establishment flow, among other things enabling **hole punching in the + browser**. -WebRTC multiaddresses are composed of an IP and UDP address component, followed -by `/webrtc` and a multihash of the certificate that the node uses. +## Shared -Examples: -- `/ip4/1.2.3.4/udp/1234/webrtc/certhash//p2p/` -- `/ip6/fe80::1ff:fe23:4567:890a/udp/1234/webrtc/certhash//p2p/` - -The TLS certificate fingerprint in `/certhash` is a -[multibase](https://github.com/multiformats/multibase) encoded -[multihash](https://github.com/multiformats/multihash). - -For compatibility implementations MUST support hash algorithm -[`sha-256`](https://github.com/multiformats/multihash) and base encoding -[`base64url`](https://github.com/multiformats/multibase). Implementations MAY -support other hash algorithms and base encodings, but they may not be able to -connect to all other nodes. - -## Connection Establishment - -### Browser to public Server - -Scenario: Browser _A_ wants to connect to server node _B_ where _B_ is publicly -reachable but _B_ does not have a TLS certificate trusted by _A_. - -1. Server node _B_ generates a TLS certificate, listens on a UDP port and - advertises the corresponding multiaddress (see [#addressing]) through some - external mechanism. - - Given that _B_ is publicly reachable, _B_ acts as a [ICE - Lite](https://www.rfc-editor.org/rfc/rfc5245) agent. It binds to a UDP port - waiting for incoming STUN and SCTP packets and multiplexes based on source IP - and source port. - -2. Browser _A_ discovers server node _B_'s multiaddr, containing _B_'s IP, UDP - port, TLS certificate fingerprint and optionally libp2p peer ID (e.g. - `/ip6/2001:db8::/udp/1234/webrtc/certhash//p2p/`), through some - external mechanism. - -3. _A_ instantiates a `RTCPeerConnection`. See - [`RTCPeerConnection()`](https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/RTCPeerConnection). - - _A_ (i.e. the browser) SHOULD NOT reuse the same certificate across - `RTCPeerConnection`s. Reusing the certificate can be used to identify _A_ - across connections by on-path observers given that WebRTC uses TLS 1.2. - -4. _A_ constructs _B_'s SDP answer locally based on _B_'s multiaddr. - - _A_ generates a random string prefixed with "libp2p+webrtc+v1/". The prefix - allows us to use the ufrag as an upgrade mechanism to role out a new version - of the libp2p WebRTC protocol on a live network. While a hack, this might be - very useful in the future. _A_ sets the string as the username (_ufrag_ or _username fragment_) - and password on the SDP of the remote's answer. - - _A_ MUST set the `a=max-message-size:16384` SDP attribute. See reasoning - [multiplexing](#multiplexing) for rational. - - Finally _A_ sets the remote answer via - [`RTCPeerConnection.setRemoteDescription()`](https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/setRemoteDescription). - -5. _A_ creates a local offer via - [`RTCPeerConnection.createOffer()`](https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/createOffer). - _A_ sets the same username and password on the local offer as done in (4) on - the remote answer. - - _A_ MUST set the `a=max-message-size:16384` SDP attribute. See reasoning - [multiplexing](#multiplexing) for rational. - - Finally _A_ sets the modified offer via - [`RTCPeerConnection.setLocalDescription()`](https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/setLocalDescription). - - Note that this process, oftentimes referred to as "SDP munging" is disallowed - by the specification, but not enforced across the major browsers (Safari, - Firefox, Chrome) due to use-cases in the wild. See also - https://bugs.chromium.org/p/chromium/issues/detail?id=823036 - -6. Once _A_ sets the SDP offer and answer, it will start sending STUN requests - to _B_. _B_ reads the _ufrag_ from the incoming STUN request's _username_ - field. _B_ then infers _A_'s SDP offer using the IP, port, and _ufrag_ of the - request as follows: - - 1. _B_ sets the the `ice-ufrag` and `ice-pwd` equal to the value read from - the `username` field. - - 2. _B_ sets an arbitrary sha-256 digest as the remote fingerprint as it does - not verify fingerprints at this point. - - 3. _B_ sets the connection field (`c`) to the IP and port of the incoming - request `c=IN `. - - 4. _B_ sets the `a=max-message-size:16384` SDP attribute. See reasoning - [multiplexing](#multiplexing) for rational. - - _B_ sets this offer as the remote description. _B_ generates an answer and - sets it as the local description. - - The _ufrag_ in combination with the IP and port of _A_ can be used by _B_ - to identify the connection, i.e. demultiplex incoming UDP datagrams per - incoming connection. - - Note that this step requires _B_ to allocate memory for each incoming STUN - message from _A_. This could be leveraged for a DOS attack where _A_ is - sending many STUN messages with different ufrags using different UDP source - ports, forcing _B_ to allocate a new peer connection for each. _B_ SHOULD - have a rate limiting mechanism in place as a defense measure. See also - https://datatracker.ietf.org/doc/html/rfc5389#section-16.1.2. - -7. _A_ and _B_ execute the DTLS handshake as part of the standard WebRTC - connection establishment. - - At this point _B_ does not know the TLS certificate fingerprint of _A_. Thus - _B_ can not verify _A_'s TLS certificate fingerprint during the DTLS - handshake. Instead _B_ needs to _disable certificate fingerprint - verification_ (see e.g. [Pion's `disableCertificateFingerprintVerification` - option](https://github.com/pion/webrtc/blob/360b0f1745c7244850ed638f423cda716a81cedf/settingengine.go#L62)). - - On success of the DTLS handshake the connection provides confidentiality and - integrity but not authenticity. The latter is guaranteed through the - succeeding Noise handshake. See [Connection Security - section](#connection-security). - -8. Messages on each `RTCDataChannel` are framed using the message - framing mechanism described in [Multiplexing](#multiplexing). - -9. The remote is authenticated via an additional Noise handshake. See - [Connection Security section](#connection-security). - -WebRTC can run both on UDP and TCP. libp2p WebRTC implementations MUST support -UDP and MAY support TCP. - -## Multiplexing +### Multiplexing The WebRTC browser APIs do not support half-closing of streams nor resets of the sending part of streams. @@ -233,14 +91,14 @@ limits"](https://developer.mozilla.org/en-US/docs/Web/API/WebRTC_API/Using_data_ Implementations MAY choose to send smaller messages, e.g. to reduce delays sending _flagged_ messages. -### Ordering +#### Ordering Implementations MAY expose an unordered byte stream abstraction to the user by overriding the default value of `ordered` `true` to `false` when creating a new data channel via [`RTCPeerConnection.createDataChannel`](https://www.w3.org/TR/webrtc/#dom-peerconnection-createdatachannel). -### Head-of-line blocking +#### Head-of-line blocking WebRTC datachannels and the underlying SCTP is message-oriented and not stream-oriented (e.g. see @@ -271,7 +129,7 @@ IPv4 and 1224 bytes on IPv6. Long term we hope to be able to give better recommendations based on real-world experiments. -### `RTCDataChannel` negotiation +#### `RTCDataChannel` negotiation `RTCDataChannel`s are negotiated in-band by the WebRTC user agent (e.g. Firefox, Pion, ...). In other words libp2p WebRTC implementations MUST NOT change the @@ -293,7 +151,7 @@ containing user data without waiting for the reception of the corresponding DATA_CHANNEL_ACK message", thus using `negotiated: false` does not imply an additional round trip for each new `RTCDataChannel`. -### `RTCDataChannel` label +#### `RTCDataChannel` label `RTCPeerConnection.createDataChannel()` requires passing a `label` for the to-be-created `RTCDataChannel`. When calling `createDataChannel` implementations @@ -302,66 +160,6 @@ MUST pass an empty string. When receiving an `RTCDataChannel` via an empty string. This allows future versions of this specification to make use of the `RTCDataChannel` `label` property. -## Connection Security - -Note that the below uses the message framing described in -[multiplexing](#multiplexing). - -While WebRTC offers confidentiality and integrity via TLS, one still needs to -authenticate the remote peer by its libp2p identity. - -After [Connection Establishment](#connection-establishment): - -1. _A_ and _B_ open a WebRTC data channel with `id: 0` and `negotiated: true` - ([`pc.createDataChannel("", {negotiated: true, id: - 0});`](https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/createDataChannel)). - -2. _B_ starts a Noise `XX` handshake on the new channel. See - [noise-libp2p](https://github.com/libp2p/specs/tree/master/noise). - - _A_ and _B_ use the [Noise - Prologue](https://noiseprotocol.org/noise.html#prologue) mechanism. More - specifically _A_ and _B_ set the Noise _Prologue_ to - `` before starting the actual Noise - handshake. `` is the UTF-8 byte representation of the string - `libp2p-webrtc-noise:`. `` is the concatenation - of the two TLS fingerprints of _A_ (Noise handshake responder) and then _B_ - (Noise handshake initiator), in their multihash byte representation. - - On Chrome _A_ can access its TLS certificate fingerprint directly via - `RTCCertificate#getFingerprints`. Firefox does not allow _A_ to do so. Browser - compatibility can be found - [here](https://developer.mozilla.org/en-US/docs/Web/API/RTCCertificate). In - practice, this is not an issue since the fingerprint is embedded in the local - SDP string. - -3. On success of the authentication handshake, the used datachannel is - closed and the plain WebRTC connection is used with its multiplexing - capabilities via datachannels. See [Multiplexing](#multiplexing). - -Note: WebRTC supports different hash functions to hash the TLS certificate (see -https://datatracker.ietf.org/doc/html/rfc8122#section-5). The hash function used -in WebRTC and the hash function used in the multiaddr `/certhash` component MUST -be the same. On mismatch the final Noise handshake MUST fail. - -_A_ knows _B_'s fingerprint hash algorithm through _B_'s multiaddr. _A_ MUST use -the same hash algorithm to calculate the fingerprint of its (i.e. _A_'s) TLS -certificate. _B_ assumes _A_ to use the same hash algorithm it discovers through -_B_'s multiaddr. For now implementations MUST support sha-256. Future iterations -of this specification may add support for other hash algorithms. - -Implementations SHOULD setup all the necessary callbacks (e.g. -[`ondatachannel`](https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/datachannel_event)) -before starting the Noise handshake. This is to avoid scenarios like one where -_A_ initiates a stream before _B_ got a chance to set the `ondatachannel` -callback. This would result in _B_ ignoring all the messages coming from _A_ -targeting that stream. - -Implementations MAY open streams before completion of the Noise handshake. -Applications MUST take special care what application data they send, since at -this point the peer is not yet authenticated. Similarly, the receiving side MAY -accept streams before completion of the handshake. - ## Previous, ongoing and related work - Completed implementations of this specification: @@ -374,68 +172,7 @@ accept streams before completion of the handshake. WASM): https://github.com/wngr/libp2p-webrtc - WebRTC using STUN and TURN: https://github.com/libp2p/js-libp2p-webrtc-star -## Test vectors - -### Noise prologue - -All of these test vectors represent hex-encoded bytes. - -#### Both client and server use SHA-256 - -Here client is _A_ and server is _B_. - -``` -client_fingerprint = "3e79af40d6059617a0d83b83a52ce73b0c1f37a72c6043ad2969e2351bdca870" -server_fingerprint = "30fc9f469c207419dfdd0aab5f27a86c973c94e40548db9375cca2e915973b99" - -prologue = "6c69627032702d7765627274632d6e6f6973653a12203e79af40d6059617a0d83b83a52ce73b0c1f37a72c6043ad2969e2351bdca870122030fc9f469c207419dfdd0aab5f27a86c973c94e40548db9375cca2e915973b99" -``` - -# FAQ - -- _Why exchange the TLS certificate fingerprint in the multiaddr? Why not - base it on the libp2p public key?_ - - Browsers do not allow loading a custom certificate. One can only generate a - certificate via - [rtcpeerconnection-generatecertificate](https://www.w3.org/TR/webrtc/#dom-rtcpeerconnection-generatecertificate). - -- _Why not embed the peer ID in the TLS certificate, thus rendering the - additional "peer certificate" exchange obsolete?_ - - Browsers do not allow editing the properties of the TLS certificate. - -- _How about distributing the multiaddr in a signed peer record, thus rendering - the additional "peer certificate" exchange obsolete?_ - - Signed peer records are not yet rolled out across the many libp2p protocols. - Making the libp2p WebRTC protocol dependent on the former is not deemed worth - it at this point in time. Later versions of the libp2p WebRTC protocol might - adopt this optimization. - - Note, one can role out a new version of the libp2p WebRTC protocol through a - new multiaddr protocol, e.g. `/webrtc-2`. - -- _Why exchange fingerprints in an additional authentication handshake on top of - an established WebRTC connection? Why not only exchange signatures of ones TLS - fingerprints signed with ones libp2p private key on the plain WebRTC - connection?_ - - Once _A_ and _B_ established a WebRTC connection, _A_ sends - `signature_libp2p_a(fingerprint_a)` to _B_ and vice versa. While this has the - benefit of only requring two messages, thus one round trip, it is prone to a - key compromise and replay attack. Say that _E_ is able to attain - `signature_libp2p_a(fingerprint_a)` and somehow compromise _A_'s TLS private - key, _E_ can now impersonate _A_ without knowing _A_'s libp2p private key. - - If one requires the signatures to contain both fingerprints, e.g. - `signature_libp2p_a(fingerprint_a, fingerprint_b)`, the above attack still - works, just that _E_ can only impersonate _A_ when talking to _B_. - - Adding a cryptographic identifier of the unique connection (i.e. session) to - the signature (`signature_libp2p_a(fingerprint_a, fingerprint_b, - connection_identifier)`) would protect against this attack. To the best of our - knowledge the browser does not give us access to such identifier. +## FAQ - _Why use Protobuf for WebRTC message framing. Why not use our own, potentially smaller encoding schema?_ @@ -450,44 +187,11 @@ prologue = "6c69627032702d7765627274632d6e6f6973653a12203e79af40d6059617a0d83b83 going forward. Using Protobuf is consistent with the many other libp2p protocols. These benefits outweigh the drawback of additional overhead. -- _Can a browser know upfront its UDP port which it is listening for incoming - connections on? Does the browser reuse the UDP port across many WebRTC - connections? If that is the case one could connect to any public node, with - the remote telling the local node what port it is perceived on. Thus one could - use libp2p's identify and AutoNAT protocol instead of relying on STUN._ - - No, a browser uses a new UDP port for each `RTCPeerConnection`. - -- _Why not load a remote node's certificate into one's browser trust-store and - then connect e.g. via WebSocket._ - - This would require a mechanism to discover remote node's certificates upfront. - More importantly, this does not scale with the number of connections a typical - peer-to-peer application establishes. - - _Why not use a central TURN servers? Why rely on libp2p's Circuit Relay v2 instead?_ As a peer-to-peer networking library, libp2p should rely as little as possible on central infrastructure. -- _Can an attacker launch an amplification attack with the STUN endpoint of - the server?_ - - We follow the reasoning of the QUIC protocol, namely requiring: - - > an endpoint MUST limit the amount of data it sends to the unvalidated - > address to three times the amount of data received from that address. - - https://datatracker.ietf.org/doc/html/rfc9000#section-8 - - This is the case for STUN response messages which are only slight larger than - the request messages. See also - https://datatracker.ietf.org/doc/html/rfc5389#section-16.1.2. - -- _Why does B start the Noise handshake and not A?_ - - Given that WebRTC uses DTLS 1.2, _B_ is the one that can send data first. - [QUIC RFC]: https://www.rfc-editor.org/rfc/rfc9000.html [uvarint-spec]: https://github.com/multiformats/unsigned-varint diff --git a/webrtc/browser-to-server.md b/webrtc/browser-to-server.md new file mode 100644 index 000000000..3de258596 --- /dev/null +++ b/webrtc/browser-to-server.md @@ -0,0 +1,312 @@ +# WebRTC browser-to-server + +| Lifecycle Stage | Maturity | Status | Latest Revision | +|-----------------|---------------------------|--------|-----------------| +| 2A | Candidate Recommendation | Active | r0, 2022-10-14 | + +Authors: [@mxinden] + +Interest Group: [@marten-seemann] + +[@marten-seemann]: https://github.com/marten-seemann +[@mxinden]: https://github.com/mxinden/ + +## Motivation + +**No need for trusted TLS certificates.** Enable browsers to connect to public +server nodes without those server nodes providing a TLS certificate within the +browser's trustchain. Note that we can not do this today with our Websocket +transport as the browser requires the remote to have a trusted TLS certificate. +Nor can we establish a plain TCP or QUIC connection from within a browser. We +can establish a WebTransport connection from the browser (see [WebTransport +specification](../webtransport)). + +## Addressing + +WebRTC multiaddresses are composed of an IP and UDP address component, followed +by `/webrtc` and a multihash of the certificate that the node uses. + +Examples: +- `/ip4/1.2.3.4/udp/1234/webrtc/certhash//p2p/` +- `/ip6/fe80::1ff:fe23:4567:890a/udp/1234/webrtc/certhash//p2p/` + +The TLS certificate fingerprint in `/certhash` is a +[multibase](https://github.com/multiformats/multibase) encoded +[multihash](https://github.com/multiformats/multihash). + +For compatibility implementations MUST support hash algorithm +[`sha-256`](https://github.com/multiformats/multihash) and base encoding +[`base64url`](https://github.com/multiformats/multibase). Implementations MAY +support other hash algorithms and base encodings, but they may not be able to +connect to all other nodes. + +## Connection Establishment + +### Browser to public Server + +Scenario: Browser _A_ wants to connect to server node _B_ where _B_ is publicly +reachable but _B_ does not have a TLS certificate trusted by _A_. + +1. Server node _B_ generates a TLS certificate, listens on a UDP port and + advertises the corresponding multiaddress (see [#addressing]) through some + external mechanism. + + Given that _B_ is publicly reachable, _B_ acts as a [ICE + Lite](https://www.rfc-editor.org/rfc/rfc5245) agent. It binds to a UDP port + waiting for incoming STUN and SCTP packets and multiplexes based on source IP + and source port. + +2. Browser _A_ discovers server node _B_'s multiaddr, containing _B_'s IP, UDP + port, TLS certificate fingerprint and optionally libp2p peer ID (e.g. + `/ip6/2001:db8::/udp/1234/webrtc/certhash//p2p/`), through some + external mechanism. + +3. _A_ instantiates a `RTCPeerConnection`. See + [`RTCPeerConnection()`](https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/RTCPeerConnection). + + _A_ (i.e. the browser) SHOULD NOT reuse the same certificate across + `RTCPeerConnection`s. Reusing the certificate can be used to identify _A_ + across connections by on-path observers given that WebRTC uses TLS 1.2. + +4. _A_ constructs _B_'s SDP answer locally based on _B_'s multiaddr. + + _A_ generates a random string prefixed with "libp2p+webrtc+v1/". The prefix + allows us to use the ufrag as an upgrade mechanism to role out a new version + of the libp2p WebRTC protocol on a live network. While a hack, this might be + very useful in the future. _A_ sets the string as the username (_ufrag_ or _username fragment_) + and password on the SDP of the remote's answer. + + _A_ MUST set the `a=max-message-size:16384` SDP attribute. See reasoning + [multiplexing] for rational. + + Finally _A_ sets the remote answer via + [`RTCPeerConnection.setRemoteDescription()`](https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/setRemoteDescription). + +5. _A_ creates a local offer via + [`RTCPeerConnection.createOffer()`](https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/createOffer). + _A_ sets the same username and password on the local offer as done in (4) on + the remote answer. + + _A_ MUST set the `a=max-message-size:16384` SDP attribute. See reasoning + [multiplexing] for rational. + + Finally _A_ sets the modified offer via + [`RTCPeerConnection.setLocalDescription()`](https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/setLocalDescription). + + Note that this process, oftentimes referred to as "SDP munging" is disallowed + by the specification, but not enforced across the major browsers (Safari, + Firefox, Chrome) due to use-cases in the wild. See also + https://bugs.chromium.org/p/chromium/issues/detail?id=823036 + +6. Once _A_ sets the SDP offer and answer, it will start sending STUN requests + to _B_. _B_ reads the _ufrag_ from the incoming STUN request's _username_ + field. _B_ then infers _A_'s SDP offer using the IP, port, and _ufrag_ of the + request as follows: + + 1. _B_ sets the the `ice-ufrag` and `ice-pwd` equal to the value read from + the `username` field. + + 2. _B_ sets an arbitrary sha-256 digest as the remote fingerprint as it does + not verify fingerprints at this point. + + 3. _B_ sets the connection field (`c`) to the IP and port of the incoming + request `c=IN `. + + 4. _B_ sets the `a=max-message-size:16384` SDP attribute. See reasoning + [multiplexing] for rational. + + _B_ sets this offer as the remote description. _B_ generates an answer and + sets it as the local description. + + The _ufrag_ in combination with the IP and port of _A_ can be used by _B_ + to identify the connection, i.e. demultiplex incoming UDP datagrams per + incoming connection. + + Note that this step requires _B_ to allocate memory for each incoming STUN + message from _A_. This could be leveraged for a DOS attack where _A_ is + sending many STUN messages with different ufrags using different UDP source + ports, forcing _B_ to allocate a new peer connection for each. _B_ SHOULD + have a rate limiting mechanism in place as a defense measure. See also + https://datatracker.ietf.org/doc/html/rfc5389#section-16.1.2. + +7. _A_ and _B_ execute the DTLS handshake as part of the standard WebRTC + connection establishment. + + At this point _B_ does not know the TLS certificate fingerprint of _A_. Thus + _B_ can not verify _A_'s TLS certificate fingerprint during the DTLS + handshake. Instead _B_ needs to _disable certificate fingerprint + verification_ (see e.g. [Pion's `disableCertificateFingerprintVerification` + option](https://github.com/pion/webrtc/blob/360b0f1745c7244850ed638f423cda716a81cedf/settingengine.go#L62)). + + On success of the DTLS handshake the connection provides confidentiality and + integrity but not authenticity. The latter is guaranteed through the + succeeding Noise handshake. See [Connection Security + section](#connection-security). + +8. Messages on each `RTCDataChannel` are framed using the message + framing mechanism described in [Multiplexing]. + +9. The remote is authenticated via an additional Noise handshake. See + [Connection Security section](#connection-security). + +WebRTC can run both on UDP and TCP. libp2p WebRTC implementations MUST support +UDP and MAY support TCP. + + +## Connection Security + +Note that the below uses the message framing described in +[multiplexing]. + +While WebRTC offers confidentiality and integrity via TLS, one still needs to +authenticate the remote peer by its libp2p identity. + +After [Connection Establishment](#connection-establishment): + +1. _A_ and _B_ open a WebRTC data channel with `id: 0` and `negotiated: true` + ([`pc.createDataChannel("", {negotiated: true, id: + 0});`](https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/createDataChannel)). + +2. _B_ starts a Noise `XX` handshake on the new channel. See + [noise-libp2p](https://github.com/libp2p/specs/tree/master/noise). + + _A_ and _B_ use the [Noise + Prologue](https://noiseprotocol.org/noise.html#prologue) mechanism. More + specifically _A_ and _B_ set the Noise _Prologue_ to + `` before starting the actual Noise + handshake. `` is the UTF-8 byte representation of the string + `libp2p-webrtc-noise:`. `` is the concatenation + of the two TLS fingerprints of _A_ (Noise handshake responder) and then _B_ + (Noise handshake initiator), in their multihash byte representation. + + On Chrome _A_ can access its TLS certificate fingerprint directly via + `RTCCertificate#getFingerprints`. Firefox does not allow _A_ to do so. Browser + compatibility can be found + [here](https://developer.mozilla.org/en-US/docs/Web/API/RTCCertificate). In + practice, this is not an issue since the fingerprint is embedded in the local + SDP string. + +3. On success of the authentication handshake, the used datachannel is + closed and the plain WebRTC connection is used with its multiplexing + capabilities via datachannels. See [Multiplexing]. + +Note: WebRTC supports different hash functions to hash the TLS certificate (see +https://datatracker.ietf.org/doc/html/rfc8122#section-5). The hash function used +in WebRTC and the hash function used in the multiaddr `/certhash` component MUST +be the same. On mismatch the final Noise handshake MUST fail. + +_A_ knows _B_'s fingerprint hash algorithm through _B_'s multiaddr. _A_ MUST use +the same hash algorithm to calculate the fingerprint of its (i.e. _A_'s) TLS +certificate. _B_ assumes _A_ to use the same hash algorithm it discovers through +_B_'s multiaddr. For now implementations MUST support sha-256. Future iterations +of this specification may add support for other hash algorithms. + +Implementations SHOULD setup all the necessary callbacks (e.g. +[`ondatachannel`](https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/datachannel_event)) +before starting the Noise handshake. This is to avoid scenarios like one where +_A_ initiates a stream before _B_ got a chance to set the `ondatachannel` +callback. This would result in _B_ ignoring all the messages coming from _A_ +targeting that stream. + +Implementations MAY open streams before completion of the Noise handshake. +Applications MUST take special care what application data they send, since at +this point the peer is not yet authenticated. Similarly, the receiving side MAY +accept streams before completion of the handshake. + +## Test vectors + +### Noise prologue + +All of these test vectors represent hex-encoded bytes. + +#### Both client and server use SHA-256 + +Here client is _A_ and server is _B_. + +``` +client_fingerprint = "3e79af40d6059617a0d83b83a52ce73b0c1f37a72c6043ad2969e2351bdca870" +server_fingerprint = "30fc9f469c207419dfdd0aab5f27a86c973c94e40548db9375cca2e915973b99" + +prologue = "6c69627032702d7765627274632d6e6f6973653a12203e79af40d6059617a0d83b83a52ce73b0c1f37a72c6043ad2969e2351bdca870122030fc9f469c207419dfdd0aab5f27a86c973c94e40548db9375cca2e915973b99" +``` + +# FAQ + +- _Why exchange the TLS certificate fingerprint in the multiaddr? Why not + base it on the libp2p public key?_ + + Browsers do not allow loading a custom certificate. One can only generate a + certificate via + [rtcpeerconnection-generatecertificate](https://www.w3.org/TR/webrtc/#dom-rtcpeerconnection-generatecertificate). + +- _Why not embed the peer ID in the TLS certificate, thus rendering the + additional "peer certificate" exchange obsolete?_ + + Browsers do not allow editing the properties of the TLS certificate. + +- _How about distributing the multiaddr in a signed peer record, thus rendering + the additional "peer certificate" exchange obsolete?_ + + Signed peer records are not yet rolled out across the many libp2p protocols. + Making the libp2p WebRTC protocol dependent on the former is not deemed worth + it at this point in time. Later versions of the libp2p WebRTC protocol might + adopt this optimization. + + Note, one can role out a new version of the libp2p WebRTC protocol through a + new multiaddr protocol, e.g. `/webrtc-2`. + +- _Why exchange fingerprints in an additional authentication handshake on top of + an established WebRTC connection? Why not only exchange signatures of ones TLS + fingerprints signed with ones libp2p private key on the plain WebRTC + connection?_ + + Once _A_ and _B_ established a WebRTC connection, _A_ sends + `signature_libp2p_a(fingerprint_a)` to _B_ and vice versa. While this has the + benefit of only requring two messages, thus one round trip, it is prone to a + key compromise and replay attack. Say that _E_ is able to attain + `signature_libp2p_a(fingerprint_a)` and somehow compromise _A_'s TLS private + key, _E_ can now impersonate _A_ without knowing _A_'s libp2p private key. + + If one requires the signatures to contain both fingerprints, e.g. + `signature_libp2p_a(fingerprint_a, fingerprint_b)`, the above attack still + works, just that _E_ can only impersonate _A_ when talking to _B_. + + Adding a cryptographic identifier of the unique connection (i.e. session) to + the signature (`signature_libp2p_a(fingerprint_a, fingerprint_b, + connection_identifier)`) would protect against this attack. To the best of our + knowledge the browser does not give us access to such identifier. + +- _Can a browser know upfront its UDP port which it is listening for incoming + connections on? Does the browser reuse the UDP port across many WebRTC + connections? If that is the case one could connect to any public node, with + the remote telling the local node what port it is perceived on. Thus one could + use libp2p's identify and AutoNAT protocol instead of relying on STUN._ + + No, a browser uses a new UDP port for each `RTCPeerConnection`. + +- _Why not load a remote node's certificate into one's browser trust-store and + then connect e.g. via WebSocket._ + + This would require a mechanism to discover remote node's certificates upfront. + More importantly, this does not scale with the number of connections a typical + peer-to-peer application establishes. + +- _Can an attacker launch an amplification attack with the STUN endpoint of + the server?_ + + We follow the reasoning of the QUIC protocol, namely requiring: + + > an endpoint MUST limit the amount of data it sends to the unvalidated + > address to three times the amount of data received from that address. + + https://datatracker.ietf.org/doc/html/rfc9000#section-8 + + This is the case for STUN response messages which are only slight larger than + the request messages. See also + https://datatracker.ietf.org/doc/html/rfc5389#section-16.1.2. + +- _Why does B start the Noise handshake and not A?_ + + Given that WebRTC uses DTLS 1.2, _B_ is the one that can send data first. + +[multiplexing]: ./README.md#multiplexing diff --git a/webrtc/browser-to-browser.md b/webrtc/w3c.md similarity index 98% rename from webrtc/browser-to-browser.md rename to webrtc/w3c.md index 0a8db5a1a..82e0d21f2 100644 --- a/webrtc/browser-to-browser.md +++ b/webrtc/w3c.md @@ -2,7 +2,9 @@ | Lifecycle Stage | Maturity | Status | Latest Revision | |-----------------|---------------|--------|-----------------| -| 1A | Working Draft | Active | r0, 2022-12-15 | +| 1A | Working Draft | Active | r0, 2023-03-03 | + +Authors: [@mxinden] ## Motivation From d63368a82183884f839e183a931cdf2599a73a9b Mon Sep 17 00:00:00 2001 From: Max Inden Date: Fri, 3 Mar 2023 17:23:11 +0100 Subject: [PATCH 41/57] Fix indentation --- webrtc/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/webrtc/README.md b/webrtc/README.md index 449c40487..91008e7b6 100644 --- a/webrtc/README.md +++ b/webrtc/README.md @@ -26,9 +26,9 @@ WebRTC flavors in libp2p: 2. [WebRTC W3C](./w3c.md) - libp2p transport protocol using the W3C defined WebRTC connection - establishment flow, among other things enabling **hole punching in the - browser**. + libp2p transport protocol using the W3C defined WebRTC connection + establishment flow, among other things enabling **hole punching in the + browser**. ## Shared From 25e5774eff4a1268232faefba32aacdc444e83a8 Mon Sep 17 00:00:00 2001 From: Max Inden Date: Fri, 10 Mar 2023 14:30:47 +0100 Subject: [PATCH 42/57] Introduce private-to-private rename --- webrtc/README.md | 7 +++---- webrtc/{w3c.md => private-to-private.md} | 10 +++++----- 2 files changed, 8 insertions(+), 9 deletions(-) rename webrtc/{w3c.md => private-to-private.md} (94%) diff --git a/webrtc/README.md b/webrtc/README.md index 91008e7b6..e4101c5ea 100644 --- a/webrtc/README.md +++ b/webrtc/README.md @@ -24,11 +24,10 @@ WebRTC flavors in libp2p: connection from the browser (see [WebTransport specification](../webtransport)). -2. [WebRTC W3C](./w3c.md) +2. [WebRTC Private-to-Private](./private-to-private.md) - libp2p transport protocol using the W3C defined WebRTC connection - establishment flow, among other things enabling **hole punching in the - browser**. + libp2p transport protocol enabling two private nodes (e.g. two browsers) to + establish a direct connection. ## Shared diff --git a/webrtc/w3c.md b/webrtc/private-to-private.md similarity index 94% rename from webrtc/w3c.md rename to webrtc/private-to-private.md index 82e0d21f2..8c00f708a 100644 --- a/webrtc/w3c.md +++ b/webrtc/private-to-private.md @@ -1,4 +1,4 @@ -# WebRTC W3C +# WebRTC Private-to-Private | Lifecycle Stage | Maturity | Status | Latest Revision | |-----------------|---------------|--------|-----------------| @@ -8,7 +8,7 @@ Authors: [@mxinden] ## Motivation -libp2p transport protocol using the W3C defined WebRTC connection establishment flow, among other things enabling **hole punching in the browser**. +libp2p transport protocol enabling two private nodes (e.g. two browsers) to establish a direct connection. Browser _A_ wants to connect to Browser node _B_ with the help of server node _R_. Both _A_ and _B_ can not listen for incoming connections due to running in a constrained environment (i.e. a browser) with its only transport capability being the W3C WebRTC `RTCPeerConnection` API and being behind a NAT and/or firewall. @@ -19,9 +19,9 @@ On a historical note, this specification replaces the existing [libp2p WebRTC st ## Connection Establishment -1. _B_ advertises support for the WebRTC browser-to-browser protocol by appending `/webrtc-w3c` to its relayed multiaddr e.g. `/ip6/fe80::883:a581:fff1:833/udp/4001/quic/webtransport/certhash//p2p//p2p-circuit/webrtc-w3c/p2p/`. +1. _B_ advertises support for the WebRTC browser-to-browser protocol by appending `/webrtc-private-to-private` to its relayed multiaddr e.g. `/ip6/fe80::883:a581:fff1:833/udp/4001/quic/webtransport/certhash//p2p//p2p-circuit/webrtc-private-to-private/p2p/`. -2. Upon discovery of _B_'s multiaddress, _A_ learns that _B_ supports the WebRTC transport through the (constrained) W3C API and knows how to establish a relayed connection to _B_ to run the `/webrtc-w3c-signaling` protocol on top. +2. Upon discovery of _B_'s multiaddress, _A_ learns that _B_ supports the WebRTC transport through the (constrained) W3C API and knows how to establish a relayed connection to _B_ to run the `/webrtc-signaling` protocol on top. 3. _A_ establish a relayed connection to _B_. Note that further steps depend on the relayed connection to be authenticated, i.e. that data sent on the relayed connection can be trusted. @@ -66,7 +66,7 @@ As an aside, note that _A_ and _B_ do not need to use the same STUN server in or ## Signaling Protocol -The protocol id is `/webrtc-w3c-signaling`. +The protocol id is `/webrtc-signaling`. Messages are sent prefixed with the message length in bytes, encoded as an unsigned variable length integer as defined by the [multiformats unsigned-varint spec][uvarint-spec]. ``` protobuf From e171330864e4cdf1a8e30d4943736190a05cde0b Mon Sep 17 00:00:00 2001 From: Max Inden Date: Thu, 23 Mar 2023 15:30:58 +0100 Subject: [PATCH 43/57] Rename webrtc to webrtc-direct and webrtc-private-to-private to webrtc See https://github.com/multiformats/multiaddr/pull/150/#issuecomment-1468791586 for rational. --- webrtc/README.md | 12 ++++++------ webrtc/{browser-to-server.md => webrtc-direct.md} | 14 +++++++------- webrtc/{private-to-private.md => webrtc.md} | 4 ++-- 3 files changed, 15 insertions(+), 15 deletions(-) rename webrtc/{browser-to-server.md => webrtc-direct.md} (96%) rename webrtc/{private-to-private.md => webrtc.md} (96%) diff --git a/webrtc/README.md b/webrtc/README.md index e4101c5ea..7c515b82f 100644 --- a/webrtc/README.md +++ b/webrtc/README.md @@ -13,7 +13,12 @@ Interest Group: [@marten-seemann] WebRTC flavors in libp2p: -1. [WebRTC browser-to-server](./browser-to-server.md) +1. [WebRTC](./webrtc.md) + + libp2p transport protocol enabling two private nodes (e.g. two browsers) to + establish a direct connection. + +2. [WebRTC Direct](./webrtc-direct.md) libp2p transport protocol **without the need for trusted TLS certificates.** Enable browsers to connect to public server nodes without those server nodes @@ -24,11 +29,6 @@ WebRTC flavors in libp2p: connection from the browser (see [WebTransport specification](../webtransport)). -2. [WebRTC Private-to-Private](./private-to-private.md) - - libp2p transport protocol enabling two private nodes (e.g. two browsers) to - establish a direct connection. - ## Shared ### Multiplexing diff --git a/webrtc/browser-to-server.md b/webrtc/webrtc-direct.md similarity index 96% rename from webrtc/browser-to-server.md rename to webrtc/webrtc-direct.md index 3de258596..d5030ab7b 100644 --- a/webrtc/browser-to-server.md +++ b/webrtc/webrtc-direct.md @@ -1,4 +1,4 @@ -# WebRTC browser-to-server +# WebRTC Direct | Lifecycle Stage | Maturity | Status | Latest Revision | |-----------------|---------------------------|--------|-----------------| @@ -23,12 +23,12 @@ specification](../webtransport)). ## Addressing -WebRTC multiaddresses are composed of an IP and UDP address component, followed -by `/webrtc` and a multihash of the certificate that the node uses. +WebRTC Direct multiaddresses are composed of an IP and UDP address component, followed +by `/webrtc-direct` and a multihash of the certificate that the node uses. Examples: -- `/ip4/1.2.3.4/udp/1234/webrtc/certhash//p2p/` -- `/ip6/fe80::1ff:fe23:4567:890a/udp/1234/webrtc/certhash//p2p/` +- `/ip4/1.2.3.4/udp/1234/webrtc-direct/certhash//p2p/` +- `/ip6/fe80::1ff:fe23:4567:890a/udp/1234/webrtc-direct/certhash//p2p/` The TLS certificate fingerprint in `/certhash` is a [multibase](https://github.com/multiformats/multibase) encoded @@ -58,7 +58,7 @@ reachable but _B_ does not have a TLS certificate trusted by _A_. 2. Browser _A_ discovers server node _B_'s multiaddr, containing _B_'s IP, UDP port, TLS certificate fingerprint and optionally libp2p peer ID (e.g. - `/ip6/2001:db8::/udp/1234/webrtc/certhash//p2p/`), through some + `/ip6/2001:db8::/udp/1234/webrtc-direct/certhash//p2p/`), through some external mechanism. 3. _A_ instantiates a `RTCPeerConnection`. See @@ -253,7 +253,7 @@ prologue = "6c69627032702d7765627274632d6e6f6973653a12203e79af40d6059617a0d83b83 adopt this optimization. Note, one can role out a new version of the libp2p WebRTC protocol through a - new multiaddr protocol, e.g. `/webrtc-2`. + new multiaddr protocol, e.g. `/webrtc-direct-2`. - _Why exchange fingerprints in an additional authentication handshake on top of an established WebRTC connection? Why not only exchange signatures of ones TLS diff --git a/webrtc/private-to-private.md b/webrtc/webrtc.md similarity index 96% rename from webrtc/private-to-private.md rename to webrtc/webrtc.md index 8c00f708a..0796be5e3 100644 --- a/webrtc/private-to-private.md +++ b/webrtc/webrtc.md @@ -1,4 +1,4 @@ -# WebRTC Private-to-Private +# WebRTC | Lifecycle Stage | Maturity | Status | Latest Revision | |-----------------|---------------|--------|-----------------| @@ -19,7 +19,7 @@ On a historical note, this specification replaces the existing [libp2p WebRTC st ## Connection Establishment -1. _B_ advertises support for the WebRTC browser-to-browser protocol by appending `/webrtc-private-to-private` to its relayed multiaddr e.g. `/ip6/fe80::883:a581:fff1:833/udp/4001/quic/webtransport/certhash//p2p//p2p-circuit/webrtc-private-to-private/p2p/`. +1. _B_ advertises support for the WebRTC browser-to-browser protocol by appending `/webrtc` to its relayed multiaddr e.g. `/ip6/fe80::883:a581:fff1:833/udp/4001/quic/webtransport/certhash//p2p//p2p-circuit/webrtc/p2p/`. 2. Upon discovery of _B_'s multiaddress, _A_ learns that _B_ supports the WebRTC transport through the (constrained) W3C API and knows how to establish a relayed connection to _B_ to run the `/webrtc-signaling` protocol on top. From 610a3ddeb9e5f5822d53502c2e31384cf49a9ab5 Mon Sep 17 00:00:00 2001 From: Max Inden Date: Mon, 27 Mar 2023 10:03:10 +0200 Subject: [PATCH 44/57] Rename to "Shared concepts" --- webrtc/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webrtc/README.md b/webrtc/README.md index e0d356079..018576f69 100644 --- a/webrtc/README.md +++ b/webrtc/README.md @@ -29,7 +29,7 @@ WebRTC flavors in libp2p: connection from the browser (see [WebTransport specification](../webtransport)). -## Shared +## Shared concepts ### Multiplexing From 249ff1b1acab6261434634c854f9367722680130 Mon Sep 17 00:00:00 2001 From: Max Inden Date: Mon, 27 Mar 2023 10:05:22 +0200 Subject: [PATCH 45/57] Don't expand on relayed address in example --- webrtc/webrtc.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webrtc/webrtc.md b/webrtc/webrtc.md index 0796be5e3..ef1635c0c 100644 --- a/webrtc/webrtc.md +++ b/webrtc/webrtc.md @@ -19,7 +19,7 @@ On a historical note, this specification replaces the existing [libp2p WebRTC st ## Connection Establishment -1. _B_ advertises support for the WebRTC browser-to-browser protocol by appending `/webrtc` to its relayed multiaddr e.g. `/ip6/fe80::883:a581:fff1:833/udp/4001/quic/webtransport/certhash//p2p//p2p-circuit/webrtc/p2p/`. +1. _B_ advertises support for the WebRTC browser-to-browser protocol by appending `/webrtc` to its relayed multiaddr, meaning it takes the form of `/webrtc/p2p/`. 2. Upon discovery of _B_'s multiaddress, _A_ learns that _B_ supports the WebRTC transport through the (constrained) W3C API and knows how to establish a relayed connection to _B_ to run the `/webrtc-signaling` protocol on top. From 8c4d45055ce264d17fe36347a30157b68bc0fbb3 Mon Sep 17 00:00:00 2001 From: Max Inden Date: Mon, 27 Mar 2023 10:07:35 +0200 Subject: [PATCH 46/57] Remove mention of constrained w3c api --- webrtc/webrtc.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webrtc/webrtc.md b/webrtc/webrtc.md index ef1635c0c..ec9d96230 100644 --- a/webrtc/webrtc.md +++ b/webrtc/webrtc.md @@ -21,7 +21,7 @@ On a historical note, this specification replaces the existing [libp2p WebRTC st 1. _B_ advertises support for the WebRTC browser-to-browser protocol by appending `/webrtc` to its relayed multiaddr, meaning it takes the form of `/webrtc/p2p/`. -2. Upon discovery of _B_'s multiaddress, _A_ learns that _B_ supports the WebRTC transport through the (constrained) W3C API and knows how to establish a relayed connection to _B_ to run the `/webrtc-signaling` protocol on top. +2. Upon discovery of _B_'s multiaddress, _A_ learns that _B_ supports the WebRTC transport and knows how to establish a relayed connection to _B_ to run the `/webrtc-signaling` protocol on top. 3. _A_ establish a relayed connection to _B_. Note that further steps depend on the relayed connection to be authenticated, i.e. that data sent on the relayed connection can be trusted. From ad2549b69f2f253504d25868e15ccbd7e0665b40 Mon Sep 17 00:00:00 2001 From: Max Inden Date: Mon, 27 Mar 2023 10:10:41 +0200 Subject: [PATCH 47/57] Stress that _B_ creates RTCPeerConnection after incoming stream --- webrtc/webrtc.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webrtc/webrtc.md b/webrtc/webrtc.md index ec9d96230..afe87d944 100644 --- a/webrtc/webrtc.md +++ b/webrtc/webrtc.md @@ -31,7 +31,7 @@ On a historical note, this specification replaces the existing [libp2p WebRTC st _A_ creates an SDP offer via `RTCPeerConnection.createOffer()`. _A_ initiates the signaling protocol to _B_ via the relayed connection from (1), see [Signaling Protocol](#signaling-protocol) and sends the offer to _B_. -5. _B_ (inbound side of relayed connection) creates an `RTCPeerConnection`. +5. On reception of the incoming stream, _B_ (inbound side of relayed connection) creates an `RTCPeerConnection`. Again see [STUN](#stun) section on what STUN servers to configure at creation time. _B_ receives _A_'s offer sent in (2) via the signaling protocol stream and provides the offer to its `RTCPeerConnection` via `RTCPeerConnection.setRemoteDescription`. _B_ then creates an answer via `RTCPeerConnection.createAnswer` and sends it to _A_ via the existing signaling protocol stream (see [Signaling Protocol](#signaling-protocol)). From 2b506ab4600a7520c1a7b520efbed0e81b319e95 Mon Sep 17 00:00:00 2001 From: Max Inden Date: Mon, 27 Mar 2023 10:12:50 +0200 Subject: [PATCH 48/57] "Cannot" --- webrtc/webrtc.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/webrtc/webrtc.md b/webrtc/webrtc.md index afe87d944..7a6d0b25c 100644 --- a/webrtc/webrtc.md +++ b/webrtc/webrtc.md @@ -11,7 +11,7 @@ Authors: [@mxinden] libp2p transport protocol enabling two private nodes (e.g. two browsers) to establish a direct connection. Browser _A_ wants to connect to Browser node _B_ with the help of server node _R_. -Both _A_ and _B_ can not listen for incoming connections due to running in a constrained environment (i.e. a browser) with its only transport capability being the W3C WebRTC `RTCPeerConnection` API and being behind a NAT and/or firewall. +Both _A_ and _B_ cannot listen for incoming connections due to running in a constrained environment (i.e. a browser) with its only transport capability being the W3C WebRTC `RTCPeerConnection` API and being behind a NAT and/or firewall. Note that _A_ and/or _B_ may as well be non-browser nodes behind NATs and/or firewalls. However, for two non-browser nodes using TCP or QUIC hole punching with [DCUtR] will be the more efficient way to establish a direct connection. @@ -52,7 +52,7 @@ On a historical note, this specification replaces the existing [libp2p WebRTC st A node needs to discover its public IP and port, which is forwarded to the remote node in order to connect to the local node. On non-browser libp2p nodes doing a hole punch with TCP or QUIC, the libp2p node discovers its public address via the [identify] protocol. -One can not use the [identify] protocol on browser nodes to discover ones public IP and port given that the browser uses a new port for each connection. +One cannot use the [identify] protocol on browser nodes to discover ones public IP and port given that the browser uses a new port for each connection. For example say that the local browser node establishes a WebRTC connection C1 via browser-to-server to a server node and runs the [identify] protocol. The returned observed public port P1 will most likely (depending on the NAT) be a different port than the port observed on another connection C2. The only browser supported mechanism to discover ones public IP and port for a given connection is the non-libp2p protocol STUN. From 01f78a735765fc33ecc25f56287148ebf8aa91de Mon Sep 17 00:00:00 2001 From: Max Inden Date: Mon, 27 Mar 2023 10:18:50 +0200 Subject: [PATCH 49/57] Require A to support B initiating the signaling process --- webrtc/webrtc.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/webrtc/webrtc.md b/webrtc/webrtc.md index 7a6d0b25c..3c87436f6 100644 --- a/webrtc/webrtc.md +++ b/webrtc/webrtc.md @@ -30,6 +30,8 @@ On a historical note, this specification replaces the existing [libp2p WebRTC st See [STUN](#stun) section on what STUN servers to configure at creation time. _A_ creates an SDP offer via `RTCPeerConnection.createOffer()`. _A_ initiates the signaling protocol to _B_ via the relayed connection from (1), see [Signaling Protocol](#signaling-protocol) and sends the offer to _B_. + Note that _A_ being the initiator of the stream is merely a convention preventing both nodes to simultaneously initiate a new connection thus potentially resulting in two WebRTC connections. + _A_ MUST as well be able to handle an incoming signaling protocol stream to support the case where _B_ initiates the signaling process. 5. On reception of the incoming stream, _B_ (inbound side of relayed connection) creates an `RTCPeerConnection`. Again see [STUN](#stun) section on what STUN servers to configure at creation time. From fca22b3ccbcb6065900b313ee9a577b43802b907 Mon Sep 17 00:00:00 2001 From: Max Inden Date: Mon, 27 Mar 2023 10:21:59 +0200 Subject: [PATCH 50/57] Expand on trickle ICE --- webrtc/webrtc.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webrtc/webrtc.md b/webrtc/webrtc.md index 3c87436f6..ec8adf353 100644 --- a/webrtc/webrtc.md +++ b/webrtc/webrtc.md @@ -40,7 +40,7 @@ On a historical note, this specification replaces the existing [libp2p WebRTC st 6. _A_ receives _B_'s answer via the signaling protocol stream and sets it locally via `RTCPeerConnection.setRemoteDescription`. -7. _A_ and _B_ send their local ICE candidates via the existing signaling protocol stream. +7. _A_ and _B_ send their local ICE candidates via the existing signaling protocol stream to enable trickle ICE. Both nodes continuously read from the stream, adding incoming remote candidates via `RTCPeerConnection.addIceCandidate()`. 8. On successful establishment of the direct connection, _B_ and _A_ close the signaling protocol stream. From 669e0c3c48141082f794485c2b0a167e72088d68 Mon Sep 17 00:00:00 2001 From: Max Inden Date: Mon, 27 Mar 2023 10:22:51 +0200 Subject: [PATCH 51/57] Port for a webrtc connection --- webrtc/webrtc.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webrtc/webrtc.md b/webrtc/webrtc.md index ec8adf353..10237d159 100644 --- a/webrtc/webrtc.md +++ b/webrtc/webrtc.md @@ -57,7 +57,7 @@ On non-browser libp2p nodes doing a hole punch with TCP or QUIC, the libp2p node One cannot use the [identify] protocol on browser nodes to discover ones public IP and port given that the browser uses a new port for each connection. For example say that the local browser node establishes a WebRTC connection C1 via browser-to-server to a server node and runs the [identify] protocol. The returned observed public port P1 will most likely (depending on the NAT) be a different port than the port observed on another connection C2. -The only browser supported mechanism to discover ones public IP and port for a given connection is the non-libp2p protocol STUN. +The only browser supported mechanism to discover ones public IP and port for a given WebRTC connection is the non-libp2p protocol STUN. This is why this specification depends on STUN, and thus the availability of one or more STUN servers for _A_ and _B_ to discovery their public addresses. There are various publicly available STUN servers. From 7a2bf0af7aaeecc93d5720cdf866c6b3c25e25cc Mon Sep 17 00:00:00 2001 From: Max Inden Date: Mon, 27 Mar 2023 10:24:13 +0200 Subject: [PATCH 52/57] Reword dedicated STUN --- webrtc/webrtc.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/webrtc/webrtc.md b/webrtc/webrtc.md index 10237d159..1db895025 100644 --- a/webrtc/webrtc.md +++ b/webrtc/webrtc.md @@ -60,8 +60,7 @@ The returned observed public port P1 will most likely (depending on the NAT) be The only browser supported mechanism to discover ones public IP and port for a given WebRTC connection is the non-libp2p protocol STUN. This is why this specification depends on STUN, and thus the availability of one or more STUN servers for _A_ and _B_ to discovery their public addresses. -There are various publicly available STUN servers. -As an alternative one may operate dedicated STUN servers for a given libp2p network. +Implementations MAY use one of the publicly available STUN servers, or deploy a dedicated server for a given libp2p network. Further specification of the usage of STUN is out of scope for this specifitcation. As an aside, note that _A_ and _B_ do not need to use the same STUN server in order to establish a direct WebRTC connection. From 3425f011792094de8c7a9c620e91921690787780 Mon Sep 17 00:00:00 2001 From: Max Inden Date: Mon, 27 Mar 2023 10:25:36 +0200 Subject: [PATCH 53/57] Replace note with not necessary --- webrtc/webrtc.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webrtc/webrtc.md b/webrtc/webrtc.md index 1db895025..d9e23a471 100644 --- a/webrtc/webrtc.md +++ b/webrtc/webrtc.md @@ -63,7 +63,7 @@ This is why this specification depends on STUN, and thus the availability of one Implementations MAY use one of the publicly available STUN servers, or deploy a dedicated server for a given libp2p network. Further specification of the usage of STUN is out of scope for this specifitcation. -As an aside, note that _A_ and _B_ do not need to use the same STUN server in order to establish a direct WebRTC connection. +It is not necessary that _A_ and _B_ do not need to use the same STUN server in order to establish a direct WebRTC connection. ## Signaling Protocol From 554e3db0c251076dfb1396bfc84ea8fca74eff14 Mon Sep 17 00:00:00 2001 From: Max Inden Date: Thu, 30 Mar 2023 11:39:40 +0200 Subject: [PATCH 54/57] Wording on STUN --- webrtc/webrtc.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webrtc/webrtc.md b/webrtc/webrtc.md index d9e23a471..243168b60 100644 --- a/webrtc/webrtc.md +++ b/webrtc/webrtc.md @@ -63,7 +63,7 @@ This is why this specification depends on STUN, and thus the availability of one Implementations MAY use one of the publicly available STUN servers, or deploy a dedicated server for a given libp2p network. Further specification of the usage of STUN is out of scope for this specifitcation. -It is not necessary that _A_ and _B_ do not need to use the same STUN server in order to establish a direct WebRTC connection. +It is not necessary for _A_ and _B_ to use the same STUN server when establishing a WebRTC connection. ## Signaling Protocol From 2cd2f195209d5c4a13458a8966efee55d35e0c3c Mon Sep 17 00:00:00 2001 From: Max Inden Date: Sun, 9 Apr 2023 16:48:04 +0200 Subject: [PATCH 55/57] Fix typo in webrtc/webrtc.md Co-authored-by: Chad Nehemiah --- webrtc/webrtc.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webrtc/webrtc.md b/webrtc/webrtc.md index 243168b60..3b9995566 100644 --- a/webrtc/webrtc.md +++ b/webrtc/webrtc.md @@ -23,7 +23,7 @@ On a historical note, this specification replaces the existing [libp2p WebRTC st 2. Upon discovery of _B_'s multiaddress, _A_ learns that _B_ supports the WebRTC transport and knows how to establish a relayed connection to _B_ to run the `/webrtc-signaling` protocol on top. -3. _A_ establish a relayed connection to _B_. +3. _A_ establishes a relayed connection to _B_. Note that further steps depend on the relayed connection to be authenticated, i.e. that data sent on the relayed connection can be trusted. 4. _A_ (outbound side of relayed connection) creates an `RTCPeerConnection` provided by a W3C compliant WebRTC implementation (e.g. a browser). From 1160982ed318f41e54b1e96c3181c6827a7b07bc Mon Sep 17 00:00:00 2001 From: Max Inden Date: Wed, 12 Apr 2023 09:23:50 +0200 Subject: [PATCH 56/57] Update spec headers - Bump webrtc-direct revision to r1 given the multiaddr change - Move webrtc to lifecycle 2A Candidate Recommendation - Updates dates --- webrtc/README.md | 6 +++--- webrtc/webrtc-direct.md | 2 +- webrtc/webrtc.md | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/webrtc/README.md b/webrtc/README.md index 018576f69..a44d46495 100644 --- a/webrtc/README.md +++ b/webrtc/README.md @@ -1,8 +1,8 @@ # WebRTC -| Lifecycle Stage | Maturity | Status | Latest Revision | -|-----------------|---------------------------|--------|-----------------| -| 2A | Candidate Recommendation | Active | r1, 2023-03-03 | +| Lifecycle Stage | Maturity | Status | Latest Revision | +|-----------------|--------------------------|--------|-----------------| +| 2A | Candidate Recommendation | Active | r1, 2023-04-12 | Authors: [@mxinden] diff --git a/webrtc/webrtc-direct.md b/webrtc/webrtc-direct.md index d5030ab7b..3e7ddd11c 100644 --- a/webrtc/webrtc-direct.md +++ b/webrtc/webrtc-direct.md @@ -2,7 +2,7 @@ | Lifecycle Stage | Maturity | Status | Latest Revision | |-----------------|---------------------------|--------|-----------------| -| 2A | Candidate Recommendation | Active | r0, 2022-10-14 | +| 2A | Candidate Recommendation | Active | r1, 2023-04-12 | Authors: [@mxinden] diff --git a/webrtc/webrtc.md b/webrtc/webrtc.md index 3b9995566..e84e316c2 100644 --- a/webrtc/webrtc.md +++ b/webrtc/webrtc.md @@ -1,8 +1,8 @@ # WebRTC -| Lifecycle Stage | Maturity | Status | Latest Revision | -|-----------------|---------------|--------|-----------------| -| 1A | Working Draft | Active | r0, 2023-03-03 | +| Lifecycle Stage | Maturity | Status | Latest Revision | +|-----------------|--------------------------|--------|-----------------| +| 2A | Candidate Recommendation | Active | r0, 2023-04-12 | Authors: [@mxinden] From 63b141d9fd8f946dc0211c735a83b3afb3c89e60 Mon Sep 17 00:00:00 2001 From: Max Inden Date: Wed, 12 Apr 2023 09:25:29 +0200 Subject: [PATCH 57/57] Signal in root readme that there is more than one webrtc --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8155b8a65..da1b0486c 100644 --- a/README.md +++ b/README.md @@ -99,7 +99,7 @@ see [#465](https://github.com/libp2p/specs/issues/465). - [secio][spec_secio] - SECIO, a transport security protocol for libp2p - [tls][spec_tls] - The libp2p TLS Handshake (TLS 1.3+) - [quic][spec_quic] - The libp2p QUIC Handshake -- [webrtc][spec_webrtc] - The libp2p WebRTC transport +- [webrtc][spec_webrtc] - The libp2p WebRTC transports - [WebTransport][spec_webtransport] - Using WebTransport in libp2p