Protocol Overview
Xray-core implements a diverse set of proxy protocols, each registered via common.RegisterConfig() in its init() function. The core dispatches inbound connections to the appropriate protocol handler based on configuration, and outbound handlers connect to upstream servers or destinations.
Protocol Capability Matrix
| Protocol | Inbound | Outbound | TCP | UDP | Encryption | Mux Support | Auth |
|---|---|---|---|---|---|---|---|
| VMess | Yes | Yes | Yes | Yes | AES-128-GCM, ChaCha20-Poly1305, None | Yes (v1.mux.cool) | UUID + AEAD header |
| VLESS | Yes | Yes | Yes | Yes | None (relies on transport TLS) | Yes (XUDP) | UUID |
| Trojan | Yes | Yes | Yes | Yes | None (relies on TLS) | No | SHA224(password) |
| Shadowsocks | Yes | Yes | Yes | Yes | AES-128-GCM, AES-256-GCM, ChaCha20-Poly1305, XChaCha20, None | No | Per-key |
| Shadowsocks 2022 | Yes | Yes | Yes | Yes | 2022-blake3-aes-128-gcm, 2022-blake3-aes-256-gcm, etc. | No | PSK (base64) |
| SOCKS5 | Yes | Yes | Yes | Yes (UDP Associate) | None | No | Username/Password |
| HTTP | Yes | Yes | Yes | No | None (HTTPS via transport) | No | Basic Auth |
| Dokodemo-door | Yes | No | Yes | Yes | N/A (transparent) | No | N/A |
| Freedom | No | Yes | Yes | Yes | N/A (direct) | No | N/A |
| Blackhole | No | Yes | N/A | N/A | N/A | No | N/A |
| WireGuard | Yes | Yes | Yes | Yes | Noise protocol (Curve25519, ChaCha20-Poly1305) | No | Public/Private key |
| Hysteria2 | Yes | Yes | Yes | Yes (QUIC datagram) | QUIC TLS 1.3 | No | Password-based |
Architecture
Inbound Handler Interface
Every inbound protocol implements proxy.Inbound:
type Inbound interface {
Network() []net.Network // Supported networks (TCP, UDP, UNIX)
Process(ctx context.Context,
network net.Network,
conn stat.Connection,
dispatcher routing.Dispatcher) error
}Key source: proxy/proxy.go
Outbound Handler Interface
Every outbound protocol implements proxy.Outbound:
type Outbound interface {
Process(ctx context.Context,
link *transport.Link,
dialer internet.Dialer) error
}Key source: proxy/proxy.go
Registration Pattern
All protocols self-register using the same pattern in their init():
func init() {
common.Must(common.RegisterConfig((*Config)(nil),
func(ctx context.Context, config interface{}) (interface{}, error) {
return New(ctx, config.(*Config))
}))
}Connection Flow
graph LR
A[Client] -->|Transport Layer| B[Inbound Handler]
B -->|Decode Protocol| C[Dispatcher]
C -->|Routing Rules| D[Outbound Handler]
D -->|Encode Protocol| E[Transport Layer]
E --> F[Destination]Splice Copy Levels
The CanSpliceCopy field on inbound/outbound metadata controls zero-copy optimization:
| Value | Meaning |
|---|---|
| 0 | No splice |
| 1 | Splice allowed (direct/dokodemo) |
| 2 | Splice possible after handshake (socks/http raw) |
| 3 | Full splice support (encrypted protocols) |
Address Parsing
Most protocols use protocol.NewAddressParser with SOCKS5-style address family bytes:
| Byte | Family |
|---|---|
0x01 | IPv4 (4 bytes) |
0x03 | Domain (1-byte length prefix + string) |
0x04 | IPv6 (16 bytes) |
VMess uses a different ordering: 0x01 = IPv4, 0x02 = Domain, 0x03 = IPv6, with port-then-address format.
Source: proxy/vmess/encoding/encoding.go:12-17, proxy/trojan/protocol.go:16-20, proxy/shadowsocks/protocol.go:24-31
Key Source Files
| Protocol | Directory |
|---|---|
| VMess | proxy/vmess/ (aead/, encoding/, inbound/, outbound/) |
| VLESS | proxy/vless/ |
| Trojan | proxy/trojan/ |
| Shadowsocks | proxy/shadowsocks/ |
| Shadowsocks 2022 | proxy/shadowsocks_2022/ |
| SOCKS | proxy/socks/ |
| HTTP | proxy/http/ |
| Dokodemo-door | proxy/dokodemo/ |
| Freedom | proxy/freedom/ |
| Blackhole | proxy/blackhole/ |
| WireGuard | proxy/wireguard/ |
| Hysteria2 | proxy/hysteria/ |