Trojan Rust

Trojan Protocol

Trojan protocol specification and wire format

The Trojan protocol operates over TLS, making proxy traffic indistinguishable from normal HTTPS connections. This page documents the wire format used by trojan-rs.

Protocol Stack

Application Data
Trojan Protocol
TLS 1.2/1.3
TCP

The client first completes a standard TLS handshake. On success, it sends the Trojan header followed by application data. On failure, the connection is dropped (identical to a failed HTTPS connection).

TCP Header Format

The Trojan header consists of a password hash, a request, and CRLF delimiters:

+-----------------------+---------+----------------+---------+----------+
| hex(SHA224(password)) |  CRLF   | Trojan Request |  CRLF   | Payload  |
+-----------------------+---------+----------------+---------+----------+
|          56           | X'0D0A' |    Variable    | X'0D0A' | Variable |
  • Password hash — 56 bytes of lowercase hexadecimal ASCII, computed as hex(SHA224(password))
  • CRLF\r\n (0x0D 0x0A) delimiter
  • Payload — Optional first-packet payload, bundled with the header to reduce latency

Trojan Request

The request follows the SOCKS5 address format:

+-----+------+----------+----------+
| CMD | ATYP | DST.ADDR | DST.PORT |
+-----+------+----------+----------+
|  1  |  1   | Variable |    2     |

CMD (Command):

  • 0x01 — CONNECT (TCP proxy)
  • 0x03 — UDP ASSOCIATE

ATYP (Address Type):

  • 0x01 — IPv4 (4 bytes)
  • 0x03 — Domain name (1 byte length + domain bytes)
  • 0x04 — IPv6 (16 bytes)

DST.PORT — Destination port in network byte order (big-endian, 2 bytes)

UDP Packet Format

When CMD is 0x03 (UDP ASSOCIATE), subsequent data follows this per-packet format:

+------+----------+----------+--------+---------+----------+
| ATYP | DST.ADDR | DST.PORT | Length |  CRLF   | Payload  |
+------+----------+----------+--------+---------+----------+
|  1   | Variable |    2     |   2    | X'0D0A' | Variable |
  • Length — Payload length in bytes (2 bytes, big-endian)
  • CRLF\r\n delimiter
  • UDP packets do not include authentication. Authentication occurs once during the TCP header phase.

Authentication

Passwords are configured in plaintext and hashed at runtime:

  1. Server stores the SHA-224 hash of each valid password
  2. Client computes hex(SHA224(password)) — 56 lowercase hex characters
  3. Client sends the hash as the first 56 bytes of the Trojan header
  4. Server checks the hash against its valid set

SHA-224 produces a 28-byte digest, which is 56 hex characters. trojan-rs enforces lowercase hex and validates the 56-byte length.

Fallback Behavior

When the server receives a connection that does not match the Trojan protocol:

  1. TLS handshake succeeds, invalid header — The server buffers the received bytes and forwards the entire connection (including buffered bytes) to the fallback address
  2. Password mismatch — Same as invalid header: forward to fallback

This makes the server behave identically to a normal HTTPS server for any traffic that isn't a valid Trojan connection. The fallback is typically a web server serving legitimate content.

trojan-rs implements this with a PrefixedStream that replays buffered bytes before reading new data from the socket.

First-Packet Payload

The protocol allows (and encourages) sending application data in the same TLS record as the header. This:

  • Reduces the number of round trips
  • Makes the traffic pattern less distinguishable from normal HTTPS

trojan-rs bundles the first data packet with the Trojan header when data is available during the handshake.

Compatibility

trojan-rs is wire-compatible with:

  • The original Trojan C++ implementation
  • trojan-go

The protocol format is identical. Any Trojan-compatible client can connect to a trojan-rs server and vice versa.

On this page