Skip to content

gibme-c/sneakerpp

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

22 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Sneaker++ — Encrypted Peer-to-Peer Mesh Networking

An encrypted peer-to-peer mesh networking library for C++17 providing authenticated encrypted channels over UDP with dynamic peer discovery, NAT traversal, and QUIC-inspired reliable stream transport. Inspired by the simplicity of WireGuard — a single fixed cipher suite, minimal attack surface, no protocol negotiation — applied to mesh networking instead of point-to-point tunnels. Everything you need for secure mesh communication in one place — just #include <sneaker.hpp> and link against sneakerpp.

The API exposes only standard library types — no crypto headers, no platform headers. Under the hood, every packet is encrypted with ChaCha20-Poly1305, authenticated via a full Noise XX handshake over X25519, and padded to a uniform size (1200 bytes baseline, up to 1472 after path MTU discovery) so that an observer cannot distinguish data from chaff. Peer identity is a static Noise public key, and in-tunnel rekey with fresh ephemeral keypairs happens automatically on a configurable interval (default: every two minutes).

Features

Encrypted Transport

  • Noise XX handshake — mutual authentication with forward secrecy (X25519 + ChaChaPoly + BLAKE2b)
  • Uniform-size packets — all UDP datagrams padded to the current path MTU (1200 bytes baseline, up to 1472 after PLPMTUD) by default; observer cannot determine payload size (configurable: disable padding for higher throughput)
  • In-tunnel rekey — fresh ephemeral keypairs every 2 minutes, zero downtime
  • Chaff traffic — configurable random padding packets mask idle peers

QUIC-Inspired Stream Transport

  • Per-channel reliable ordered streams — 128 independent channels (0-127) with byte-stream semantics and length-prefixed message framing
  • BBR congestion control — bandwidth-probing congestion control with STARTUP, DRAIN, PROBE_BW, and PROBE_RTT phases
  • Packet pacing — token-bucket pacer smooths send bursts to reduce loss
  • Loss detection — packet-number-based and time-based loss detection per RFC 9002, with Probe Timeout (PTO)
  • RTT estimation — smoothed RTT, RTT variance, and minimum RTT tracking per RFC 9002 section 5.3
  • Selective ACKs — ACK frames with range encoding for efficient out-of-order acknowledgement
  • Flow control — per-peer (4 MB default) and per-channel (1 MB default) send windows with backpressure signaling
  • Automatic retransmission — lost stream data is re-queued and retransmitted by the congestion controller
  • Path MTU discovery — RFC 8899 PLPMTUD binary-searches between 1200 and 1472 bytes for the largest UDP payload the path supports

Mesh & Peer Management

  • Reputation scoring — peers earn/lose score based on relay behavior, latency, protocol compliance
  • Automatic eviction — low-scoring peers removed to make room for better ones
  • Temporary banning — misbehaving peers banned by IP with configurable duration
  • Peer exchange (PEX) — connected peers share their peer lists (rate-limited, up to 32 entries)
  • Capability filtering — peers advertise capability bits; connections respect them

Discovery & NAT Traversal

  • Domain Generation Algorithm (DGA) — BLAKE2b-derived base32 subdomains across configurable TLDs
  • DNS TXT bootstrap — Ed25519-signed bootstrap records with peer lists
  • LAN multicast — zero-config local peer discovery on 239.255.77.77:7777
  • Manual peers — explicit peer list for known endpoints
  • Introduction protocol — ask a mutual peer to introduce you to someone behind NAT
  • UDP hole punching — symmetric NAT traversal with 200ms probe ticks
  • Relay fallback — capacity-limited relay sessions with 120-second idle timeout

Cross-Platform

  • Linux (GCC, Clang), macOS (AppleClang), Windows (MSVC, MinGW)
  • Hardened compiler flags: /W4 /WX /GS /guard:cf (MSVC), -Wall -Wextra -Wpedantic -Werror -fstack-protector-strong (GCC/Clang)
  • ASLR, DEP, RELRO/NOW, noexecstack linker hardening

Wire Protocol

Every UDP packet follows the same outer format:

┌──────────────────────────────────────────────────────┐
│  Magic "SNKR" (4B) │ pkt_type (1B) │ version (1B)    │  6 bytes cleartext
├──────────────────────────────────────────────────────┤
│  Nonce (8B)                                          │
├──────────────────────────────────────────────────────┤
│  Encrypted payload (variable, up to 1442B)           │  ChaCha20-Poly1305
├──────────────────────────────────────────────────────┤
│  Poly1305 tag (16B)                                  │
├──────────────────────────────────────────────────────┤
│  Padding (to current MTU, when enabled)              │
└──────────────────────────────────────────────────────┘

