libp2p / go-libp2p-webrtc-direct

A libp2p transport that enables browser-to-server, and server-to-server, direct communication over WebRTC without requiring signalling servers
MIT License
82 stars 18 forks source link

Other signaling strategies #14

Open backkem opened 5 years ago

backkem commented 5 years ago

go-libp2p-webrtc-direct contains the first step towards WebRTC support in go-ipfs: a port of js-libp2p-webrtc-direct which is the simplest WebRTC transport on the JS side. The drawback of *-libp2p-webrtc-direct is that the signaling is done over HTTP. This requires a direct connection between the peers and therefore can't make use of WebRTC's NAT traversal capabilities.

This ticket aims to explore other signaling strategies. For example, strategies that would also work when both peers are behind a NAT. I think it would be preferable to explore strategies that work across libp2p implementations.

'Centralized' signaling

Signaling over connected peers

rob-deutsch commented 5 years ago

[edit]: my suggestion was nonsense.

cretz commented 5 years ago

What is the goal here? Are y'all only looking to signal from Go-to-Go? Browser-to-Go? The options will be different depending upon what clients you want supported.

backkem commented 5 years ago

Bit of background: My goal is to fill in the missing WebRTC support in go-libp2p. This library contains the first step in that direction: a port of js-libp2p-webrtc-direct which is the simplest WebRTC transport on the JS side. The drawback of webrtc-direct is that the signaling is done over a direct HTTP connection. This requires a direct connection between the peers and therefore can't make use of WebRTC's NAT traversal capabilities.

This ticket aims to explore other signaling strategies. For example, strategies that would also work when both peers are behind a NAT. I think it would be preferable to explore strategies that work across libp2p implementations.

Update: I copied this explainer to the ticket description.

cretz commented 5 years ago

Ah, ok. So to clarify, you need decentralized signaling on both the JS and Go. Part of my experiment was to find something that solved the same. There is a current bug preventing go-ipfs from talking to js-ipfs, but in general IPFS pubsub is the only solution I have found in this space. The only other thing I have considered is building a Go version of gun. Otherwise, there are other DHTs (e.g. bittorrent mainline) mutably available from Go, but the JS side can't write to them.

Also, in general I'd like to see a signaling abstraction project that provided a common API and a collection of signaling backends (not specific to decentralized or anything) that a dev could leverage. I personally moved to centralized a system like https://www.websocket.in/ after realizing there are no easy decentralized ones (I don't want a 600+k js-ipfs blob if I can avoid it and it was struggling to communicate w/ go-ipfs at the time of my experiment).

EDIT: I should add I have had recent success using https://github.com/amark/gun for signaling. I'm not sure it applies to a libp2p project though, it's more of an alternative than complementary.

rob-deutsch commented 5 years ago

So I've been um'ing and ah'ing over this for the last week, and I have some thoughts to throw into the pile. And a suggested way forward...

I want to start by noting that the ultimate problem here can be framed as: PeerA and PeerB exist but can only run web browsers. PeerA wants to create a WebRTC connection with PeerB. We need some way of getting a message to PeerB. This is the ultimate desire, even though we call it "signalling".

Any solution here only makes sense if people will actually use it. Key attributes would be:

So let's simplify this discussion be removing a few options:

Of the remaining options, they can be split into two buckets as follows:

Decentralised

Semi-decentralised

Decentralised

Unfortunately, I think we have to disregard decentralised signalling for now.

IPFS is an awesome decentralised network, and @cretz has done awesome work, but is pubsub ready for primetime? Is it possible to code? Is it sufficiently reliable? I'm unconvinced.

Tor is an interesting option. It allows us to pass messages between two peers. But will Tor allow to web browsers to pass messages between each other? It would need to have HTTP/WebSocket entry points.

Are there other options here?

Semi-decentralised

I am warming up to this idea. The two options above are more similar than we give them credit for, but they ultimately fail on two aspects:

  1. There are no public reliable servers because they are prone to abuse. I don't have a strong desire to operate what's essentially a free data proxy.
  2. libp2p/js-libp2p-webrtc-star is more than just a signalling server, it does peer discover as well. I would say that this is nice, but unnecessary.

Potential solution

