Skip to content

Совместимость на уровне протокола

Эта страница документирует точные форматы данных на уровне проводного протокола, необходимые для взаимодействия с существующими экземплярами 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:

protobuf
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, записывается перед адресом (порядок порт-затем-адрес).

Ключевые замечания по совместимости

  1. Кодирование UUID: Сырые 16 байт, НЕ строковая форма с дефисами.

  2. Проводной формат protobuf: VLESS addons используют стандартное protobuf-кодирование. Префикс длины — один байт (не varint), что ограничивает addons 255 байтами.

  3. XUDP session ID 0: Именно так сервер отличает XUDP от обычного mux. ID сессий обычного mux начинаются с 1.

  4. Магический порт XUDP 666: Когда VLESS outbound конвертирует UDP в XUDP, он использует адрес v1.mux.cool с портом 666. Это соглашение, а не деталь проводного формата (адрес передаётся как часть заголовка VLESS).

  5. Vision UserUUID один раз: 16-байтный UUID появляется только в первом фрейме заполнения. Если первый фрейм не начинается с ожидаемого UUID, сервер переходит в режим без Vision.

  6. Пароль Trojan в hex: SHA224(password) кодируется как 56 символов hex в нижнем регистре (ASCII), а не в бинарном формате.

  7. Временное окно VMess: Временная метка в auth ID равна time.Now().Unix() / 30. Сервер принимает +/-120 секунд (8 временных периодов).

  8. Порядок байтов: Все многобайтовые целые числа передаются в формате big-endian, если не указано иное.

  9. Обнаружение фоллбэка VLESS: Если первые 17 байт (версия + UUID) не совпадают ни с одним пользователем, и фоллбэк включён, все буферизованные данные пересылаются к назначению фоллбэка.

  10. Флаг Cone-режима: Значение контекста cone определяет, использует ли UDP формат XUDP (cone=true) или индивидуальные mux-сессии (cone=false). Это влияет на используемый проводной формат.

Технический анализ для целей повторной реализации.