2391 lines
40 KiB
Markdown
2391 lines
40 KiB
Markdown
# Multiprotocol UDP Transport Layer
|
||
## Functional & Technical Specification v1.0
|
||
|
||
## 1. Purpose
|
||
|
||
This project is a Linux userspace client/server system for transporting arbitrary UDP datagrams through networks where direct UDP connectivity may be restricted.
|
||
|
||
Its primary initial use case is carrying WireGuard traffic, but the software MUST remain completely protocol-agnostic.
|
||
|
||
The system MUST NOT:
|
||
|
||
- configure WireGuard;
|
||
- inspect WireGuard packets;
|
||
- depend on WireGuard libraries;
|
||
- manipulate WireGuard interfaces;
|
||
- assume anything about the encapsulated UDP protocol.
|
||
|
||
The fundamental abstraction is:
|
||
|
||
> Transport opaque UDP datagrams between two endpoints using the least complex viable carrier.
|
||
|
||
Typical WireGuard deployment:
|
||
|
||
```text
|
||
WireGuard client
|
||
│
|
||
│ UDP
|
||
▼
|
||
127.0.0.1:51821
|
||
│
|
||
▼
|
||
Transport client
|
||
│
|
||
│ selected carrier
|
||
▼
|
||
Internet
|
||
│
|
||
▼
|
||
Transport server
|
||
│
|
||
│ UDP
|
||
▼
|
||
127.0.0.1:51820
|
||
│
|
||
▼
|
||
WireGuard server
|
||
```
|
||
|
||
The exact same setup MUST be usable with any other UDP application.
|
||
|
||
---
|
||
|
||
# 2. Design Principles
|
||
|
||
The project SHALL follow these principles:
|
||
|
||
1. Protocol independence.
|
||
2. Minimal packet transformation.
|
||
3. Datagram semantics preserved wherever possible.
|
||
4. No custom cryptography.
|
||
5. Pluggable transports.
|
||
6. Automatic fallback from simpler transports to more compatible ones.
|
||
7. Low-overhead direct mode.
|
||
8. Multi-client server from the first release.
|
||
9. Unprivileged execution wherever possible.
|
||
10. Human-readable TOML configuration.
|
||
11. Sensible defaults with optional advanced tuning.
|
||
12. Explicit observability and diagnostics.
|
||
13. Architecture prepared for multiple client tunnels in a future release.
|
||
14. Security-sensitive parsing kept small and deterministic.
|
||
15. Transport-specific behavior MUST NOT leak unnecessarily into the core.
|
||
|
||
---
|
||
|
||
# 3. Initial Platform Scope
|
||
|
||
Initial supported operating system:
|
||
|
||
```text
|
||
Linux
|
||
```
|
||
|
||
The project SHALL run entirely in userspace.
|
||
|
||
Root privileges SHALL NOT be required during normal operation.
|
||
|
||
Binding privileged ports such as 443 MAY be accomplished using:
|
||
|
||
```text
|
||
CAP_NET_BIND_SERVICE
|
||
```
|
||
|
||
or an external supervisor/socket mechanism.
|
||
|
||
The daemon SHALL NOT require:
|
||
|
||
```text
|
||
CAP_NET_ADMIN
|
||
CAP_SYS_ADMIN
|
||
```
|
||
|
||
for normal operation.
|
||
|
||
---
|
||
|
||
# 4. Operating Roles
|
||
|
||
The project has two runtime roles:
|
||
|
||
```text
|
||
client
|
||
server
|
||
```
|
||
|
||
They SHOULD initially be exposed through one executable:
|
||
|
||
```bash
|
||
project client --config client.toml
|
||
project server --config server.toml
|
||
```
|
||
|
||
The final project name may replace `project`.
|
||
|
||
---
|
||
|
||
# 5. Client Data Path
|
||
|
||
The client listens on a configured local UDP address.
|
||
|
||
Default example:
|
||
|
||
```text
|
||
127.0.0.1:51821
|
||
```
|
||
|
||
An arbitrary local application sends UDP datagrams to this socket.
|
||
|
||
The client:
|
||
|
||
1. receives the datagram;
|
||
2. associates it with the configured tunnel;
|
||
3. passes it unchanged to the active transport;
|
||
4. transports it to the server;
|
||
5. receives return datagrams;
|
||
6. sends them to the originating local UDP peer.
|
||
|
||
The application payload MUST remain opaque.
|
||
|
||
---
|
||
|
||
# 6. Local Client Peer Handling
|
||
|
||
Although v1 represents one configured tunnel, the local UDP listener MUST track the local source peer.
|
||
|
||
For example:
|
||
|
||
```text
|
||
127.0.0.1:49218 -> 127.0.0.1:51821
|
||
```
|
||
|
||
The most recently active local peer becomes the return destination.
|
||
|
||
For v1, one active local peer per tunnel is sufficient.
|
||
|
||
If packets arrive concurrently from a different local peer, the implementation SHOULD:
|
||
|
||
1. update the active peer;
|
||
2. emit a warning/debug event;
|
||
3. continue operation.
|
||
|
||
This avoids coupling the software to a fixed local source port.
|
||
|
||
Future multi-flow support MAY replace this behavior.
|
||
|
||
---
|
||
|
||
# 7. Server Data Path
|
||
|
||
The server MUST support multiple clients concurrently.
|
||
|
||
Every authenticated client transport session maps to its own backend UDP socket.
|
||
|
||
Example:
|
||
|
||
```text
|
||
Client A
|
||
│
|
||
▼
|
||
Session A
|
||
│
|
||
UDP socket :41001
|
||
│
|
||
├─────────────► backend :51820
|
||
|
||
Client B
|
||
│
|
||
▼
|
||
Session B
|
||
│
|
||
UDP socket :41002
|
||
│
|
||
├─────────────► backend :51820
|
||
|
||
Client C
|
||
│
|
||
▼
|
||
Session C
|
||
│
|
||
UDP socket :41003
|
||
│
|
||
└─────────────► backend :51820
|
||
```
|
||
|
||
Each backend socket provides natural response demultiplexing.
|
||
|
||
The server MUST NOT inspect the backend protocol in order to determine response ownership.
|
||
|
||
---
|
||
|
||
# 8. Backend Target
|
||
|
||
The server configuration defines one UDP backend destination for v1.
|
||
|
||
Example:
|
||
|
||
```toml
|
||
[backend]
|
||
target = "127.0.0.1:51820"
|
||
```
|
||
|
||
Every authenticated client receives an independent UDP socket connected to this backend.
|
||
|
||
Future versions MAY support client-specific backend targets.
|
||
|
||
That feature is explicitly out of scope for v1.
|
||
|
||
---
|
||
|
||
# 9. Transport Architecture
|
||
|
||
The core operates on logical datagrams.
|
||
|
||
A transport session SHALL conceptually expose:
|
||
|
||
```rust
|
||
pub trait TransportSession {
|
||
async fn send_datagram(&self, data: Bytes) -> Result<()>;
|
||
async fn recv_datagram(&self) -> Result<Bytes>;
|
||
async fn close(&self) -> Result<()>;
|
||
}
|
||
```
|
||
|
||
Connection establishment SHALL be separated from established-session behavior.
|
||
|
||
Conceptually:
|
||
|
||
```rust
|
||
pub trait TransportConnector {
|
||
async fn connect(
|
||
&self,
|
||
endpoint: &ServerEndpoint,
|
||
) -> Result<Box<dyn TransportSession>>;
|
||
}
|
||
```
|
||
|
||
The final implementation MAY use associated types, enums, channels, or trait objects depending on ergonomics and performance.
|
||
|
||
The architectural boundary is more important than the exact Rust syntax.
|
||
|
||
---
|
||
|
||
# 10. Supported Transports
|
||
|
||
The planned v1 transport order is:
|
||
|
||
```text
|
||
1. direct UDP
|
||
2. QUIC DATAGRAM
|
||
3. HTTP/3 CONNECT-UDP
|
||
4. TLS/TCP framed fallback
|
||
```
|
||
|
||
All four SHALL share the same logical session API.
|
||
|
||
---
|
||
|
||
# 11. Direct UDP Transport
|
||
|
||
Direct UDP is the lowest-overhead transport.
|
||
|
||
It provides:
|
||
|
||
- native datagram behavior;
|
||
- minimal encapsulation;
|
||
- easiest debugging;
|
||
- lowest latency;
|
||
- baseline performance measurements.
|
||
|
||
It also provides the least firewall traversal capability.
|
||
|
||
Direct UDP MUST therefore have its own lightweight session and authentication protocol.
|
||
|
||
---
|
||
|
||
# 12. QUIC Transport
|
||
|
||
QUIC SHALL be the primary encapsulated datagram transport.
|
||
|
||
Application packets SHALL use QUIC DATAGRAM support rather than QUIC streams.
|
||
|
||
Desired semantics:
|
||
|
||
```text
|
||
application datagram
|
||
│
|
||
▼
|
||
QUIC DATAGRAM
|
||
│
|
||
▼
|
||
QUIC
|
||
│
|
||
▼
|
||
UDP
|
||
```
|
||
|
||
QUIC provides:
|
||
|
||
- TLS 1.3;
|
||
- server authentication;
|
||
- encrypted transport metadata;
|
||
- connection identity;
|
||
- connection state;
|
||
- congestion control;
|
||
- transport-level integrity;
|
||
- migration primitives;
|
||
- keepalive support.
|
||
|
||
The QUIC connection itself constitutes the transport session.
|
||
|
||
No redundant project session identifier SHALL be placed in every QUIC data packet.
|
||
|
||
---
|
||
|
||
# 13. HTTP/3 Transport
|
||
|
||
HTTP/3 SHALL use legitimate HTTP/3 semantics.
|
||
|
||
Preferred architecture:
|
||
|
||
```text
|
||
UDP payload
|
||
│
|
||
▼
|
||
CONNECT-UDP
|
||
│
|
||
▼
|
||
HTTP Datagram
|
||
│
|
||
▼
|
||
HTTP/3
|
||
│
|
||
▼
|
||
QUIC
|
||
```
|
||
|
||
The implementation SHOULD follow the standardized MASQUE CONNECT-UDP architecture rather than inventing an HTTP-shaped custom transport.
|
||
|
||
The purpose of this transport is firewall compatibility, not sophisticated fingerprint impersonation.
|
||
|
||
---
|
||
|
||
# 14. TLS/TCP Fallback
|
||
|
||
Some restrictive networks may block UDP completely.
|
||
|
||
The final fallback SHALL therefore operate over TLS/TCP.
|
||
|
||
Datagrams MUST be explicitly framed because TCP has no message boundaries.
|
||
|
||
Frame format:
|
||
|
||
```text
|
||
+----------------+----------------------+
|
||
| payload length | UDP payload |
|
||
| u16 BE | variable |
|
||
+----------------+----------------------+
|
||
```
|
||
|
||
Maximum payload:
|
||
|
||
```text
|
||
65535 bytes
|
||
```
|
||
|
||
In practice the project SHALL enforce a much lower configurable transport maximum.
|
||
|
||
The fallback MUST preserve original datagram boundaries after reassembly.
|
||
|
||
TCP mode SHALL be considered a compatibility mechanism rather than a performance-optimal transport because head-of-line blocking is unavoidable.
|
||
|
||
---
|
||
|
||
# 15. Automatic Transport Selection
|
||
|
||
Default client configuration:
|
||
|
||
```toml
|
||
[transport]
|
||
mode = "auto"
|
||
```
|
||
|
||
Automatic mode SHALL attempt transports in the following order:
|
||
|
||
```text
|
||
direct_udp
|
||
↓ failure
|
||
quic
|
||
↓ failure
|
||
http3
|
||
↓ failure
|
||
tls_tcp
|
||
```
|
||
|
||
The first working transport is selected.
|
||
|
||
The selected transport remains active until:
|
||
|
||
- the connection fails;
|
||
- the daemon is restarted;
|
||
- the user explicitly requests reconnection;
|
||
- configuration is reloaded requiring reconnection.
|
||
|
||
After failure, the client SHALL begin transport probing again.
|
||
|
||
---
|
||
|
||
# 16. Probe Behavior
|
||
|
||
Default values:
|
||
|
||
```toml
|
||
[transport.auto]
|
||
probe_timeout_ms = 1500
|
||
retries = 2
|
||
```
|
||
|
||
A transport is considered unavailable if connection establishment or authentication fails within the configured limit.
|
||
|
||
Authentication rejection MUST be distinguished from connectivity failure.
|
||
|
||
A rejected credential MUST NOT cause automatic fallback through every transport indefinitely.
|
||
|
||
Instead:
|
||
|
||
```text
|
||
authentication rejected
|
||
↓
|
||
stop probing
|
||
↓
|
||
report configuration/authentication error
|
||
```
|
||
|
||
This prevents invalid credentials from producing unnecessary connection traffic.
|
||
|
||
---
|
||
|
||
# 17. Transport Preference Override
|
||
|
||
Users MAY explicitly select a transport:
|
||
|
||
```toml
|
||
[transport]
|
||
mode = "quic"
|
||
```
|
||
|
||
Valid initial values:
|
||
|
||
```text
|
||
auto
|
||
direct_udp
|
||
quic
|
||
http3
|
||
tls_tcp
|
||
```
|
||
|
||
When a specific transport is configured, automatic fallback SHALL be disabled unless separately enabled in a future version.
|
||
|
||
---
|
||
|
||
# 18. Direct UDP Protocol
|
||
|
||
Direct UDP requires a small project-specific wire protocol.
|
||
|
||
Protocol version:
|
||
|
||
```text
|
||
1
|
||
```
|
||
|
||
All integer fields SHALL use network byte order.
|
||
|
||
All packet parsers MUST reject malformed or truncated messages before allocating large buffers.
|
||
|
||
---
|
||
|
||
# 19. Direct UDP Packet Types
|
||
|
||
Initial packet types:
|
||
|
||
```text
|
||
0x01 HELLO
|
||
0x02 ACCEPT
|
||
0x03 REJECT
|
||
|
||
0x10 DATA
|
||
0x11 KEEPALIVE
|
||
0x12 CLOSE
|
||
```
|
||
|
||
Unknown packet types MUST be ignored or rejected according to protocol context.
|
||
|
||
They MUST NOT cause daemon termination.
|
||
|
||
---
|
||
|
||
# 20. Direct UDP Common Header
|
||
|
||
All direct transport messages use:
|
||
|
||
```text
|
||
+---------+---------+---------+---------+
|
||
| version | type | flags | hdr_len |
|
||
| u8 | u8 | u8 | u8 |
|
||
+---------+---------+---------+---------+
|
||
| |
|
||
| session_id |
|
||
| u64 |
|
||
| |
|
||
+-----------------------------------+
|
||
```
|
||
|
||
Total common header:
|
||
|
||
```text
|
||
12 bytes
|
||
```
|
||
|
||
Fields:
|
||
|
||
```text
|
||
version
|
||
protocol version
|
||
|
||
type
|
||
packet type
|
||
|
||
flags
|
||
type-specific flags
|
||
|
||
hdr_len
|
||
complete header length in bytes
|
||
|
||
session_id
|
||
zero during initial HELLO
|
||
assigned by server after authentication
|
||
```
|
||
|
||
A 64-bit session identifier is selected for v1.
|
||
|
||
It is sufficiently large when generated randomly and checked for collision.
|
||
|
||
---
|
||
|
||
# 21. Session Identifier Generation
|
||
|
||
Session IDs MUST:
|
||
|
||
- be generated by a cryptographically secure random number generator;
|
||
- never use sequential counters;
|
||
- never be predictable;
|
||
- never use zero;
|
||
- be collision-checked against active sessions.
|
||
|
||
If a collision occurs, the server generates another identifier.
|
||
|
||
Session IDs are identifiers, not secrets.
|
||
|
||
Authentication MUST NOT rely solely on knowledge of the session ID.
|
||
|
||
---
|
||
|
||
# 22. Client Identity
|
||
|
||
Each configured client has:
|
||
|
||
```text
|
||
client_id
|
||
shared_secret
|
||
```
|
||
|
||
Example server configuration:
|
||
|
||
```toml
|
||
[[auth.clients]]
|
||
id = "laptop"
|
||
secret = "base64-or-hex-secret"
|
||
|
||
[[auth.clients]]
|
||
id = "server-a"
|
||
secret = "base64-or-hex-secret"
|
||
```
|
||
|
||
Client IDs are not confidential.
|
||
|
||
Secrets MUST have at least 256 bits of entropy.
|
||
|
||
A project CLI SHOULD eventually provide:
|
||
|
||
```bash
|
||
project generate-secret
|
||
```
|
||
|
||
---
|
||
|
||
# 23. Direct UDP HELLO
|
||
|
||
The HELLO packet contains:
|
||
|
||
```text
|
||
common header
|
||
client_id_length u8
|
||
client_id bytes
|
||
timestamp u64
|
||
client_nonce 16 bytes
|
||
authenticator 32 bytes
|
||
```
|
||
|
||
`session_id` SHALL be zero.
|
||
|
||
The authenticator is:
|
||
|
||
```text
|
||
HMAC-SHA256(
|
||
client_secret,
|
||
protocol_version
|
||
|| client_id
|
||
|| timestamp
|
||
|| client_nonce
|
||
)
|
||
```
|
||
|
||
The exact serialization used for the HMAC input MUST be canonical and documented in the protocol implementation.
|
||
|
||
---
|
||
|
||
# 24. Replay Protection
|
||
|
||
The server MUST protect HELLO authentication against replay.
|
||
|
||
A HELLO is accepted only if:
|
||
|
||
```text
|
||
abs(server_time - client_timestamp) <= allowed_clock_skew
|
||
```
|
||
|
||
Default:
|
||
|
||
```text
|
||
60 seconds
|
||
```
|
||
|
||
The server SHALL also retain recently accepted client nonces for the replay window.
|
||
|
||
A repeated:
|
||
|
||
```text
|
||
client_id + client_nonce
|
||
```
|
||
|
||
combination MUST be rejected.
|
||
|
||
Nonce replay state MAY expire after:
|
||
|
||
```text
|
||
2 × allowed_clock_skew
|
||
```
|
||
|
||
---
|
||
|
||
# 25. Direct UDP ACCEPT
|
||
|
||
After successful authentication, the server creates a session and responds:
|
||
|
||
```text
|
||
type ACCEPT
|
||
session_id generated u64
|
||
|
||
server_nonce 16 bytes
|
||
idle_timeout u32 seconds
|
||
max_datagram u16
|
||
authenticator 32 bytes
|
||
```
|
||
|
||
The server authenticator SHALL be:
|
||
|
||
```text
|
||
HMAC-SHA256(
|
||
client_secret,
|
||
session_id
|
||
|| client_nonce
|
||
|| server_nonce
|
||
|| idle_timeout
|
||
|| max_datagram
|
||
)
|
||
```
|
||
|
||
This proves that the ACCEPT originated from a party possessing the configured secret.
|
||
|
||
---
|
||
|
||
# 26. Direct UDP REJECT
|
||
|
||
REJECT SHALL contain a small reason code.
|
||
|
||
Example codes:
|
||
|
||
```text
|
||
0x01 unsupported_version
|
||
0x02 unknown_client
|
||
0x03 authentication_failed
|
||
0x04 replay_detected
|
||
0x05 server_busy
|
||
0x06 rate_limited
|
||
```
|
||
|
||
Detailed authentication information MUST NOT be returned.
|
||
|
||
For example, an unknown client and an invalid HMAC MAY both be externally represented as:
|
||
|
||
```text
|
||
authentication_failed
|
||
```
|
||
|
||
if reducing information leakage is preferred.
|
||
|
||
---
|
||
|
||
# 27. Direct DATA Packets
|
||
|
||
DATA packets SHALL use:
|
||
|
||
```text
|
||
common header
|
||
sequence u32
|
||
auth_tag 16 bytes
|
||
payload remaining bytes
|
||
```
|
||
|
||
Sequence numbers are included.
|
||
|
||
They provide:
|
||
|
||
- replay protection;
|
||
- diagnostics;
|
||
- loss measurement;
|
||
- duplicate detection;
|
||
- future protocol extensibility.
|
||
|
||
They MUST NOT be used to reorder packets.
|
||
|
||
The transport preserves the natural UDP arrival order.
|
||
|
||
---
|
||
|
||
# 28. Direct Session Authentication
|
||
|
||
Direct UDP DATA packets require integrity/authentication.
|
||
|
||
A per-session key SHALL be derived after the handshake.
|
||
|
||
Conceptually:
|
||
|
||
```text
|
||
session_key = HKDF-SHA256(
|
||
client_secret,
|
||
client_nonce || server_nonce || session_id
|
||
)
|
||
```
|
||
|
||
The implementation SHALL use a well-established Rust cryptographic library.
|
||
|
||
The project SHALL NOT implement HMAC, HKDF, or MAC primitives manually.
|
||
|
||
---
|
||
|
||
# 29. DATA Authentication Tag
|
||
|
||
Each DATA packet SHALL carry a truncated authentication tag.
|
||
|
||
Recommended:
|
||
|
||
```text
|
||
HMAC-SHA256 truncated to 128 bits
|
||
```
|
||
|
||
The MAC covers:
|
||
|
||
```text
|
||
version
|
||
type
|
||
flags
|
||
session_id
|
||
sequence
|
||
payload
|
||
```
|
||
|
||
A 128-bit tag provides ample integrity protection while keeping packet overhead manageable.
|
||
|
||
Unauthenticated DATA packets MUST be discarded before forwarding.
|
||
|
||
---
|
||
|
||
# 30. Direct DATA Overhead
|
||
|
||
Approximate direct data overhead:
|
||
|
||
```text
|
||
common header 12 bytes
|
||
sequence 4 bytes
|
||
auth tag 16 bytes
|
||
--------------------------
|
||
total 32 bytes
|
||
```
|
||
|
||
The design favors simple, robust parsing over saving a handful of bytes.
|
||
|
||
Future protocol versions MAY reduce overhead if profiling shows a meaningful benefit.
|
||
|
||
---
|
||
|
||
# 31. Sequence Numbers
|
||
|
||
Each direction SHALL maintain an independent 32-bit sequence counter.
|
||
|
||
Example:
|
||
|
||
```text
|
||
client -> server counter
|
||
server -> client counter
|
||
```
|
||
|
||
Initial value SHALL be random.
|
||
|
||
Sequence numbers increment modulo `2^32`.
|
||
|
||
Replay protection SHALL use a sliding receive window.
|
||
|
||
Recommended window:
|
||
|
||
```text
|
||
1024 packets
|
||
```
|
||
|
||
Packets may arrive out of order within this window.
|
||
|
||
Already-seen sequence numbers MUST be dropped.
|
||
|
||
Packets older than the replay window MUST be dropped.
|
||
|
||
---
|
||
|
||
# 32. NAT Rebinding
|
||
|
||
Direct UDP sessions MUST tolerate client NAT rebinding.
|
||
|
||
The server SHALL NOT permanently bind session identity to:
|
||
|
||
```text
|
||
source IP + source port
|
||
```
|
||
|
||
Instead:
|
||
|
||
1. receive packet;
|
||
2. parse session ID;
|
||
3. verify packet authentication;
|
||
4. verify sequence/replay protection;
|
||
5. if valid, update the session's current peer address.
|
||
|
||
Therefore:
|
||
|
||
```text
|
||
192.0.2.20:43871
|
||
```
|
||
|
||
may become:
|
||
|
||
```text
|
||
192.0.2.20:51203
|
||
```
|
||
|
||
without renegotiating the session.
|
||
|
||
An attacker cannot redirect the session merely by spoofing its session ID because a valid packet MAC is also required.
|
||
|
||
---
|
||
|
||
# 33. KEEPALIVE
|
||
|
||
Direct transport KEEPALIVE messages SHALL use the same session authentication mechanism as DATA messages.
|
||
|
||
They carry:
|
||
|
||
```text
|
||
common header
|
||
sequence
|
||
auth_tag
|
||
```
|
||
|
||
with no application payload.
|
||
|
||
Default interval:
|
||
|
||
```text
|
||
15 seconds
|
||
```
|
||
|
||
Keepalive MAY be disabled.
|
||
|
||
Keepalives count as session activity.
|
||
|
||
---
|
||
|
||
# 34. CLOSE
|
||
|
||
CLOSE SHALL be authenticated.
|
||
|
||
The receiver SHOULD immediately release the associated session.
|
||
|
||
Loss of a CLOSE packet is harmless because idle timeout remains authoritative.
|
||
|
||
---
|
||
|
||
# 35. Session Timeout
|
||
|
||
Default idle timeout:
|
||
|
||
```text
|
||
120 seconds
|
||
```
|
||
|
||
A session is active when an authenticated:
|
||
|
||
```text
|
||
DATA
|
||
KEEPALIVE
|
||
```
|
||
|
||
packet is received.
|
||
|
||
Expired sessions SHALL:
|
||
|
||
1. close their backend socket;
|
||
2. release memory;
|
||
3. remove replay state;
|
||
4. increment expiration metrics.
|
||
|
||
---
|
||
|
||
# 36. QUIC and HTTP/3 Authentication
|
||
|
||
TLS authenticates the server but does not necessarily authenticate the client.
|
||
|
||
QUIC and HTTP/3 transports SHALL therefore use the same logical:
|
||
|
||
```text
|
||
client_id
|
||
shared_secret
|
||
```
|
||
|
||
credentials as direct mode.
|
||
|
||
Authentication occurs once after transport establishment.
|
||
|
||
It SHALL use a challenge-response protocol based on HMAC rather than directly sending the shared secret.
|
||
|
||
Conceptually:
|
||
|
||
```text
|
||
server -> random challenge
|
||
|
||
client -> client_id
|
||
client_nonce
|
||
HMAC(secret, challenge || client_nonce || client_id)
|
||
|
||
server -> authenticated
|
||
```
|
||
|
||
The exact representation MAY use:
|
||
|
||
- a QUIC control stream;
|
||
- an HTTP request;
|
||
- a dedicated initial protocol message.
|
||
|
||
Application DATA MUST NOT be accepted before authentication completes.
|
||
|
||
---
|
||
|
||
# 37. TLS/TCP Authentication
|
||
|
||
TLS/TCP SHALL use the same challenge-response client authentication mechanism.
|
||
|
||
This gives all transports one conceptual authentication model:
|
||
|
||
```text
|
||
server authenticated by TLS where applicable
|
||
client authenticated by project shared secret
|
||
```
|
||
|
||
---
|
||
|
||
# 38. Future Authentication
|
||
|
||
The architecture SHOULD permit later introduction of:
|
||
|
||
```text
|
||
mTLS
|
||
public-key client identity
|
||
short-lived credentials
|
||
external authentication
|
||
```
|
||
|
||
without altering the core datagram API.
|
||
|
||
These are not required for v1.
|
||
|
||
---
|
||
|
||
# 39. DoS and Resource Protection
|
||
|
||
The server MUST assume that its public listeners receive hostile traffic.
|
||
|
||
It SHALL implement:
|
||
|
||
```text
|
||
maximum active sessions
|
||
maximum sessions per source IP
|
||
handshake timeout
|
||
authentication rate limiting
|
||
maximum authentication attempts per source
|
||
maximum datagram size
|
||
idle session timeout
|
||
maximum pending handshakes
|
||
```
|
||
|
||
Defaults SHOULD be conservative.
|
||
|
||
Example:
|
||
|
||
```toml
|
||
[limits]
|
||
max_sessions = 1024
|
||
max_sessions_per_ip = 32
|
||
max_pending_handshakes = 256
|
||
handshake_timeout_ms = 3000
|
||
```
|
||
|
||
Limits MUST be configurable.
|
||
|
||
---
|
||
|
||
# 40. Allocation Policy
|
||
|
||
Expensive resources MUST NOT be allocated before authentication where avoidable.
|
||
|
||
In particular, the server SHOULD NOT open a backend UDP socket until client authentication succeeds.
|
||
|
||
Desired order:
|
||
|
||
```text
|
||
receive handshake
|
||
↓
|
||
cheap validation
|
||
↓
|
||
authentication
|
||
↓
|
||
rate-limit check
|
||
↓
|
||
session allocation
|
||
↓
|
||
backend socket creation
|
||
```
|
||
|
||
---
|
||
|
||
# 41. MTU and Datagram Size
|
||
|
||
The project SHALL treat transport datagram size as a first-class capability.
|
||
|
||
Every active transport session exposes:
|
||
|
||
```text
|
||
max_datagram_size
|
||
```
|
||
|
||
The core SHALL reject application datagrams larger than this value.
|
||
|
||
Initial behavior:
|
||
|
||
```text
|
||
oversized datagram
|
||
↓
|
||
drop
|
||
↓
|
||
increment counter
|
||
↓
|
||
debug/warn log
|
||
```
|
||
|
||
The project SHALL NOT implement application-layer fragmentation in v1.
|
||
|
||
---
|
||
|
||
# 42. Recommended Initial Datagram Limit
|
||
|
||
A conservative default application payload limit SHOULD begin around:
|
||
|
||
```text
|
||
1200 bytes
|
||
```
|
||
|
||
and later be refined using transport/path information.
|
||
|
||
Users MAY override this value.
|
||
|
||
The default MUST favor reliability over maximum packet size.
|
||
|
||
---
|
||
|
||
# 43. Configuration Format
|
||
|
||
Configuration SHALL use TOML.
|
||
|
||
Parsing stack:
|
||
|
||
```text
|
||
serde
|
||
toml
|
||
```
|
||
|
||
Configuration MUST be validated before network listeners start.
|
||
|
||
Invalid configuration SHALL result in a clear fatal error.
|
||
|
||
---
|
||
|
||
# 44. Minimal Client Configuration
|
||
|
||
```toml
|
||
[client]
|
||
server = "vpn.example.com"
|
||
id = "laptop"
|
||
secret_file = "/etc/project/client.secret"
|
||
|
||
[local]
|
||
listen = "127.0.0.1:51821"
|
||
|
||
[transport]
|
||
mode = "auto"
|
||
```
|
||
|
||
The server hostname is static in v1.
|
||
|
||
DNS resolution SHALL use the system resolver.
|
||
|
||
---
|
||
|
||
# 45. Minimal Server Configuration
|
||
|
||
```toml
|
||
[server]
|
||
listen = "0.0.0.0"
|
||
|
||
[backend]
|
||
target = "127.0.0.1:51820"
|
||
|
||
[tls]
|
||
certificate = "/etc/letsencrypt/live/vpn.example.com/fullchain.pem"
|
||
private_key = "/etc/letsencrypt/live/vpn.example.com/privkey.pem"
|
||
|
||
[[auth.clients]]
|
||
id = "laptop"
|
||
secret_file = "/etc/project/clients/laptop.secret"
|
||
```
|
||
|
||
---
|
||
|
||
# 46. Advanced Client Configuration
|
||
|
||
```toml
|
||
[client]
|
||
server = "vpn.example.com"
|
||
id = "laptop"
|
||
secret_file = "/etc/project/client.secret"
|
||
|
||
[local]
|
||
listen = "127.0.0.1:51821"
|
||
|
||
[transport]
|
||
mode = "auto"
|
||
|
||
[transport.auto]
|
||
order = [
|
||
"direct_udp",
|
||
"quic",
|
||
"http3",
|
||
"tls_tcp",
|
||
]
|
||
|
||
probe_timeout_ms = 1500
|
||
retries = 2
|
||
|
||
[transport.direct_udp]
|
||
port = 51830
|
||
keepalive_secs = 15
|
||
|
||
[transport.quic]
|
||
port = 443
|
||
keepalive_secs = 15
|
||
|
||
[transport.http3]
|
||
port = 443
|
||
path = "/tunnel"
|
||
|
||
[transport.tls_tcp]
|
||
port = 443
|
||
|
||
[network]
|
||
max_datagram_size = 1200
|
||
|
||
[logging]
|
||
level = "info"
|
||
```
|
||
|
||
---
|
||
|
||
# 47. Advanced Server Configuration
|
||
|
||
```toml
|
||
[server]
|
||
listen = "0.0.0.0"
|
||
|
||
[backend]
|
||
target = "127.0.0.1:51820"
|
||
|
||
[transports.direct_udp]
|
||
enabled = true
|
||
port = 51830
|
||
|
||
[transports.quic]
|
||
enabled = true
|
||
port = 443
|
||
|
||
[transports.http3]
|
||
enabled = true
|
||
port = 443
|
||
path = "/tunnel"
|
||
|
||
[transports.tls_tcp]
|
||
enabled = true
|
||
port = 443
|
||
|
||
[tls]
|
||
certificate = "/etc/letsencrypt/live/vpn.example.com/fullchain.pem"
|
||
private_key = "/etc/letsencrypt/live/vpn.example.com/privkey.pem"
|
||
|
||
[session]
|
||
idle_timeout_secs = 120
|
||
|
||
[limits]
|
||
max_sessions = 1024
|
||
max_sessions_per_ip = 32
|
||
max_pending_handshakes = 256
|
||
handshake_timeout_ms = 3000
|
||
|
||
[[auth.clients]]
|
||
id = "laptop"
|
||
secret_file = "/etc/project/clients/laptop.secret"
|
||
|
||
[[auth.clients]]
|
||
id = "desktop"
|
||
secret_file = "/etc/project/clients/desktop.secret"
|
||
|
||
[logging]
|
||
level = "info"
|
||
```
|
||
|
||
---
|
||
|
||
# 48. Secret Storage
|
||
|
||
Inline secrets MAY be accepted for testing but SHOULD generate a warning.
|
||
|
||
Preferred configuration:
|
||
|
||
```toml
|
||
secret_file = "/path/to/secret"
|
||
```
|
||
|
||
Secret files SHOULD require restrictive permissions.
|
||
|
||
Recommended:
|
||
|
||
```text
|
||
0600
|
||
```
|
||
|
||
Secrets MUST NOT appear in logs.
|
||
|
||
---
|
||
|
||
# 49. TLS Certificates
|
||
|
||
TLS-capable transports SHALL use normal X.509 server certificates.
|
||
|
||
Expected provisioning includes:
|
||
|
||
```text
|
||
Certbot
|
||
acme.sh
|
||
Caddy
|
||
other ACME tooling
|
||
```
|
||
|
||
The project does not implement ACME itself in v1.
|
||
|
||
Clients SHALL perform normal hostname verification against the configured static hostname.
|
||
|
||
Certificate verification MUST NOT be disabled by default.
|
||
|
||
---
|
||
|
||
# 50. Certificate Reload
|
||
|
||
Automatic certificate reload is desirable but optional for the first prototype.
|
||
|
||
The architecture SHOULD allow certificates to be reloaded without rebuilding transport logic.
|
||
|
||
---
|
||
|
||
# 51. Session Model
|
||
|
||
Core session representation:
|
||
|
||
```rust
|
||
struct Session {
|
||
id: SessionId,
|
||
client_id: ClientId,
|
||
transport: TransportKind,
|
||
backend: UdpSocket,
|
||
created_at: Instant,
|
||
last_activity: Instant,
|
||
stats: SessionStats,
|
||
}
|
||
```
|
||
|
||
Transport-specific information SHOULD remain outside the generic session where possible.
|
||
|
||
---
|
||
|
||
# 52. Datagram Representation
|
||
|
||
Initial representation:
|
||
|
||
```rust
|
||
struct Datagram {
|
||
payload: Bytes,
|
||
}
|
||
```
|
||
|
||
Do not add unnecessary metadata until required.
|
||
|
||
Potential future form:
|
||
|
||
```rust
|
||
struct Datagram {
|
||
payload: Bytes,
|
||
received_at: Instant,
|
||
flow_id: Option<FlowId>,
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
# 53. Client State Machine
|
||
|
||
```text
|
||
STARTING
|
||
│
|
||
▼
|
||
RESOLVING
|
||
│
|
||
▼
|
||
PROBING
|
||
│
|
||
├─ direct_udp
|
||
├─ quic
|
||
├─ http3
|
||
└─ tls_tcp
|
||
│
|
||
▼
|
||
AUTHENTICATING
|
||
│
|
||
▼
|
||
CONNECTED
|
||
│
|
||
├──────── traffic
|
||
│
|
||
└──────── failure
|
||
│
|
||
▼
|
||
RECONNECTING
|
||
│
|
||
▼
|
||
PROBING
|
||
```
|
||
|
||
A transport failure MUST NOT terminate the daemon.
|
||
|
||
---
|
||
|
||
# 54. Backoff
|
||
|
||
Repeated connection failures SHALL use exponential backoff with jitter.
|
||
|
||
Example bounds:
|
||
|
||
```text
|
||
minimum 250 ms
|
||
maximum 30 s
|
||
```
|
||
|
||
Successful connection resets the backoff.
|
||
|
||
This avoids aggressive reconnect loops during outages.
|
||
|
||
---
|
||
|
||
# 55. Server Session Lifecycle
|
||
|
||
```text
|
||
HANDSHAKE
|
||
│
|
||
▼
|
||
AUTHENTICATING
|
||
│
|
||
├── reject
|
||
│
|
||
▼
|
||
ACTIVE
|
||
│
|
||
├── client close
|
||
├── transport loss
|
||
├── timeout
|
||
└── server shutdown
|
||
│
|
||
▼
|
||
CLOSED
|
||
```
|
||
|
||
Resources SHALL be released deterministically.
|
||
|
||
---
|
||
|
||
# 56. Keepalive Strategy
|
||
|
||
Keepalive behavior is transport-specific.
|
||
|
||
```text
|
||
direct_udp
|
||
authenticated protocol KEEPALIVE
|
||
|
||
quic
|
||
QUIC keepalive
|
||
|
||
http3
|
||
underlying QUIC keepalive
|
||
|
||
tls_tcp
|
||
transport heartbeat or TCP state
|
||
```
|
||
|
||
Keepalive defaults SHOULD preserve common NAT mappings without producing unnecessary traffic.
|
||
|
||
---
|
||
|
||
# 57. Observability
|
||
|
||
At minimum the client SHALL expose:
|
||
|
||
```text
|
||
state
|
||
server hostname
|
||
resolved remote address
|
||
selected transport
|
||
connection duration
|
||
RTT where available
|
||
bytes sent
|
||
bytes received
|
||
datagrams sent
|
||
datagrams received
|
||
datagrams dropped
|
||
oversized datagrams
|
||
authentication failures
|
||
reconnections
|
||
max datagram size
|
||
```
|
||
|
||
The server SHALL additionally expose:
|
||
|
||
```text
|
||
active sessions
|
||
sessions by transport
|
||
sessions by client ID
|
||
handshake attempts
|
||
authentication rejections
|
||
rate-limited attempts
|
||
expired sessions
|
||
backend errors
|
||
```
|
||
|
||
---
|
||
|
||
# 58. Logging
|
||
|
||
Use:
|
||
|
||
```text
|
||
tracing
|
||
tracing-subscriber
|
||
```
|
||
|
||
Logs SHOULD contain structured fields such as:
|
||
|
||
```text
|
||
client_id
|
||
session_id
|
||
transport
|
||
remote_addr
|
||
event
|
||
```
|
||
|
||
Secrets and application payloads MUST NEVER be logged by default.
|
||
|
||
Packet payload logging SHOULD not exist in normal release builds.
|
||
|
||
---
|
||
|
||
# 59. Logging Levels
|
||
|
||
Suggested semantics:
|
||
|
||
```text
|
||
ERROR
|
||
unrecoverable subsystem failure
|
||
|
||
WARN
|
||
transport failure
|
||
malformed traffic
|
||
rejected config behavior
|
||
|
||
INFO
|
||
startup
|
||
successful connection
|
||
selected transport
|
||
authenticated session
|
||
reconnect
|
||
shutdown
|
||
|
||
DEBUG
|
||
probing details
|
||
MTU decisions
|
||
session lifecycle
|
||
|
||
TRACE
|
||
low-level protocol state
|
||
```
|
||
|
||
---
|
||
|
||
# 60. Local Control Interface
|
||
|
||
The daemon SHOULD expose a Unix domain control socket.
|
||
|
||
Example:
|
||
|
||
```text
|
||
$XDG_RUNTIME_DIR/project.sock
|
||
```
|
||
|
||
The control protocol MAY initially use newline-delimited JSON.
|
||
|
||
Expected commands:
|
||
|
||
```text
|
||
status
|
||
stats
|
||
reconnect
|
||
reload
|
||
shutdown
|
||
```
|
||
|
||
The control socket MUST use filesystem permissions to prevent unauthorized local control.
|
||
|
||
---
|
||
|
||
# 61. CLI
|
||
|
||
Initial commands:
|
||
|
||
```bash
|
||
project client --config FILE
|
||
project server --config FILE
|
||
|
||
project check-config --config FILE
|
||
project generate-secret
|
||
```
|
||
|
||
Later:
|
||
|
||
```bash
|
||
project status
|
||
project stats
|
||
project reconnect
|
||
project reload
|
||
```
|
||
|
||
---
|
||
|
||
# 62. Graceful Shutdown
|
||
|
||
On SIGTERM or SIGINT:
|
||
|
||
1. stop accepting new sessions;
|
||
2. notify transports where appropriate;
|
||
3. stop local ingestion;
|
||
4. close backend sockets;
|
||
5. flush useful final metrics/logs;
|
||
6. terminate cleanly.
|
||
|
||
Shutdown MUST have a bounded timeout.
|
||
|
||
---
|
||
|
||
# 63. Configuration Reload
|
||
|
||
Full hot reload is not mandatory for the first milestone.
|
||
|
||
Architecture SHOULD nonetheless separate:
|
||
|
||
```text
|
||
parsed configuration
|
||
runtime state
|
||
```
|
||
|
||
A future reload MUST be capable of updating:
|
||
|
||
- clients;
|
||
- limits;
|
||
- log level;
|
||
- certificate paths;
|
||
|
||
without requiring architectural redesign.
|
||
|
||
---
|
||
|
||
# 64. Future Multiple Tunnel Support
|
||
|
||
V1 exposes one client tunnel.
|
||
|
||
Internally, configuration SHOULD already use:
|
||
|
||
```rust
|
||
struct TunnelConfig
|
||
```
|
||
|
||
rather than embedding tunnel fields directly everywhere.
|
||
|
||
Initial:
|
||
|
||
```rust
|
||
struct ClientConfig {
|
||
tunnel: TunnelConfig,
|
||
}
|
||
```
|
||
|
||
Future:
|
||
|
||
```rust
|
||
struct ClientConfig {
|
||
tunnels: Vec<TunnelConfig>,
|
||
}
|
||
```
|
||
|
||
Future TOML:
|
||
|
||
```toml
|
||
[[tunnels]]
|
||
name = "home"
|
||
|
||
[[tunnels]]
|
||
name = "work"
|
||
```
|
||
|
||
No v1 UI or runtime behavior is required for multiple tunnels.
|
||
|
||
---
|
||
|
||
# 65. Rust Technical Stack
|
||
|
||
Recommended language:
|
||
|
||
```text
|
||
Rust
|
||
```
|
||
|
||
Recommended runtime:
|
||
|
||
```text
|
||
Tokio
|
||
```
|
||
|
||
Recommended major libraries:
|
||
|
||
```text
|
||
tokio
|
||
quinn
|
||
rustls
|
||
h3
|
||
h3-quinn
|
||
bytes
|
||
serde
|
||
toml
|
||
clap
|
||
tracing
|
||
tracing-subscriber
|
||
thiserror
|
||
anyhow
|
||
socket2
|
||
hmac
|
||
sha2
|
||
hkdf
|
||
rand
|
||
subtle
|
||
```
|
||
|
||
Potential optional libraries:
|
||
|
||
```text
|
||
secrecy
|
||
zeroize
|
||
```
|
||
|
||
Exact versions SHALL be selected at implementation time.
|
||
|
||
---
|
||
|
||
# 66. Error Handling
|
||
|
||
Library/core modules SHOULD use typed errors with:
|
||
|
||
```text
|
||
thiserror
|
||
```
|
||
|
||
Binary/CLI boundaries MAY use:
|
||
|
||
```text
|
||
anyhow
|
||
```
|
||
|
||
Recoverable network failure MUST NOT be represented as an unrecoverable process error.
|
||
|
||
---
|
||
|
||
# 67. Constant-Time Authentication
|
||
|
||
Authentication tag comparison MUST use constant-time equality.
|
||
|
||
Do not compare authentication data with ordinary:
|
||
|
||
```rust
|
||
a == b
|
||
```
|
||
|
||
unless the cryptographic library explicitly guarantees appropriate behavior.
|
||
|
||
Use primitives supplied by the selected crypto implementation or a constant-time helper library.
|
||
|
||
---
|
||
|
||
# 68. Crypto Policy
|
||
|
||
The project SHALL NOT:
|
||
|
||
- invent encryption algorithms;
|
||
- implement SHA manually;
|
||
- implement HMAC manually;
|
||
- implement HKDF manually;
|
||
- implement TLS manually.
|
||
|
||
All cryptographic operations SHALL use maintained, reviewed Rust libraries.
|
||
|
||
The direct transport payload itself does not require encryption because the encapsulated application may already be encrypted.
|
||
|
||
Direct transport DOES require integrity and authentication.
|
||
|
||
Users requiring outer confidentiality SHALL use QUIC, HTTP/3, or TLS/TCP.
|
||
|
||
---
|
||
|
||
# 69. Core Module Structure
|
||
|
||
Initial source tree SHOULD remain simple:
|
||
|
||
```text
|
||
src/
|
||
├── main.rs
|
||
├── cli.rs
|
||
├── config.rs
|
||
├── datagram.rs
|
||
├── session.rs
|
||
├── stats.rs
|
||
├── client/
|
||
│ ├── mod.rs
|
||
│ ├── listener.rs
|
||
│ └── supervisor.rs
|
||
├── server/
|
||
│ ├── mod.rs
|
||
│ ├── session.rs
|
||
│ ├── backend.rs
|
||
│ └── limits.rs
|
||
├── protocol/
|
||
│ ├── mod.rs
|
||
│ ├── direct.rs
|
||
│ ├── auth.rs
|
||
│ └── replay.rs
|
||
└── transport/
|
||
├── mod.rs
|
||
├── direct_udp.rs
|
||
├── quic.rs
|
||
├── http3.rs
|
||
└── tls_tcp.rs
|
||
```
|
||
|
||
A Cargo workspace SHOULD NOT be introduced until module boundaries have stabilized.
|
||
|
||
---
|
||
|
||
# 70. Core Dependency Direction
|
||
|
||
Desired dependency structure:
|
||
|
||
```text
|
||
configuration
|
||
│
|
||
▼
|
||
core
|
||
┌────────┴────────┐
|
||
│ │
|
||
client server
|
||
│ │
|
||
└──── transport ──┘
|
||
│
|
||
┌─────────┼──────────┐
|
||
▼ ▼ ▼
|
||
UDP QUIC HTTP/3
|
||
│
|
||
etc.
|
||
```
|
||
|
||
The core MUST NOT contain scattered transport type checks.
|
||
|
||
Avoid:
|
||
|
||
```rust
|
||
if transport == Transport::Quic {
|
||
...
|
||
}
|
||
```
|
||
|
||
unless behavior genuinely belongs at the orchestration layer.
|
||
|
||
---
|
||
|
||
# 71. Performance Model
|
||
|
||
The fast path SHOULD minimize allocations.
|
||
|
||
Preferred packet representation:
|
||
|
||
```rust
|
||
Bytes
|
||
BytesMut
|
||
```
|
||
|
||
Buffers SHOULD be reused where practical.
|
||
|
||
The implementation SHOULD avoid:
|
||
|
||
- copying payloads unnecessarily;
|
||
- global mutexes on every packet;
|
||
- per-packet heap allocation where easily avoidable;
|
||
- synchronous filesystem operations in packet paths.
|
||
|
||
Correctness takes priority over premature micro-optimization.
|
||
|
||
---
|
||
|
||
# 72. Concurrency Model
|
||
|
||
Tokio tasks SHALL be used around logical session operations.
|
||
|
||
A server session will approximately contain:
|
||
|
||
```text
|
||
transport receive ─────► backend UDP send
|
||
transport send ◄─────── backend UDP receive
|
||
```
|
||
|
||
These may be implemented using:
|
||
|
||
- paired tasks;
|
||
- `tokio::select!`;
|
||
- channels;
|
||
- a session supervisor.
|
||
|
||
The simplest implementation that preserves cancellation and ownership clarity SHOULD be preferred.
|
||
|
||
---
|
||
|
||
# 73. Cancellation
|
||
|
||
All long-lived tasks MUST support deterministic cancellation.
|
||
|
||
Recommended primitives include:
|
||
|
||
```text
|
||
CancellationToken
|
||
broadcast/watch channels
|
||
task ownership through supervisors
|
||
```
|
||
|
||
Detached tasks that cannot be shut down SHOULD be avoided.
|
||
|
||
---
|
||
|
||
# 74. Server Multi-Client Requirements
|
||
|
||
The server MUST:
|
||
|
||
- accept concurrent clients;
|
||
- isolate session errors;
|
||
- prevent one client from crashing another session;
|
||
- enforce per-client limits;
|
||
- maintain independent backend sockets;
|
||
- clean up dead sessions;
|
||
- maintain aggregate and per-session stats.
|
||
|
||
One malformed client packet MUST NOT terminate a listener.
|
||
|
||
---
|
||
|
||
# 75. Direct UDP Listener Model
|
||
|
||
The direct listener may use one public UDP socket.
|
||
|
||
Incoming packets are dispatched by:
|
||
|
||
```text
|
||
packet type
|
||
session ID
|
||
```
|
||
|
||
Initial HELLO packets use:
|
||
|
||
```text
|
||
session_id = 0
|
||
```
|
||
|
||
Authenticated DATA packets identify their session through the assigned random ID.
|
||
|
||
---
|
||
|
||
# 76. QUIC Listener Model
|
||
|
||
One QUIC endpoint accepts many connections.
|
||
|
||
Each authenticated QUIC connection becomes one server session.
|
||
|
||
QUIC connection state acts as transport identity.
|
||
|
||
Application packets arrive through QUIC DATAGRAM frames.
|
||
|
||
---
|
||
|
||
# 77. HTTP/3 Listener Model
|
||
|
||
HTTP/3 operates over the QUIC listener architecture.
|
||
|
||
Each successful authenticated CONNECT-UDP exchange maps to one backend session.
|
||
|
||
Where feasible, QUIC and HTTP/3 MAY share certificate/configuration infrastructure.
|
||
|
||
---
|
||
|
||
# 78. TCP Listener Model
|
||
|
||
Each accepted TLS/TCP connection becomes one potential session.
|
||
|
||
No backend socket is created until project authentication succeeds.
|
||
|
||
After authentication, framed datagrams are transported bidirectionally.
|
||
|
||
---
|
||
|
||
# 79. Protocol Versioning
|
||
|
||
Direct wire protocol packets contain:
|
||
|
||
```text
|
||
version = 1
|
||
```
|
||
|
||
Breaking protocol changes SHALL increment the version.
|
||
|
||
Unknown versions MUST result in clean rejection.
|
||
|
||
Configuration schema and project binary version are independent from transport wire protocol version.
|
||
|
||
---
|
||
|
||
# 80. Metrics and Benchmarking
|
||
|
||
The project SHOULD eventually include benchmarks for:
|
||
|
||
```text
|
||
datagrams/sec
|
||
throughput
|
||
latency overhead
|
||
memory/session
|
||
CPU usage
|
||
direct UDP overhead
|
||
QUIC overhead
|
||
HTTP/3 overhead
|
||
TCP fallback overhead
|
||
```
|
||
|
||
Performance tests SHOULD compare the tunnel against direct UDP baseline.
|
||
|
||
---
|
||
|
||
# 81. Testing Strategy
|
||
|
||
Unit tests SHALL cover:
|
||
|
||
```text
|
||
packet serialization
|
||
packet parsing
|
||
malformed packets
|
||
HMAC verification
|
||
session key derivation
|
||
sequence windows
|
||
replay detection
|
||
configuration validation
|
||
timeout logic
|
||
```
|
||
|
||
Integration tests SHALL cover:
|
||
|
||
```text
|
||
client ↔ server direct UDP
|
||
multiple simultaneous clients
|
||
NAT-like source port change
|
||
authentication rejection
|
||
server restart
|
||
client reconnect
|
||
backend unavailable
|
||
oversized datagram
|
||
session expiration
|
||
```
|
||
|
||
Later tests SHALL cover each transport.
|
||
|
||
---
|
||
|
||
# 82. Fuzzing
|
||
|
||
The direct UDP protocol parser is a good fuzzing target.
|
||
|
||
The parser SHOULD be written so arbitrary byte strings can be fed into it independently of network state.
|
||
|
||
Fuzz targets SHOULD include:
|
||
|
||
```text
|
||
direct packet parser
|
||
TCP frame parser
|
||
authentication message parser
|
||
configuration parser where appropriate
|
||
```
|
||
|
||
---
|
||
|
||
# 83. Development Milestone 1
|
||
|
||
Goal:
|
||
|
||
```text
|
||
generic authenticated UDP relay
|
||
```
|
||
|
||
Implement only:
|
||
|
||
```text
|
||
client local UDP listener
|
||
direct UDP transport
|
||
server listener
|
||
authentication handshake
|
||
session creation
|
||
backend UDP sockets
|
||
DATA packet authentication
|
||
replay protection
|
||
keepalive
|
||
session expiry
|
||
multiple simultaneous clients
|
||
TOML configuration
|
||
structured logs
|
||
basic statistics
|
||
```
|
||
|
||
No QUIC yet.
|
||
|
||
This validates the entire core architecture.
|
||
|
||
---
|
||
|
||
# 84. Development Milestone 2
|
||
|
||
Add QUIC.
|
||
|
||
Requirements:
|
||
|
||
```text
|
||
TLS certificate loading
|
||
hostname validation
|
||
QUIC connection establishment
|
||
project client authentication
|
||
QUIC DATAGRAM send/receive
|
||
keepalive
|
||
MTU reporting
|
||
reconnect
|
||
multi-client server handling
|
||
```
|
||
|
||
No core datagram API redesign should be necessary.
|
||
|
||
If substantial core redesign is required, the transport abstraction should be reconsidered before continuing.
|
||
|
||
---
|
||
|
||
# 85. Development Milestone 3
|
||
|
||
Implement:
|
||
|
||
```text
|
||
transport = "auto"
|
||
```
|
||
|
||
Automatic order:
|
||
|
||
```text
|
||
direct_udp
|
||
quic
|
||
```
|
||
|
||
Include:
|
||
|
||
- probing;
|
||
- timeouts;
|
||
- retries;
|
||
- exponential reconnect backoff;
|
||
- status reporting.
|
||
|
||
---
|
||
|
||
# 86. Development Milestone 4
|
||
|
||
Implement:
|
||
|
||
```text
|
||
HTTP/3 CONNECT-UDP
|
||
```
|
||
|
||
using the existing QUIC infrastructure where practical.
|
||
|
||
Add:
|
||
|
||
```text
|
||
HTTP/3 listener
|
||
CONNECT request handling
|
||
authentication
|
||
HTTP datagrams
|
||
backend session mapping
|
||
```
|
||
|
||
---
|
||
|
||
# 87. Development Milestone 5
|
||
|
||
Implement TLS/TCP fallback.
|
||
|
||
Add:
|
||
|
||
```text
|
||
TLS listener
|
||
framed packet parser
|
||
project authentication
|
||
bidirectional datagram reconstruction
|
||
automatic fallback integration
|
||
```
|
||
|
||
---
|
||
|
||
# 88. Development Milestone 6
|
||
|
||
Operational polish:
|
||
|
||
```text
|
||
Unix control socket
|
||
status command
|
||
stats command
|
||
reconnect command
|
||
config validation command
|
||
systemd units
|
||
CAP_NET_BIND_SERVICE documentation
|
||
certificate reload
|
||
configuration reload
|
||
benchmarks
|
||
fuzzing
|
||
installation documentation
|
||
```
|
||
|
||
---
|
||
|
||
# 89. Definition of v1 Completion
|
||
|
||
Version 1 is considered complete when:
|
||
|
||
1. multiple clients can concurrently reach one UDP backend;
|
||
2. no WireGuard-specific logic exists;
|
||
3. direct UDP works reliably;
|
||
4. QUIC DATAGRAM works reliably;
|
||
5. HTTP/3 CONNECT-UDP works;
|
||
6. TLS/TCP fallback works;
|
||
7. automatic transport selection works;
|
||
8. authentication is enforced on every public transport;
|
||
9. direct UDP includes replay and integrity protection;
|
||
10. NAT rebinding works for direct UDP;
|
||
11. sessions expire and clean up correctly;
|
||
12. the server survives malformed and unauthenticated traffic;
|
||
13. the daemon runs unprivileged except for optional privileged-port capability;
|
||
14. TOML configuration is validated clearly;
|
||
15. meaningful status and statistics are available;
|
||
16. reconnects occur automatically;
|
||
17. automated integration tests cover multi-client operation.
|
||
|
||
---
|
||
|
||
# 90. Explicit Non-Goals for v1
|
||
|
||
The following SHALL remain out of scope:
|
||
|
||
```text
|
||
WireGuard configuration
|
||
TUN/TAP interfaces
|
||
routing management
|
||
firewall management
|
||
multi-hop routing
|
||
browser fingerprint imitation
|
||
traffic shaping for censorship evasion
|
||
packet-size mimicry
|
||
TLS fingerprint spoofing
|
||
dynamic server discovery
|
||
server clustering
|
||
automatic roaming between servers
|
||
GUI
|
||
Windows
|
||
macOS
|
||
multiple simultaneous client tunnels
|
||
application-layer fragmentation
|
||
custom encryption
|
||
```
|
||
|
||
These MAY be explored after the core transport system is mature.
|
||
|
||
---
|
||
|
||
# 91. Architectural Summary
|
||
|
||
The system can be summarized as:
|
||
|
||
```text
|
||
CLIENT
|
||
|
||
Application
|
||
│
|
||
│ UDP
|
||
▼
|
||
Local listener
|
||
│
|
||
▼
|
||
Tunnel/session core
|
||
│
|
||
▼
|
||
Transport abstraction
|
||
│
|
||
├── Direct UDP
|
||
├── QUIC DATAGRAM
|
||
├── HTTP/3 CONNECT-UDP
|
||
└── TLS/TCP
|
||
│
|
||
════════════════ Internet ════════════════
|
||
│
|
||
▼
|
||
Transport listener
|
||
│
|
||
▼
|
||
Authenticated server session
|
||
│
|
||
▼
|
||
Dedicated backend UDP socket
|
||
│
|
||
▼
|
||
Configured UDP backend
|
||
```
|
||
|
||
The core sees only:
|
||
|
||
```text
|
||
send datagram
|
||
receive datagram
|
||
session opened
|
||
session closed
|
||
transport capabilities
|
||
```
|
||
|
||
It does not care whether the external representation is:
|
||
|
||
```text
|
||
custom direct UDP packet
|
||
QUIC connection
|
||
HTTP/3 CONNECT-UDP flow
|
||
TLS/TCP stream
|
||
```
|
||
|
||
---
|
||
|
||
# 92. Final Design Rule
|
||
|
||
The project SHALL always preserve this separation:
|
||
|
||
```text
|
||
application protocol
|
||
≠
|
||
tunnel session
|
||
≠
|
||
transport
|
||
≠
|
||
authentication
|
||
```
|
||
|
||
The encapsulated application remains opaque.
|
||
|
||
Sessions provide logical client isolation.
|
||
|
||
Transports determine how datagrams cross the network.
|
||
|
||
Authentication determines who may create sessions.
|
||
|
||
Keeping those four responsibilities independent is the central architectural rule of the project.
|