quic-reverse
A Rust library for reverse-initiated, multiplexed streams over QUIC.
quic-reverse helps with the "reverse connection" problem: allowing services behind NAT or firewalls to accept incoming connections without exposing a public port. The library handles connection negotiation, stream lifecycle management, and multiplexing while staying out of authentication, certificate management, and application-level protocols.
What can you build with quic-reverse?
quic-reverse is useful whenever a service behind NAT or a firewall needs to accept incoming connections but isn't explicitly exposed to do so. Common use cases include:
- Remote access tools - SSH, RDP, or VNC tunneling through restrictive networks
- IoT device management - Push commands to devices that can only make outbound connections
- Development tunnels - Expose localhost services to the internet (similar to ngrok)
- Edge-to-cloud connectivity - Let edge nodes receive work from a central orchestrator
- Multiplexed service proxies - Route multiple logical services over a single QUIC connection
What quic-reverse handles
- Connection negotiation and feature discovery
- Stream lifecycle (open requests, responses, graceful close)
- Logical stream multiplexing with service-based routing
- Keep-alive and timeout management
What you provide
- The QUIC connection (quic-reverse abstracts over Quinn; you control TLS and certificates)
- Service handlers for incoming stream requests
- Application-level framing for your data streams
Quick Start
# Run the echo server example
# In another terminal, run the echo client
# Output: HELLO WORLD
See Examples for more details and crates/quic-reverse/examples/ for full source code.
Installation
Add quic-reverse to your Cargo.toml:
[]
= "0.1"
The library uses Quinn as the default QUIC implementation. If you need a different transport, disable default features:
[]
= { = "0.1", = false }
Usage
Server (Responder)
The server accepts incoming QUIC connections and handles stream open requests from clients.
use ;
use QuinnConnection;
// Wrap your Quinn connection
let quinn_conn = new;
let config = new.with_agent;
// Create and start the session
let session = new;
let mut handle = session.start.await?;
// Process control messages
loop
Client (Requester)
The client initiates connections and requests streams to specific services.
use ;
use QuinnConnection;
let quinn_conn = new;
let config = new.with_agent;
let session = new;
let mut handle = session.start.await?;
// Request a stream to a service
let = handle.open.await?;
// Use the stream for bidirectional communication
send.write_all.await?;
Architecture
quic-reverse is organized into three crates:
| Crate | Purpose |
|---|---|
quic-reverse |
Public API: Session, Config, Error types |
quic-reverse-control |
Protocol messages, framing, serialization |
quic-reverse-transport |
Transport traits, Quinn adapter, mock transport |
The protocol uses a dedicated control stream for signaling, separate from data streams:
Client Server
│ │
│──── Hello ─────────────────────► │
│◄─── Hello ─────────────────────── │
│──── HelloAck ──────────────────► │
│◄─── HelloAck ──────────────────── │
│ │
│ [Session Ready] │
│ │
│──── OpenRequest ───────────────► │
│◄─── OpenResponse (accept) ─────── │
│◄════ Data Stream ════════════════►│
│ │
See ARCHITECTURE.md for design rationale and PROTOCOL.md for wire format details.
Configuration
Sessions are configured using Config:
use Config;
use Duration;
let config = new
.with_agent
.with_open_timeout
.with_ping_timeout
.with_max_inflight_opens
.with_max_concurrent_streams;
Timeouts
| Setting | Default | Description |
|---|---|---|
open_timeout |
30s | How long to wait for an open request response |
stream_bind_timeout |
10s | How long to wait for the data stream after acceptance |
negotiation_timeout |
30s | How long to wait for the handshake to complete |
ping_timeout |
10s | How long to wait for a pong response |
Examples
The repository includes working examples demonstrating the library:
# Basic example using mock transport
# Multi-service echo server (uses real QUIC)
# Echo client
The echo server demonstrates multiplexing with three services:
echo/plain- Returns input unchangedecho/uppercase- Returns input in uppercaseecho/reverse- Returns input reversed
Error Handling
The library provides structured error types for different failure modes:
use ;
match handle.open.await
Observability
quic-reverse uses the tracing crate for structured logging. Enable tracing in your application:
fmt
.with_max_level
.init;
Log levels follow this convention:
trace- Low-level I/O operationsdebug- Protocol operations and state changesinfo- Session lifecycle eventswarn/error- Problems requiring attention
Documentation
- ARCHITECTURE.md - Design rationale and architectural decisions
- PROTOCOL.md - Wire protocol specification
- Examples - Example documentation
License
Licensed under Apache-2.0.