Ricochet is a relay server and C++ client library for bridging UDP/TCP applications that cannot connect directly due to strict firewall rules or NAT constraints.
It works similarly to a TURN relay, but unlike TURN it is not tied to multimedia protocols — it can relay raw UDP or TCP data transparently for any type of application.
A typical scenario is the connection of peers when one of them located behind a symmetric NAT. For success, in that case another peer must have no NAT or Full Cone NAT filtering. If these conditions are not met, then you need a relay.
It is assumed that peers coordinate connection via some rendezvous service and a relay initiator implements Ricochet protocol. There are three steps to make relay:
- The relay initiator requests a relay endpoint from the server, specifying the desired protocol. The server returns the assigned address and port.
- The relay initiator negotiates peer roles (
clientorserver) with peers and passes them the relay endpoint via a rendezvous service. - The relay initiator forwards to the server the description of peers and triggers their connection. The relay accepts the
clientpeer(s), then connects theserverpeer, if there is one, and begins data forwarding.
Peer with bad NAT must implement client role. Endpoint of the server peer must be defined, but the client peer endpoint is used as an accept filter and can be defined partially or undefined at all.
- Full protocol matrix: UDP4, TCP4, UDP6, TCP6
- Security: mutual TLS (mTLS) with certificate-based authentication
- Flexible limits: per-client session cap and global session limit
- Idle timeout: automatic cleanup of idle sessions
- Multi-threading: automatic scaling to the number of CPU cores
The project depends on Boost and OpenSSL. You can download prebuilt packages or build from source:
$ cd ~
$ git clone https://github.com/novemus/ricochet.git
$ cd ~/ricochet
$ cmake -B ./build -DCMAKE_BUILD_TYPE=Release [-DBUILD_SHARED_LIBS=ON] [-DBOOST_ROOT=...] [-DOPENSSL_ROOT_DIR=...]
$ cmake --build ./build --target all
$ cmake --build ./build --target installServer requires mTLS. You can rely on your own PKI infrastructure to issue certificates, or use preshared self-signed certificates. In the latter case, the client can use the server certificate as a CA, and the server must store client certificates in a local repository with the following structure:
repo/
├── owner1/
│ ├── host1/
│ │ └── cert.pem
│ └── host2/
│ └── cert.crt
└── owner2/
└── host1/
└── cert.pemAccepted file extensions: .pem and .crt.
$ ./ricochet --help
$ ./ricochet --bind-addr=0.0.0.0 --bind-port=443 --cert=server.pem --key=server.key --repo=.Server options:
| Option | Default | Description |
|---|---|---|
--address |
0.0.0.0 |
Listen address |
--port |
443 |
Listen port |
--cert |
server.pem |
Server certificate |
--key |
server.key |
Server private key |
--ca |
— | CA for client verification (optional) |
--repo |
. |
Client certificate repository |
--wait |
30 |
Wait for relay connection (seconds) |
--idle |
180 |
Idle relay timeout (seconds) |
--quota |
10 |
Maximum sessions per client |
--limit |
100 |
Maximum concurrent sessions |
--report |
info |
Logging level (trace, debug, info, warning, error, fatal) |
--journal |
— | Path to log file (optional) |
Interface:
#include <boost/asio.hpp>
#include <boost/asio/spawn.hpp>
#include <filesystem>
#include "proto.h"
namespace ricochet {
struct agent
{
virtual ~agent() {}
virtual void assign_relay(boost::asio::yield_context yield, protocol proto, endpoint& relay) = 0;
virtual void launch_relay(boost::asio::yield_context yield, const peer& red, const peer& blue) = 0;
};
std::shared_ptr<agent> create_agent(const boost::asio::ip::tcp::endpoint& server,
const std::filesystem::path& cert,
const std::filesystem::path& key,
const std::filesystem::path& ca);
}Workflow:
- Call
assign_relaywith the desired protocol. The server will return an allocated relay endpoint or throws an exception (unavailable_proto,limit_reached). - Define peer roles (
clientorserver) and forward them with the relay endpoint to both peers via a rendezvous service. - Call
launch_relaywith the description of both peers. The relay will acceptclientpeer(s) and connect to theserverpeer, if there is one, then start transmitting data.
See the header files agent.h and proto.h for details.
Licensed under the Apache License 2.0. You are free to use it for commercial and non-commercial purposes as long as you fulfill its conditions. See LICENSE.txt for details.
Copyright © 2026 Novemus Band. All Rights Reserved.