-
Notifications
You must be signed in to change notification settings - Fork 447
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
Suggestion: circuit-relay-like module, but for negotiating WebRTC #361
Comments
There is a WIP by @mkg20001 to convert webrtc-star to a distributed architecture at libp2p/js-libp2p-webrtc-star#148. It's currently blocked by some needed work on libp2p-crypto libp2p/js-libp2p-crypto#125. |
@mkg20001 , I see you are already one year deep in this. |
@guysv The extra benefit isn't really for upgrading but for esablisihng webrtc connections between browsers. If two browsers are connected to the same bootstrap node that also runs the rendezvous-exchange, then they can connect with each other over webrtc using this method. It intents to be a better replacement for the current socket.io based signaling server, since server selection and discovery is fully dynamic. |
@mkg20001 But we already have a way to communicate over mutual peer, circuit relay. Why not reuse it instead? Especially concidering the fact the the implementation of a request-response API as you are trying to create with randevouz-exchange is facing a blocking issue involving crypto incompetability? Regarding WebRTC integration, the only benefit I see randevouz-exchange has over circuit relay is that randevouz-exchange offers an API for a limited data exchange, where circuit-relay as it is now is unlimited and hence prone to abuse. The unlimited nature of circuit relay is solvable, of course. Whatever the solution, it won't be as generic as having a data exchange API, but it is sufficient for WebRTC. |
Establishing a p2p-circuit connection takes resources and isn't of much use considering we are going to toss that circuit connection once we connect via webrtc anyways. Edit: I understand that this (simple asymmetric crypto) isn't the worlds most secure way of request->response exchanging (in comparison to SECIO), but the other side's identity is going to be verified using SECIO anyways. Most attacks would be of no use (except for the usual "send invalid data, mess with memory, and cause a RCE" kind of vulnerability which would apply to the other, current, webrtc transport as well) |
If the connection has low traffic, why aren't the needed resources low too? |
SECIO takes a few network roundtrips to establish a connection, and also it seems that the browser uses a pretty inefficient way of encrypting the stream (the WebCrypto api has no way to encrypt a stream directly, every buffer must be encrypted separately) Rendezvous exchange reuses the existing connection with the bootstrap server and sends just a single request and a single response packet (unless the discovery mechanism doesn't provide the peer's public key alongside the peers id) |
I see your point, thats indeed a better idea. I saw that you plan on using native JS crypto, how does that compare to WebCrypto in terms of performence? |
@guysv Well, I sort of "had no other choice", as webcrypto PKCS-v1 encryption support seems broken, so I had to go with |
You know, I gave my solution another thought Which brings me to the other question, you could cut the crypto, and release randevouz-exchange in no time, this will be sufficient for WebRTC. Why shouldn't you? |
Modularity. My solution focused on having both an rendezvous exchange transport and a direct exchange transport, with the ability to swap them for one another or pick the best dynamically. In the roadmap (see slide) support for a tiny "router" module that would pick the "best" based on path cost (direct is faster then rendezvous) was mentioned. |
Well i get that polymorphic approach, but I think that if you ran into troubles doing the crypto, why not postponing to a future iteration? (For the record, I tried to dive in, but I don't see myself qualified to take crypto decisions) Decentralized WebRTC transport is a game changer for libp2p web apps and should be ready ASAP. On another topic, On the roadmap you mentioned:
Is there an effort underway? |
Because I thought I could solve it. Then, when I realized I couldn't, I asked for some help. But no one took on the task libp2p/js-libp2p-crypto#125. Also when I asked for a re-review after giving some clarifications on the PR, nobody looked at it. So I deemed the whole endeavor unnecessary. Well, until now libp2p/js-libp2p-webrtc-star#148 (comment). So here we are... And I just happen to no longer have time for that, because I'm currently trying to move out and "get a life", like people always said, while also having an internship with a 99% chance of becoming an apprenticeship. So, sorry but no demos and refactoring for now, unless I somehow get some time freed up in my scheudle.
There is always this "libp2p-thing needs swarm, but swarm needs libp2p-thing initialized" discussion that keeps popping up and then gets "solved" for a specific part of the swarm. Example would be wsStar: It required a peerID for crypto, so discovery modules now have access to just the peerID. |
@jacobheun @mkg20001 So in conclusion, libp2p/js-libp2p-webrtc-star#148 is waiting for the integration of mkg20001/interface-data-exchange into libp2p, but that won't happen until libp2p/js-libp2p-crypto#125 is resolved even though libp2p/js-libp2p-webrtc-star#148 does not need mkg20001/interface-data-exchange to be secure? Bummer. |
Just found out i'm not even the first one to try my approach: dryajov/js-libp2p-webrtc-circuit I really think we should work out interface-data-exchange integration into libp2p before figuring out how to secure it. |
@guysv would you have time to work on that? I'll work on getting crypto unblocked, but it's likely I won't get time to work on that myself until next quarter. If we get the majority of the work complete, we could add in the crypto update before doing a release into something like js-ipfs. |
@jacobheun Sure! There is still an open question about how to include the new WebRTC transport into the libp2p bundle. libp2p-circuit solved this by not being part of the libp2p bundle. Instead, it is burried somewhere inside libp2p-switch object, with its own API. Unless there is some rational reason I missed, this is a hack. If we hit a 2nd transport and needs the same treatment, its time to work out a generic API. I'd suggest passing all transports the swarm obj, but that will break backwards competability. The middle grounds are to create a new "3rd-party-assisted" transports field in the libp2p bundle, where all transports must be passed as classes and are instatiated with the swarm obj, and then concat it to the other transports array. Plus, relayed transports usually have a complex configuration, so this way the transports can be configured easily via the root libp2p config. Thoughts? |
I think something we can do as an intermediary step is to pass For the webrtc star update, I think the challenge is going to be providing the exchange, which needs the switch. We could potentially solve this by providing a transport factory instead of the constructor, and passing it libp2p: const webrtcStarFactory = (libp2p) => {
const exchange = new Exchange({ libp2p })
return new WebRTCStar({ libp2p, exchange })
}
new Libp2p({
modules: {
transport: [ webrtcStarFactory ]
}
}) Longer term there's been discussion of using DI in the past, #130. The big advantage there would really be making the libp2p config simpler, and allow a lot more flexibility for modules, but that potentially moves some complexity back to the modules. |
I got it, looks something like this: function WebRTCStarFactory (options) {
const WebRTCStarProxy = {
construct(target, args) {
options.exchange = new RendezvousExchange(args[0].libp2p.switch, {enableServer: true})
options.exchange.start()
return new target(Object.assign(args[0], options))
}
}
return new Proxy(WebRTCStarClass, WebRTCStarProxy)
}
module.exports = WebRTCStarFactory |
@jacobheun hey, got a working demo, found here https://github.com/guysv/js-libp2p-webrtc-star-demo there's quite some work left, but it looks good so far. |
Added a note, guysv/js-libp2p-webrtc-star-demo@48c274b#r33546307, about an issue with the demo I saw and a potential improvement for the demo as work gets finished up. |
WebRTC signaling is specified here https://github.com/libp2p/specs/blob/master/webrtc/webrtc.md and implemented in https://github.com/libp2p/js-libp2p-webrtc |
So, the best part of circuit-relay, is the fact that it allows to connect nodes where neither can listen for incoming connections.
Unfortunately, running a circuit-relay HOP node is expensive, and by default HOP is turned off.
tl;dr: I hacked js-libp2p-circuit into negotiating WebRTC signals using newly relayed connections, and establish a direct connection between unconnected peers using a helping 3rd party.
Such connection scheme is more considerate of "relay" nodes, because they only need to relay the signaling data, and not the entire connection.
Another plus, is that now browsers should be able to connect to one another directly.
I uploaded the modded js-libp2p-circuit repo and a demo to github:
You can view the diff to the original circuit-relay module in this PR: guysv/js-libp2p-webrtc-poc#1
To run the demo:
npm install
(note: I included a custom package-lock.json in the demo repo so that js-libp2p-switch will use my modded circuit module, if you feel extra paranoid, regenerate the package-lock.json and fill inguysv/js-libp2p-webrtc-poc#webrtc-poc
DEBUG=libp2p:circuit:* node src/hop.js
DEBUG=libp2p:circuit:* node src/listener.js
DEBUG=libp2p:circuit:* node src/dialer.js
The connection is not really usable, but those logs indicate that a WebRTC channel was established, good enough for POC :)
Anyhow, That was a cool experiment. I wrote this issue to hear what you guys think about it. I tried to find material about WebRTC in Libp2p but the only modules I found were webrtc-star, which is a centralized solution, and webrtc-direct, which doesn't really offer interesting features that websockets lack. I think this could be a cool addition to the stack!
The text was updated successfully, but these errors were encountered: