Совместимость на уровне протокола
Эта страница документирует точные форматы данных на уровне проводного протокола, необходимые для взаимодействия с существующими экземплярами Xray-core. Ваша реализация должна генерировать и обрабатывать байты в точном соответствии с этими форматами.
Проводной формат VLESS
Запрос (Клиент -> Сервер)
Offset Size Field
0 1 Version (0x00)
1 16 UUID (сырые байты, НЕ hex-строка)
17 1 Длина Addons (N)
18 N Addons (protobuf-кодированное сообщение Addons, или пусто если N=0)
18+N 1 Команда: 0x01=TCP, 0x02=UDP, 0x03=Mux, 0x04=Reverse
19+N ... Адрес (опускается для Mux/Reverse):
Port: 2 байта big-endian
AddrType: 0x01=IPv4, 0x02=Domain, 0x03=IPv6
Address:
IPv4: 4 байта
Domain: 1 байт длины + строка домена
IPv6: 16 байтProtobuf Addons:
message Addons {
string Flow = 1; // "xtls-rprx-vision" или пусто
bytes Seed = 2;
}Когда Flow пустой: длина addons = 0 (один байт 0x00). Когда Flow задан: protobuf-кодирование и запись длины + данных.
Ответ (Сервер -> Клиент)
Offset Size Field
0 1 Version (повторяет версию запроса, 0x00)
1 1 Длина Addons (N)
2 N Addons (protobuf-кодированные, обычно пусто)Тело VLESS
| Команда | Формат тела |
|---|---|
| TCP (без Vision) | Сырые байты потока |
| UDP | [2Б длина BE][полезная нагрузка] повторяется |
| Mux | Формат Mux-фреймов (ниже) |
| Mux port=666 | Формат XUDP-фреймов (ниже) |
Проводной формат VMess (AEAD)
Auth Info (16 байт)
authID = HMAC-MD5(key=MD5(UUID + timestamp/30s), data=timestamp + random)Заголовок запроса
[16Б AuthID]
[2Б EncryptedLength] (AES-128-GCM, ключ из authID)
[NБ EncryptedCommand] (AES-128-GCM, ключ из authID)Расшифрованная команда:
1Б Version (1)
16Б Request Body IV
16Б Request Body Key
1Б Response Auth V
1Б Option (0x01=ChunkStream, 0x02=ConnectionReuse, 0x04=ChunkMasking, 0x08=GlobalPadding, 0x10=AuthenticatedLength)
1Б Padding Length + Security
1Б Reserved
1Б Command (0x01=TCP, 0x02=UDP, 0x03=Mux)
2Б Port (BE)
1Б Address Type
NБ Address
NБ Random Padding
4Б FNV1a32 ChecksumЗаголовок ответа
1Б Response Auth V (должен совпадать с запросом)
1Б Option
1Б Command
1Б Command LengthТело (AES-128-GCM)
[2Б Длина (зашифрована AES-GCM)]
[NБ Полезная нагрузка (зашифрована AES-GCM)]
[2Б Длина]
[NБ Полезная нагрузка]
...
[2Б 0x0000] (маркер конца)Nonce: на основе счётчика, инкрементируется для каждого чанка.
Проводной формат Trojan
Запрос
[56Б Hex(SHA224(password))] (строка hex в нижнем регистре, НЕ бинарные данные)
[2Б CRLF (0x0D 0x0A)]
[1Б Команда: 0x01=TCP, 0x03=UDP]
[1Б Тип адреса: 0x01=IPv4, 0x03=Domain, 0x04=IPv6]
[NБ Адрес]
[2Б Port (BE)]
[2Б CRLF (0x0D 0x0A)]
[... Полезная нагрузка]UDP-фрейминг (Command = 0x03)
[1Б Тип адреса]
[NБ Адрес]
[2Б Port (BE)]
[2Б Длина полезной нагрузки (BE)]
[2Б CRLF]
[NБ Полезная нагрузка]Повторяется для каждого UDP-пакета.
Формат Mux-фреймов
Заголовок фрейма
[2Б Длина метаданных (BE)] — длина последующих метаданных
[2Б ID сессии (BE)]
[1Б Статус: 0x01=New, 0x02=Keep, 0x03=End, 0x04=KeepAlive]
[1Б Опция: бит 0=Data, бит 1=Error]Новая сессия (Status=0x01)
[... Заголовок фрейма]
[1Б Сеть: 0x01=TCP, 0x02=UDP]
[2Б Port (BE)]
[1Б Тип адреса: 0x01=IPv4, 0x02=Domain, 0x03=IPv6]
[NБ Адрес]Полезная нагрузка (когда Option содержит бит Data)
После заголовка фрейма/метаданных:
[2Б Длина данных (BE)]
[NБ Данные]Конец сессии (Status=0x03)
Только заголовок фрейма, без дополнительных полей.
Формат XUDP-фреймов
Та же структура, что и Mux, но:
- ID сессии всегда
0x0000 - Первый фрейм включает 8-байтный GlobalID после адреса
- Keep-фреймы включают адрес назначения для каждого пакета
Новая сессия XUDP
[2Б Длина метаданных]
[00 00] ID сессии = 0
[01] Статус = New
[01] Опция = Data
[02] Сеть = UDP
[2Б Port (BE)]
[1Б Тип адреса]
[NБ Адрес]
[8Б GlobalID] Хэш BLAKE3 адреса источника клиента
[2Б Длина данных (BE)]
[NБ UDP-полезная нагрузка]XUDP Keep (последующие пакеты)
[2Б Длина метаданных]
[00 00] ID сессии = 0
[02] Статус = Keep
[01] Опция = Data
[02] Сеть = UDP (если присутствует назначение пакета)
[2Б Port (BE)] (назначение этого пакета)
[1Б Тип адреса]
[NБ Адрес]
[2Б Длина данных (BE)]
[NБ UDP-полезная нагрузка]Формат заполнения Vision
[16Б UserUUID] (только в первом фрейме, далее опускается)
[1Б Команда] 0x00=Continue, 0x01=End, 0x02=Direct
[2Б Длина содержимого (BE)]
[2Б Длина заполнения (BE)]
[NБ Содержимое]
[NБ Заполнение (случайные байты)]Несколько блоков заполнения могут быть объединены в одну запись.
Кодирование адресов
Все протоколы используют одинаковое кодирование адресов:
IPv4: Type=0x01, далее 4 байта
Domain: Type=0x02, далее 1 байт длины + строка домена
IPv6: Type=0x03, далее 16 байтПорт всегда 2 байта big-endian, записывается перед адресом (порядок порт-затем-адрес).
Ключевые замечания по совместимости
Кодирование UUID: Сырые 16 байт, НЕ строковая форма с дефисами.
Проводной формат protobuf: VLESS addons используют стандартное protobuf-кодирование. Префикс длины — один байт (не varint), что ограничивает addons 255 байтами.
XUDP session ID 0: Именно так сервер отличает XUDP от обычного mux. ID сессий обычного mux начинаются с 1.
Магический порт XUDP 666: Когда VLESS outbound конвертирует UDP в XUDP, он использует адрес
v1.mux.coolс портом666. Это соглашение, а не деталь проводного формата (адрес передаётся как часть заголовка VLESS).Vision UserUUID один раз: 16-байтный UUID появляется только в первом фрейме заполнения. Если первый фрейм не начинается с ожидаемого UUID, сервер переходит в режим без Vision.
Пароль Trojan в hex: SHA224(password) кодируется как 56 символов hex в нижнем регистре (ASCII), а не в бинарном формате.
Временное окно VMess: Временная метка в auth ID равна
time.Now().Unix() / 30. Сервер принимает +/-120 секунд (8 временных периодов).Порядок байтов: Все многобайтовые целые числа передаются в формате big-endian, если не указано иное.
Обнаружение фоллбэка VLESS: Если первые 17 байт (версия + UUID) не совпадают ни с одним пользователем, и фоллбэк включён, все буферизованные данные пересылаются к назначению фоллбэка.
Флаг Cone-режима: Значение контекста
coneопределяет, использует ли UDP формат XUDP (cone=true) или индивидуальные mux-сессии (cone=false). Это влияет на используемый проводной формат.