cloudflare / boringtun

Userspace WireGuard® Implementation in Rust
BSD 3-Clause "New" or "Revised" License
5.92k stars 396 forks source link

Server mode? #314

Open contrun opened 1 year ago

contrun commented 1 year ago

To the best of my knowledge, boringtun is currently only a wireguard client. We can create a new tunnel with https://github.com/cloudflare/boringtun/blob/5f61297bfb198c9eea7d9b3e1bb32bdd36e403f7/boringtun/src/wireguard_ffi.h#L76-L81 . I didn't find any function to listen for incoming wireguard connection. Will server mode be supported?

Noah-Kennedy commented 1 year ago

So, wireguard is a bit weird in that it's not client-server, it's peer-to-peer. This is different from other protocols like OpenVPN.

Wireguard does have a concept of a handshake initiator vs handshake receiver when a tunnel session is established, which provides a way to replicate client-server semantics by having clients be the peers which initiate sessions.

We support any of the peer-to-peer operations in the CLI and the Rust library. The FFI library is a bit messy and I haven't looked at it as much of used it too much unfortunately. It looks like it supports all the P2P stuff as well though.

Which do you care about here, the CLI, the Rust crate, or the FFI?

contrun commented 1 year ago

@Noah-Kennedy Thanks for the explanation. I am trying to build a wireguard server with boringtun and smoltcp (a more usespacy server that terminates tcp and udp sockets and starts new connections like a l4 reverse proxy).

I find some gaps between my understanding and the interfaces boringtun provides. It is my understanding that I need to first listen to the udp socket, and then when a peer initiates a handshake, I call some boringtun function which gives me peers information like public key. I then decide to accept this connection or not.

But it seems to me the entry point of using boringtun api is Tunn::new and the above ffi function new_tunnel, which requires me to have the public key beforehand. I need to create the tunnel first. This must be the entry point for handshare initiator. But my program is the handshake receiver.

I didn't find api for what I have described. Does boringtun support that yet?

Noah-Kennedy commented 1 year ago

So, wireguard assumes that peers already know of each others identities for the purposes of simplifying the protocol. As a result, any key sharing needs to happen outside of the protocol via, for example, an authenticated HTTPS API.

The flow for wireguard when a new handshake initialization packet comes in is to lookup the peer via the public key contained in the handshake initialization packet to find the metadata and state information for that peer, and to then use that to respond to the handshake and handle the receiver side of getting the session up and running.

The information related to the peer that is needed is largely encoded in the Tunn object, so that is the thing you will need to lookup via its cryptographic key. Unfortunately, the cryptokey routing/lookup facilities in boringtun are baked into the implementation of device, which I want to change at some point, so you will have to implement your own lookup table here. The Tunn object, once constructed, can handle handshakes delivered to it. Tunn basically is just the state machine for interacting with a remote peer.

Does that answer your questions @contrun?

contrun commented 1 year ago

@Noah-Kennedy Thank you for your explanation, now I understand better how wireguard works. Still, I don't know how to make a server out of boringtun. Say I have a set of public keys pk1, pk2 ... pkn, I want clients with any corresponding private key to connect to my boringtun instance. What do I need to do? Do I have to create Tunn for all these public keys? Afterwards I added all these Tunn, boringtun can automatically obtain information for those peers on connection initiated?

Noah-Kennedy commented 1 year ago

A Tunn represents your communication with a single remote peer, encapsulating crypto, handshakes, and the whole state machine of communicating with a single peer. You will need a Tunn for each peer.

contrun commented 1 year ago

OK. Thanks a lot. I think pre-allocating a few Tunn for each peer probably is enough for what I want for now. But most ideally, as you said

Unfortunately, the cryptokey routing/lookup facilities in boringtun are baked into the implementation of device, which I want to change at some point, so you will have to implement your own lookup table here.

I wish we have such a dynamic mechanism. Can you give a few hints on how to implement my own lookup table? I think we can open an new issue for that and this issue can be closed.

Noah-Kennedy commented 1 year ago

@contrun You need to be able to do lookups by both receiver index (for transport data packets) and by public key (for handshakes).

b00tkitism commented 1 year ago

@Noah-Kennedy Hi Can we use a unique PrivateIP for clients? like just 172.16.0.2 PrivateIP with multiple public/private keys ?