Files
wgcloak/docs/PROTOCOL.md
T

3.4 KiB

Protocol overview

The application protocol, tunnel session, transport, and authentication remain independent. The application payload is opaque and is never parsed as WireGuard (or any other protocol).

Direct UDP wire protocol (target v1)

Direct messages use protocol version 1, network byte order, and a 12-byte common header:

+---------+---------+---------+---------+
| version | type    | flags   | hdr_len |
| u8      | u8      | u8      | u8      |
+---------------------------------------+
| session_id (u64)                      |
+---------------------------------------+

Packet types are HELLO (0x01), ACCEPT (0x02), REJECT (0x03), DATA (0x10), KEEPALIVE (0x11), and CLOSE (0x12). Unknown or malformed types are rejected or ignored according to context and never crash the daemon.

HELLO has session ID zero and carries a bounded client ID, timestamp, 16-byte client nonce, and a 32-byte HMAC-SHA256 authenticator over the canonical version/client/timestamp/nonce encoding. The server checks a default 60-second clock window and remembers accepted nonces for replay protection.

ACCEPT assigns a random, non-zero 64-bit session ID and returns a server nonce, idle timeout, maximum datagram size, and an authenticator. REJECT returns only a small reason class; it must not disclose secret material.

Authenticated DATA and KEEPALIVE packets contain the common header, a 32-bit direction-specific sequence number, a 128-bit truncated HMAC tag, and the optional payload. Session keys are derived with HKDF-SHA256 from the configured secret, both nonces, and the session ID. Implementations must use maintained cryptographic libraries and constant-time tag comparison.

Sequence windows provide duplicate/replay detection and diagnostics but do not reorder UDP. After MAC and replay checks, a valid packet may update the peer address, allowing NAT rebinding. A session expires after the configured idle timeout (target default 120 seconds), then its backend socket and replay state are released.

The core rejects oversized application datagrams, increments a counter, and logs at debug/warn level. v1 does not fragment datagrams; a conservative starting limit is 1200 bytes.

Encapsulated transports

  • Direct UDP: lowest overhead and native datagrams; uses the authenticated protocol above and provides integrity but not outer confidentiality.
  • QUIC DATAGRAM: TLS 1.3 protects the transport; client shared-secret challenge/response still authenticates the configured client.
  • HTTP/3 CONNECT-UDP: uses legitimate MASQUE CONNECT-UDP and HTTP Datagram semantics over QUIC. It is for compatibility, not fingerprint spoofing.
  • TLS/TCP: uses the same client authentication model. Each datagram is framed as a big-endian u16 payload length followed by up to 65535 bytes; the configured lower limit should normally apply. TCP head-of-line blocking is expected.

QUIC, HTTP/3, and TLS/TCP are planned by milestones 2, 4, and 5 respectively. The direct packet details are a protocol target; confirm the implementation and integration tests before treating them as interoperable guarantees.

Authentication and resource order

The server performs cheap bounds/version checks, authentication and rate-limit checks before allocating a backend UDP socket. Public listeners are hostile: limits, handshake timeouts, per-source caps, and malformed-packet handling are part of the protocol boundary.