Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(webrtc): add WebRTC (prev. browser-to-browser) spec #497

Merged
merged 58 commits into from
Apr 12, 2023
Merged
Changes from 20 commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
58acd82
webrtc/: Initialize browser-to-browser specification
mxinden Dec 15, 2022
35841c3
Document that Noise handshake is not required
mxinden Jan 4, 2023
c41007e
Discourage certificate reuse
mxinden Jan 5, 2023
29d166b
Draft signaling protocol
mxinden Jan 5, 2023
5615e2f
Document outstanding role assignment
mxinden Jan 5, 2023
cc1a8f1
Change format to one line per sentence
mxinden Jan 5, 2023
78fae26
Document open question on advertising support in Multiaddr
mxinden Jan 16, 2023
4fa8da4
Extend signaling protocol section and process
mxinden Jan 16, 2023
7da6004
Define role distribution among A and B
mxinden Jan 18, 2023
badcb1f
Detail STUN section
mxinden Jan 18, 2023
d92e673
Document relaying on failure to be out of scope
mxinden Jan 18, 2023
1b86e62
Remove trickle candidate alternative
mxinden Jan 18, 2023
79ee3b0
Document non-browser behind NAT and/or firewall
mxinden Jan 18, 2023
e384839
Minor edits
mxinden Jan 18, 2023
b5d82c4
Mark proto fields as optional
mxinden Jan 18, 2023
6c139b6
Move mention of existing (deprecated) protocols
mxinden Jan 18, 2023
74c1bc0
Document not using DCUtR
mxinden Jan 18, 2023
619e4e6
Fix STUN section link
mxinden Jan 18, 2023
aa62e92
Fix signaling protocol link
mxinden Jan 18, 2023
fa79a13
Add uvarint link
mxinden Jan 18, 2023
f5ea248
refactor(proto): Rename to SDP_{OFFER,ANSWER} and ICE_CANDIDATE
mxinden Jan 23, 2023
39ed458
Update webrtc/browser-to-browser.md
mxinden Jan 23, 2023
2408db9
Use proto3
mxinden Jan 24, 2023
e1e6a0c
Make explicit that A and B might as well be non-browser
mxinden Jan 24, 2023
30b0d53
Document reset on failure
mxinden Jan 24, 2023
ebc3d5c
Remove sub heading implied by document title
mxinden Jan 24, 2023
6406947
Document latency of relayed connection
mxinden Jan 24, 2023
5a9e553
Rename signaling protocol to `/webrtc-signaling`
mxinden Feb 15, 2023
2d6ef30
Contrast to DCUtR protocol for two non-browsers
mxinden Feb 15, 2023
4255246
Reword TLS certificate validation sentence
mxinden Feb 15, 2023
e99d582
Have A initiate the signaling protocol
mxinden Feb 21, 2023
c09392b
Document advertisement via /webrtc-direct
mxinden Feb 21, 2023
0a0a30a
Rename to /webrtc-w3c and /webrtc-w3c-signaling
mxinden Feb 27, 2023
165bd52
Use webtransport instead of plain quic for relay
mxinden Feb 27, 2023
ec68ec3
Rename title to WebRTC W3C
mxinden Mar 2, 2023
c5b36d2
Introduce naming of w3c in motivation
mxinden Mar 2, 2023
e119c1d
Update webrtc/browser-to-browser.md
mxinden Mar 2, 2023
5a48183
Document the origin of `RTCPeerConnection
mxinden Mar 2, 2023
3744342
Rephrase browser being one example of a constrained env
mxinden Mar 3, 2023
4cca1f1
Restructure documents with browser-to-server and w3c subdocuments
mxinden Mar 3, 2023
d63368a
Fix indentation
mxinden Mar 3, 2023
25e5774
Introduce private-to-private rename
mxinden Mar 10, 2023
e171330
Rename webrtc to webrtc-direct and webrtc-private-to-private to webrtc
mxinden Mar 23, 2023
96529cf
Merge branch 'master' of https://github.com/libp2p/specs into webrtc-…
mxinden Mar 23, 2023
610a3dd
Rename to "Shared concepts"
mxinden Mar 27, 2023
249ff1b
Don't expand on relayed address in example
mxinden Mar 27, 2023
8c4d450
Remove mention of constrained w3c api
mxinden Mar 27, 2023
ad2549b
Stress that _B_ creates RTCPeerConnection after incoming stream
mxinden Mar 27, 2023
2b506ab
"Cannot"
mxinden Mar 27, 2023
01f78a7
Require A to support B initiating the signaling process
mxinden Mar 27, 2023
fca22b3
Expand on trickle ICE
mxinden Mar 27, 2023
669e0c3
Port for a webrtc connection
mxinden Mar 27, 2023
7a2bf0a
Reword dedicated STUN
mxinden Mar 27, 2023
3425f01
Replace note with not necessary
mxinden Mar 27, 2023
554e3db
Wording on STUN
mxinden Mar 30, 2023
2cd2f19
Fix typo in webrtc/webrtc.md
mxinden Apr 9, 2023
1160982
Update spec headers
mxinden Apr 12, 2023
63b141d
Signal in root readme that there is more than one webrtc
mxinden Apr 12, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
122 changes: 122 additions & 0 deletions webrtc/browser-to-browser.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
# WebRTC browser-to-browser
mxinden marked this conversation as resolved.
Show resolved Hide resolved

| Lifecycle Stage | Maturity | Status | Latest Revision |
|-----------------|---------------|--------|-----------------|
| 1A | Working Draft | Active | r0, 2022-12-15 |

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

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

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.
mxinden marked this conversation as resolved.
Show resolved Hide resolved

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.
mxinden marked this conversation as resolved.
Show resolved Hide resolved

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](#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](#signaling-protocol)).

4. _B_ receives _A_'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.
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.
mxinden marked this conversation as resolved.
Show resolved Hide resolved

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

## 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.
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.
mxinden marked this conversation as resolved.
Show resolved Hide resolved
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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for adding this section!


## Signaling Protocol

The protocol id is `/webrtc-direct`.
mxinden marked this conversation as resolved.
Show resolved Hide resolved
mxinden marked this conversation as resolved.
Show resolved Hide resolved
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";
mxinden marked this conversation as resolved.
Show resolved Hide resolved

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;
}
mxinden marked this conversation as resolved.
Show resolved Hide resolved

optional Type type = 1;
optional string data = 2;
mxinden marked this conversation as resolved.
Show resolved Hide resolved
}
```

## 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/<RELAY_IP>/udp/4001/p2p/<RELAY_PEER_ID>/p2p-circuit/webrtc-direct/p2p/<B_PEER_ID>`.
mxinden marked this conversation as resolved.
Show resolved Hide resolved
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.
mxinden marked this conversation as resolved.
Show resolved Hide resolved

## 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.
mxinden marked this conversation as resolved.
Show resolved Hide resolved

In contrast, the browser-to-server specification allows exchange of the server's multiaddr, containing the server's TLS certificate fingerprint, over unauthenticated channels.
mxinden marked this conversation as resolved.
Show resolved Hide resolved
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
[uvarint-spec]: https://github.com/multiformats/unsigned-varint