I think the easiest way to phrase this is to do something like libp2p/js-libp2p-webrtc-star with a few important differences that make it far more desirable to operate free and open signalling servers:

  1. Standardised SDP. Currently libp2p/js-libp2p-webrtc-star can be abused as a proxy by putting arbitrary data into SDP offers/answers. If we have a standard SDP and peers only submit their ICE candidates then this severely limits the potential for abuse. The signalling server itself can develop the SDP offer/answer with no arbitrary data.
  2. No peer discovery feature.
  3. Describe it as simply a "front" for a WebRTC connection. A libp2p peer simply chooses and registers itself with a service, and then announces to the world essentially something along the lines of "if you want to to talk to me, send your SDP offer to this other peer"
cretz commented 5 years ago

Tor is an interesting option. It allows us to pass messages between two peers. But will Tor allow to web browsers to pass messages between each other? It would need to have HTTP/WebSocket entry points.

If you're in the Tor browser, there are some opportunities, but not much more than a regular browser. I have a PoC that might interest you though it's outdated and there needs to be an app side somewhere: https://github.com/cretz/tor-dht-poc

rob-deutsch commented 5 years ago

Wow @cretz, is there anything you haven't done?!

The thing is that we would want Tor to be access for a regular browser.

backkem commented 5 years ago

@rob-deutsch I agree with your thoughts above. It would be interesting to create a super strict, minimal version of SDP. Some thoughts:

cchudant commented 5 years ago

Could the dialMe protocol (https://github.com/libp2p/specs/pull/64) be used to achieve browser-to-browser p2p?

Here is how that would work:

The dialMe protocol was introduced to handle the case where a peer is behind an impenetrable NAT, and since we need some way to exchange the ICEs between browsers, I think it makes sense to use it here.

backkem commented 5 years ago

@SkyBeastMC It seems the dialMe protocol currently only allows for exchanging a peer id and multi addresses:

message DialMe {
  message Peer {
    required bytes id = 1;    // peer id
    repeated string addrs = 2; // a multiaddr to dial the the peer over
  }
   optional Peer peer = 1;

In order to exchange ICE info we need:

cchudant commented 5 years ago

Oh, I forgot Peer A needed Peer B's SDP answer as well. Should we create another protocol for exchanging SDPs then?

backkem commented 5 years ago

Maybe we can add it to the spec discussion.

guysv commented 4 years ago

@rob-deutsch I'm not sure that it's possible to standardize the SDP dialog. There will always be user-controlled bits in the SDP, hence the signaling server could always be abused into transferring arbitrary data. It might be less obvious, which is not much, but it will also have higher bandwidth overhead, which will might deter attackers.

Anyway, in my opinion, a metered-per-peer signaling service should solve this exploit in a more elegant way.

Also, what about forwarding messages in exchange for POW? 👀

backkem commented 4 years ago

The go-webrtc-aside-transport implements signaling over another transport.

ForestJohnson commented 4 years ago

I'm super interested in using this software (https://github.com/libp2p/go-libp2p-webrtc-direct, https://github.com/Jorropo/go-webrtc-aside-transport). For my use case, I want to establish a connection between two servers that are both potentially behind NAT. For me, routing application traffic through a relay circuit defeats the purpose. However, in my use case it's reasonable to assume that a semi-trusted relay circuit exists for the purposes of exchanging Session Description Protocol (SDP).

I also want to establish a connection between a browser and one of those servers, but that's less important to me initially.

I know it won't work If neither of them can get a public listening port (for example, via upnp), and/or one of them has an inscrutable NAT/firewall. But I'm hoping I can get it to work for the majority of users who are on reasonable "home" networks, for example, not dorm WiFi, not LTE hotspot, and not restrictive corporate firewall.

aarshkshah1992 commented 3 years ago

We have a spec for a direct connection upgrade over Relay: https://github.com/libp2p/specs/pull/173

which has been implemented at: https://github.com/libp2p/go-libp2p/pull/711.

We are also currently exploring the idea of "limited Relays" which meter the bandwidth and time you can use them for (should be just about enough for co-ordinating a hole punch/signalling).

Would be great to use something similar for the signalling so we don't rely on direct HTTP connections.

backkem commented 3 years ago

@aarshkshah1992 Are there plans to 'abstract' the signaling? AKA have the signaling path be injected into transports that require it. That would allow protocols that need signaling to be developed separately from all potential signaling paths. In the case of this repo it would mean we only need go-libp2p-webrtc instead of all the different flavors there are today.

aarshkshah1992 commented 3 years ago

@backkem None for now but will very much keep this in mind when we get to working on decentralised signalling for WebRTC.

o01eg commented 2 years ago

I think it also possible to connect browser node to non-browser node with public IP without any signaling by generating answer SDP. It only requires TLS fingerprint which could be part of address.