The 6-byte cleartext header is the only thing visible to a network observer. Everything else — including the inner frame type and payload — is encrypted. When uniform_packet_size is enabled (the default), all packets are padded to the current path MTU (1200 bytes initially, growing up to 1472 as PLPMTUD discovers the path supports larger packets). Disable padding for higher throughput at the cost of leaking payload sizes.

Inside the encrypted payload, frames use a QUIC-inspired format with variable-length integer encoding (RFC 9000 section 16):

STREAM:   [type:1] [channel:1] [offset:varint] [length:varint] [data]
ACK:      [type:1] [largest_acked:varint] [ack_delay:varint] [ranges...]
CONTROL:  [type:1] [length:varint] [payload]

Multiple frames can be packed into a single packet. ACK frames are always written first, followed by control frames, retransmitted stream data, and new stream data (round-robin across channels).

Getting Started

Requirements

  • C++17 compiler (GCC, Clang, or MSVC)
  • CMake 3.10+

Building

git clone --recursive https://github.com/gibme-c/sneakerpp
cd sneakerpp
mkdir -p build && cd build
cmake .. -DCMAKE_BUILD_TYPE=Release
cmake --build . -j$(nproc)

If you already cloned without --recursive:

git submodule update --init --recursive

Using as a Dependency

git submodule add https://github.com/gibme-c/sneakerpp external/sneakerpp
git submodule update --init --recursive

In your CMakeLists.txt:

add_subdirectory(external/sneakerpp)
target_link_libraries(your_target PRIVATE sneakerpp)

Then include the single public header:

#include <sneaker.hpp>

Quick Example

#include <sneaker.hpp>
#include <iostream>

int main()
{
    sneaker::Config config;
    config.protocol_id = "my-app-v1";
    config.listen_port = 9000;
    config.manual_peers = {"192.168.1.50:9000", "10.0.0.2:9000"};

    auto node = sneaker::Node::create(config);

    node.on_message([](const sneaker::PeerId &from, uint8_t channel,
                       const uint8_t *data, size_t len) {
        std::cout << "Got message on channel " << (int)channel
                  << " (" << len << " bytes)\n";
    });

    node.on_peer_event([](const sneaker::PeerId &peer, sneaker::PeerEvent event) {
        if (event == sneaker::PeerEvent::CONNECTED)
            std::cout << "Peer connected\n";
    });

    if (node.start() != sneaker::StartResult::OK)
    {
        std::cerr << "Failed to start node\n";
        return 1;
    }

    // Send to all connected peers on channel 0 (reliable, ordered)
    const uint8_t msg[] = {0x48, 0x65, 0x6C, 0x6C, 0x6F}; // "Hello"
    node.broadcast(msg, sizeof(msg));

    // Send to a specific peer on channel 1
    auto peers = node.connected_peers();
    if (!peers.empty())
        node.send(peers[0].id, msg, sizeof(msg), 1);

    // ... run your application loop ...

    node.shutdown();
}

All sends are reliable and ordered within a channel. Messages are delivered via the stream transport layer with automatic congestion control, loss detection, and retransmission — no manual send_reliable() call needed.

Configuration

All runtime behavior is tunable through sneaker::Config. The values mentioned elsewhere in this README are just the defaults — set them to whatever your application needs.

Networking & Peers

Field Default Description
protocol_id "sneaker-default" Network identifier; different ID = isolated network
listen_port 0 (OS-assigned) UDP port to listen on
target_peer_count 12 Target number of connected peers
max_inbound 32 Maximum inbound connections
max_outbound 12 Maximum outbound connections
max_per_ip 3 Maximum peers per IP address
manual_peers {} Explicit peer endpoints to connect to

Timing & Intervals

Field Default Description
keepalive_interval 25 s PING interval to peers
dead_peer_timeout 120 s No response = peer disconnected
rekey_interval 2 min In-tunnel key rotation with fresh ephemerals
peer_evaluate_interval 30 s Peer scoring evaluation frequency
chaff_interval 200 ms Decoy packet interval (0 = disable chaff)
relay_retry_direct_interval 2 min Retry direct connection for relayed peers

Stream Transport

Field Default Description
max_connection_data 4 MB Per-peer send window (total across all channels)
max_stream_data 1 MB Per-channel send window
max_ack_delay 25 ms Maximum ACK delay before forcing an ACK
max_write_queue_bytes 16 MB Per-peer app-to-IO queue cap

IO & Performance

Field Default Description
socket_recv_buffer_size 4 MB OS socket receive buffer size (0 = OS default)
socket_send_buffer_size 1 MB OS socket send buffer size (0 = OS default)
uniform_packet_size true Pad all packets to current path MTU (disable for higher throughput)

Security & Reputation

Field Default Description
eviction_threshold 30.0 Peer score below which eviction occurs
initial_ban_duration 5 min First-time ban duration (escalates on re-ban)
max_concurrent_handshakes 20 Simultaneous Noise handshakes allowed

NAT & Relay

Field Default Description
hole_punch_timeout 5 s UDP hole punch attempt timeout
max_relayed_connections 3 Concurrent relay sessions
accept_relay_requests true Whether to relay traffic for other peers
proxy_all_traffic false Route all traffic through proxy peers

Discovery

Field Default Description
enable_dga_discovery true Enable DGA-based peer discovery
enable_local_multicast true Enable LAN multicast discovery (239.255.77.77:7777)
dga_tlds .com, .net, .org TLDs to query for DGA domains
dns_resolvers Cloudflare, Google, Quad9 DNS resolver addresses

Threading

Field Default Description
worker_threads 0 (auto) Worker thread count; 0 = CPU count - 1

CMake Options

Option Default Description
BUILD_TESTS OFF Build test binaries
BUILD_TOOLS OFF Build diagnostic tool binaries
FORCE_PORTABLE OFF Disable SIMD backends in crypto submodules
ENABLE_LTO OFF Enable link-time optimization

Architecture

┌─────────────────────────────────┐
│  Public API  (sneaker.hpp)      │  Only standard library types exposed
├─────────────────────────────────┤
│  Mesh Layer  (src/mesh/)        │  Node, peer manager, peer exchange, scoring
├─────────────────────────────────┤
│  NAT Layer   (src/nat/)         │  Introduction, hole punching, relay
├─────────────────────────────────┤
│  Transport   (src/transport/)   │  QUIC-style streams, congestion, loss detection
├─────────────────────────────────┤
│  Noise XX    (src/noise/)       │  Handshake state machine, CipherState
├─────────────────────────────────┤
│  Discovery   (src/discovery/)   │  DGA DNS, multicast, bootstrap
├─────────────────────────────────┤
│  Platform    (src/platform/)    │  Cross-platform socket/threading abstractions
└─────────────────────────────────┘

Each layer depends only on the layers below it. Crypto types never appear above src/noise/. Platform headers never appear above src/platform/. The public API at the top uses only standard library types.

Dependencies

Four crypto libraries included as git submodules under external/:

Library Provides Submodule Branch
ed25519 Ed25519 signatures, X25519 DH, Ristretto255 development
tinyblake BLAKE2b, HMAC-BLAKE2b, PBKDF2 default
tinychacha ChaCha20, Poly1305, ChaCha20-Poly1305 AEAD default
tinysha SHA-256, SHA-384, SHA-512, SHA3, HMAC-SHA, PBKDF2 default

All four are zero-dependency, header+source C++17 libraries with SIMD backends (AVX2, AVX-512, NEON). They are linked as PRIVATE CMake dependencies — their types and symbols never appear in the public API.

Documentation

Detailed documentation for the public API and each internal module:

Guide Contents
include/README.md Public API reference (sneaker.hpp)
src/platform/README.md Cross-platform socket, threading, CSPRNG
src/noise/README.md Noise XX handshake, CipherState, SymmetricState
src/transport/README.md QUIC-style streams, framing, congestion, loss detection, rekey
src/mesh/README.md Node lifecycle, peer management, peer exchange
src/discovery/README.md DGA, DNS bootstrap, LAN multicast, orchestration
src/nat/README.md Introduction protocol, hole punching, relay

License

This library is provided under the BSD-3-Clause license. See LICENSE for details.

About

Encrypted peer-to-peer mesh networking library for C++17 - Noise XX authenticated channels over UDP with BBR congestion control, QUIC-inspired reliable streams, path MTU discovery, NAT traversal, and dynamic peer discovery. Single header, zero external dependencies.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors