libp2p / specs

Technical specifications for the libp2p networking stack
https://libp2p.io
1.54k stars 273 forks source link

Messaging layer #71

Open DavidHuie opened 6 years ago

DavidHuie commented 6 years ago

This issue is aimed at getting discussion started around designing a messaging layer for libp2p. The messaging layer is for encapsulating unreliable transports, like UDP, along with other use cases.

Specifically, I want to use IPFS in order to provide p2p networking for VPN traffic, which is usually implemented over UDP. It is possible to use other transports, although wasteful since TCP is usually also implemented within the networking stack the VPN encapsulates.

We discussed this a bit in https://github.com/ipfs/go-ipfs/issues/3994

From @magik6k:

There are some problems with supporting udp properly:

  • Need to track connections if we want 2-way communication (this isn't that hard, maybe slightly harder if one wants this to be any fast)
  • Libp2p** operates on streams, udp is message oriented. There are 2 ways to solve this:
    • wrap udp packets into messages (basically size+data piped into stream)
    • IMO the wrong way to do this
    • give libp2p the concept of messages
    • There are some plans for message oriented (+unreliable) transports/muxers
      • Can't find any specific issue
    • This would be ideal for udp
    • Also, useful in other parts of libp2p.

cc: @whyrusleeping @magik6k @lgierth

whyrusleeping commented 6 years ago

also cc @Stebalien @diasdavid @bigs @mgoelzer @miyazono

This is a pretty big thing that could have a significant impact on the overall performance of protocols implemented on top of libp2p.

Within message based systems, the main 'choice' to make it reliable vs unreliable. The nice thing though, is that the interfaces shouldnt change between the two, meaning we could bootstrap the interfaces for packet based communications on top of tcp (many ipfs protocols are really just sending messages around), then add in the option later for 'unreliable' backends.

The other thing to consider, is transport security. Libp2p requires that all communications are encrypted peer to peer, so we need a workable encryption scheme (and method for negotiating this, really). Wireguard should work, and we've been meaning to investigate that.

magik6k commented 6 years ago

One thing to note with wireguard is that is would require us to switch to ed25519 keys (which afaik is something we want to do anyway, so there is yet another reason to do that)

https://www.wireguard.com/protocol/#key-exchange-and-data-packets

DavidHuie commented 6 years ago

Wireguard is implemented as a Linux kernel space module, so using it plainly would break libp2p's multi-platform ability. Would we just be using its transport protocol?

It's funny that you guys bring that up, because my VPN project creates a Wireguard mesh network using IPFS for the p2p networking layer. If secure messages were already provided by IPFS, the VPN layer becomes much simpler.

whyrusleeping commented 6 years ago

@DavidHuie wireguard is just a protocol. There is a go implementation IIRC, and we would likely just use that to wrap an 'unencrypted packet transport'. should work just fine cross platform.

On specific platforms would could have optimizations using kernel modules though.

ghost commented 6 years ago

The recently merged transports changes (libp2p/go-libp2p#297 :heart:) have made packet/message stuff significantly easier to reason about. Packet mode can be just another feature of a transport. The transport can support it natively (e.g. UDP or Ethernet), or can gain it by getting passed an upgrader which puts packets into frames on a stream.

The ReadFrom/WriteTo functions should probably live on the Conn interface? After all we do have to shake crypto-hands before doing anything, so it makes sense to represent this state as a connection (also means less stuff to add of course.)

An important thing that we have yet to design is the packet-mode equivalent of multistream - something that lets us negotiate protocols and multiplex them into a single packet connection. There's a very old draft branch of multigram here: https://github.com/multiformats/multigram/tree/draft1

@DavidHuie wireguard is just a protocol. There is a go implementation IIRC, and we would likely just use that to wrap an 'unencrypted packet transport'. should work just fine cross platform.

Yes there's in fact implementations in Rust and JS too. I have only looked at the Go impl, it's pretty badly coupled to the networking and CLI parts, but with a bit of refactoring it looks perfectly usable to me. (/me LOVES wireguard)

patrickmn commented 6 years ago

I'd like to raise another hand for WireGuard. It's very well designed. Linus Torvalds recently called it a "work of art" (compared to OpenVPN and IPSec). And yeah, the kernel mode aspect is a bit tricky, but as @whyrusleeping noted, there are a indeed a few userspace implementations in early development.

I found this thread because I was looking at secio and I was wondering if anyone had tried to implement a middleware using the Noise Protocol Framework, the framework that underlies WireGuard, Signal, WhatsApp, and, apparently, Lightning. I couldn't find any and am trying to decide if I should take a stab at implementing them.

Great intro by its author, Trevor Perrin: https://www.youtube.com/watch?v=3gipxdJ22iM

There are Noise libraries in Go, Rust and JS/Wasm.