Обзор протоколов
Xray-core реализует разнообразный набор прокси-протоколов, каждый из которых регистрируется через common.RegisterConfig() в своей функции init(). Ядро направляет входящие соединения к соответствующему обработчику протокола на основе конфигурации, а исходящие обработчики подключаются к вышестоящим серверам или конечным точкам назначения.
Матрица возможностей протоколов
| Протокол | Входящий | Исходящий | TCP | UDP | Шифрование | Поддержка Mux | Аутентификация |
|---|---|---|---|---|---|---|---|
| VMess | Да | Да | Да | Да | AES-128-GCM, ChaCha20-Poly1305, None | Да (v1.mux.cool) | UUID + AEAD-заголовок |
| VLESS | Да | Да | Да | Да | Нет (зависит от TLS транспортного уровня) | Да (XUDP) | UUID |
| Trojan | Да | Да | Да | Да | Нет (зависит от TLS) | Нет | SHA224(пароль) |
| Shadowsocks | Да | Да | Да | Да | AES-128-GCM, AES-256-GCM, ChaCha20-Poly1305, XChaCha20, None | Нет | По ключу |
| Shadowsocks 2022 | Да | Да | Да | Да | 2022-blake3-aes-128-gcm, 2022-blake3-aes-256-gcm и др. | Нет | PSK (base64) |
| SOCKS5 | Да | Да | Да | Да (UDP Associate) | Нет | Нет | Имя пользователя/Пароль |
| HTTP | Да | Да | Да | Нет | Нет (HTTPS через транспорт) | Нет | Basic Auth |
| Dokodemo-door | Да | Нет | Да | Да | Н/Д (прозрачный) | Нет | Н/Д |
| Freedom | Нет | Да | Да | Да | Н/Д (прямой) | Нет | Н/Д |
| Blackhole | Нет | Да | Н/Д | Н/Д | Н/Д | Нет | Н/Д |
| WireGuard | Да | Да | Да | Да | Протокол Noise (Curve25519, ChaCha20-Poly1305) | Нет | Публичный/Приватный ключ |
| Hysteria2 | Да | Да | Да | Да (QUIC datagram) | QUIC TLS 1.3 | Нет | На основе пароля |
Архитектура
Интерфейс входящего обработчика
Каждый входящий протокол реализует 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
}Ключевой исходный файл: proxy/proxy.go
Интерфейс исходящего обработчика
Каждый исходящий протокол реализует proxy.Outbound:
type Outbound interface {
Process(ctx context.Context,
link *transport.Link,
dialer internet.Dialer) error
}Ключевой исходный файл: proxy/proxy.go
Паттерн регистрации
Все протоколы самостоятельно регистрируются с использованием одного и того же паттерна в своей функции init():
func init() {
common.Must(common.RegisterConfig((*Config)(nil),
func(ctx context.Context, config interface{}) (interface{}, error) {
return New(ctx, config.(*Config))
}))
}Поток соединения
graph LR
A[Клиент] -->|Транспортный уровень| B[Входящий обработчик]
B -->|Декодирование протокола| C[Диспетчер]
C -->|Правила маршрутизации| D[Исходящий обработчик]
D -->|Кодирование протокола| E[Транспортный уровень]
E --> F[Назначение]Уровни Splice Copy
Поле CanSpliceCopy в метаданных входящих/исходящих обработчиков управляет оптимизацией нулевого копирования:
| Значение | Описание |
|---|---|
| 0 | Без splice |
| 1 | Splice разрешён (direct/dokodemo) |
| 2 | Splice возможен после рукопожатия (socks/http raw) |
| 3 | Полная поддержка splice (зашифрованные протоколы) |
Разбор адресов
Большинство протоколов используют protocol.NewAddressParser с байтами семейства адресов в стиле SOCKS5:
| Байт | Семейство |
|---|---|
0x01 | IPv4 (4 байта) |
0x03 | Домен (1 байт длины + строка) |
0x04 | IPv6 (16 байт) |
VMess использует другой порядок: 0x01 = IPv4, 0x02 = Домен, 0x03 = IPv6, с форматом порт-затем-адрес.
Исходный код: proxy/vmess/encoding/encoding.go:12-17, proxy/trojan/protocol.go:16-20, proxy/shadowsocks/protocol.go:24-31
Ключевые исходные файлы
| Протокол | Каталог |
|---|---|
| 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/ |