Browse Source

translate /developerment/ section (#583)

pull/584/head
Nikita Korotaev 2 months ago committed by GitHub
parent
commit
d3e8b62f2c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 3
      docs/ru/README.md
  2. 44
      docs/ru/development/README.md
  3. 50
      docs/ru/development/intro/compile.md
  4. 50
      docs/ru/development/intro/design.md
  5. 170
      docs/ru/development/intro/guide.md
  6. 130
      docs/ru/development/protocols/mkcp.md
  7. 168
      docs/ru/development/protocols/muxcool.md
  8. 100
      docs/ru/development/protocols/vless.md
  9. 307
      docs/ru/development/protocols/vmess.md

3
docs/ru/README.md

@ -75,8 +75,7 @@ footer: Лицензия CC-BY-SA 4.0 | Авторские права 2020-на
- [Project VLESS Group](https://t.me/projectVless)
- The official Xray-core group for non-Chinese participants. Sister group of [Project X](https://t.me/projectXray)
- No advertising, No insults, No politics.
- Официальная группа для некитайскоговорящих пользователей (в основном русскоязычных).
- [Канал Project X](https://t.me/projectXtls)

44
docs/ru/development/README.md

@ -1,41 +1,43 @@
# 开发指南
# Руководство по разработке
## 编译文档
## Сборка документации
Xray 支持各种平台, 您可以在多种平台上自行进行交叉编译。
Xray поддерживает различные платформы, и вы можете самостоятельно выполнить кросс-компиляцию на многих из них.
请点击[编译文档](./intro/compile.md)以查看具体编译相关内容。
Перейдите в [документацию по сборке](./intro/compile.md), чтобы узнать больше о процессе сборки.
## 设计思路
## Принципы проектирования
Xray 内核提供了一个平台,在其之上可以进二次开发。
Ядро Xray предоставляет платформу, на основе которой можно выполнять дальнейшую разработку.
这个章节阐述了 Xray 的设计目标和架构。
В этом разделе описываются цели проектирования и архитектура Xray.
请点击[设计思路](./intro/design.md)以了解 Xray 的设计目标和架构。
Перейдите в раздел [Принципы проектирования](./intro/design.md), чтобы узнать больше о целях проектирования и архитектуре Xray.
## 开发规范
## Правила разработки
这个章节阐述了获取代码,进行开发,提交 PR 的流程中需要遵循的准则, 以及相关的编码规范。
В этом разделе описываются правила, которым необходимо следовать при получении кода, разработке и отправке запросов на включение изменений (pull request), а также соответствующие стандарты кодирования.
请点击[开发规范](./intro/guide.md)查看 Xray 开发中应遵循的准则。
Перейдите в раздел [Правила разработки](./intro/guide.md), чтобы ознакомиться с правилами, которых следует придерживаться при разработке Xray.
## 协议详解
## Подробное описание протоколов
Xray 用到了很多种协议, 您可以通过各种途径获得协议的详细描述。
Xray использует множество различных протоколов, и вы можете получить их подробное описание различными способами.
### [VLESS 协议](./protocols/vless.md)
### [Протокол VLESS](./protocols/vless.md)
VLESS 是一个无状态的轻量传输协议,可以作为 Xray 客户端和服务器之间的桥梁。
VLESS - это легковесный транспортный протокол без сохранения состояния, который может служить мостом между клиентом и сервером Xray.
### [VMess 协议](./protocols/vmess.md)
### [Протокол VMess](./protocols/vmess.md)
VMess 是一个加密传输协议,可以作为 Xray 客户端和服务器之间的桥梁。
VMess - это зашифрованный транспортный протокол, который может служить мостом между клиентом и сервером Xray.
### [Mux.Cool 协议](./protocols/muxcool.md)
### [Протокол Mux.Cool](./protocols/muxcool.md)
Mux.Cool 协议是一个多路复用传输协议,用于在一条已建立的数据流中传输多个各自独立的数据流。
Протокол Mux.Cool - это транспортный протокол мультиплексирования, который используется для передачи нескольких независимых потоков данных по одному установленному потоку данных.
### [Протокол mKCP](./protocols/mkcp.md)
mKCP - это потоковый транспортный протокол, основанный на [протоколе KCP](https://github.com/skywind3000/kcp), который может передавать любые потоки данных по порядку.
### [mKCP 协议](./protocols/mkcp.md)
mKCP 是流式传输协议,由 [KCP 协议](https://github.com/skywind3000/kcp)修改而来,可以按顺序传输任意的数据流。

50
docs/ru/development/intro/compile.md

@ -1,37 +1,37 @@
# 编译文档
# Документация по сборке
## 前序工作
## Подготовка
Xray 使用 [Golang](https://golang.org/) 作为编程语言,你需要先安装最新版本 Golang 才能够编译。
Xray использует [Golang](https://golang.org/) в качестве языка программирования, поэтому вам необходимо сначала установить последнюю версию Golang, чтобы иметь возможность выполнить сборку.
::: tip TIP
安装 Golang: [golang.org/doc/install](https://golang.org/doc/install)
::: tip СОВЕТ
Установка Golang: [golang.org/doc/install](https://golang.org/doc/install)
:::
> 如果你不幸使用 Windows, 请 **务必** 使用 Powershell
> Если вы, к сожалению, используете Windows, **обязательно** используйте Powershell.
## 拉取 Xray 源代码
## Получение исходного кода Xray
```bash
git clone https://github.com/XTLS/Xray-core.git
cd Xray-core && go mod download
```
> 如果你闲的没事干,可以试试 GitHub 官方工具: `gh repo clone XTLS/Xray-core`
> Если вам нечем заняться, можете попробовать официальный инструмент GitHub: `gh repo clone XTLS/Xray-core`.
注意:在无法正常访问 Google 的网络环境,依赖无法被正常拉取,需要先设置 `GOPROXY`
Примечание: в сетевых средах, где нет доступа к Google, зависимости не могут быть получены обычным способом, поэтому необходимо сначала установить `GOPROXY`:
```bash
go env -w GOPROXY=https://goproxy.io,direct
```
## 构建二进制
## Сборка бинарного файла
:::warning
本小节的命令需要在 Xray 根目录内运行。
Команды в этом разделе необходимо выполнять в корневом каталоге Xray.
:::
### Windows(Powershell):
### Windows (Powershell):
```powershell
$env:CGO_ENABLED=0
@ -44,19 +44,19 @@ go build -o xray.exe -trimpath -ldflags "-s -w -buildid=" ./main
CGO_ENABLED=0 go build -o xray -trimpath -ldflags "-s -w -buildid=" ./main
```
运行以上命令会在目录下生成 xray 可执行文件。
Выполнение этих команд создаст исполняемый файл xray в текущем каталоге.
::: tip
如果需要编译可以进行 debug 的程序,即可以用 dlv 附加到运行的程序进行调试, 请去掉 ldflags 中的 '-w -s' 选项.
Если вам нужно собрать программу с поддержкой отладки, то есть такую, к которой можно подключиться с помощью dlv для отладки, удалите опции '-w -s' из ldflags.
-w 禁止生成 debug 信息。使用该选项后,将无法使用 gdb 进行调试。
-s 禁用符号表
PS:其实用 vscode 或其他 IDE 调试似乎更方便。
-w отключает генерацию отладочной информации. Если эта опция используется, отладка с помощью gdb будет невозможна.
-s отключает таблицу символов.
P.S.: На самом деле отладка с помощью vscode или другой IDE может быть более удобной.
:::
## 交叉编译:
## Кросс-компиляция:
这里以在 Windows(Powershell) 环境中,编译到 Linux 服务器为例:
В качестве примера рассмотрим компиляцию в среде Windows (Powershell) для сервера Linux:
```powershell
$env:CGO_ENABLED=0
@ -66,16 +66,18 @@ $env:GOARCH="amd64"
go build -o xray -trimpath -ldflags "-s -w -buildid=" ./main
```
上传到服务器后,记得在服务器终端内执行 `chmod +x xray`
После загрузки на сервер не забудьте выполнить команду `chmod +x xray` в терминале сервера.
::: tip
执行 `go tool dist list` 查看所有支持的系统与架构。
Выполните команду `go tool dist list`, чтобы просмотреть все поддерживаемые системы и архитектуры.
:::
## 可复现构建:
## Воспроизводимая сборка:
按照上述步骤,能够编译与 Release 中完全相同的二进制文件。
Выполнив описанные выше шаги, вы можете собрать бинарный файл, идентичный тому, что находится в релизе.
::: warning
请先确认您使用的 Golang 版本与编译 Release 的一致。
Убедитесь, что вы используете ту же версию Golang, что и для сборки релиза.
:::

50
docs/ru/development/intro/design.md

@ -1,43 +1,47 @@
# 设计目标
# Цели проектирования
- Xray 内核提供了一个平台,支持必要的网络代理功能,在其之上可以进二次开发,以提供更好的用户体验;
- 以跨平台为首要原则,以减少二次开发的成本;
- Ядро Xray предоставляет платформу, которая поддерживает необходимые функции сетевого прокси, и на ее основе можно выполнять дальнейшую разработку для улучшения пользовательского опыта.
- Кроссплатформенность является основным принципом, чтобы снизить затраты на вторичную разработку.
## 架构
## Архитектура
![Architecture](./framework.png)
内核分为三层:应用层、代理层和传输层。
Ядро состоит из трех уровней: уровня приложений, уровня прокси и транспортного уровня.
每一层内包含数个模块,模块间互相独立,同类型的模块可无缝替换。
Каждый уровень содержит несколько модулей, которые независимы друг от друга, и модули одного типа могут быть легко заменены.
### 应用层
### Уровень приложений
应用层包含一些代理层中常用的功能,这些功能被抽象出来,以便在不同的代理模块中复用。
Уровень приложений содержит некоторые функции, которые часто используются на уровне прокси. Эти функции абстрагированы, чтобы их можно было повторно использовать в разных модулях прокси.
应用层的模块应为纯软件实现,与硬件或平台相关的技术无关。
Модули уровня приложений должны быть реализованы чисто программным способом, без привязки к аппаратному обеспечению или платформе.
重要模块列表:
Список важных модулей:
- Dispatcher: 用于把入站代理所接收到的数据,传送给出站代理;
- Router: 路由模块,详见 [路由配置](../../config/routing.md);
- DNS: 内置的 DNS 服务器模块;
- Proxy Manager: 代理管理器;
- Dispatcher: используется для передачи данных, полученных входящим прокси, исходящему прокси;
- Router: модуль маршрутизации, см. [настройки маршрутизации](../../config/routing.md);
- DNS: встроенный модуль DNS-сервера;
- Proxy Manager: менеджер прокси;
### 代理层
### Уровень прокси
代理层分为两部分:入站代理(Inbound Proxy)和出站代理(Outbound Proxy)。
Уровень прокси делится на две части: входящий прокси (Inbound Proxy) и исходящий прокси (Outbound Proxy).
两部分相互独立,入站代理不依赖于某个特定的出站代理,反之亦然。
Эти две части независимы друг от друга, входящий прокси не зависит от какого-либо конкретного исходящего прокси, и наоборот.
#### 入站代理
#### Входящий прокси
- 实现 [proxy.Inbound](https://github.com/xtls/Xray-core/blob/main/proxy/proxy.go) 接口;
- Реализует интерфейс [proxy.Inbound](https://github.com/xtls/Xray-core/blob/main/proxy/proxy.go);
#### Исходящий прокси
- Реализует интерфейс [proxy.Outbound](https://github.com/xtls/Xray-core/blob/main/proxy/proxy.go);
### Транспортный уровень
Транспортный уровень предоставляет модули инструментов, связанных с передачей сетевых данных.
#### 出站代理
- 实现 [proxy.Outbound](https://github.com/xtls/Xray-core/blob/main/proxy/proxy.go) 接口;
### 传输层
传输层提供一些网络数据传输相关的工具模块。

170
docs/ru/development/intro/guide.md

@ -1,131 +1,135 @@
# 开发规范
# Правила разработки
## 基本
## Основные принципы
### 版本控制
### Система контроля версий
Project X 的代码被托管在 github 上:
Код проекта X размещен на GitHub:
- Xray 核心 [Xray-core](https://github.com/XTLS/Xray-core)
- 安装脚本 [Xray-install](https://github.com/XTLS/Xray-install)
- 配置模板 [Xray-examples](https://github.com/XTLS/Xray-examples)
- Xray 文档 [Xray-docs-next](https://github.com/XTLS/Xray-docs-next)
- Ядро Xray [Xray-core](https://github.com/XTLS/Xray-core)
- Скрипты установки [Xray-install](https://github.com/XTLS/Xray-install)
- Шаблоны конфигурации [Xray-examples](https://github.com/XTLS/Xray-examples)
- Документация по Xray [Xray-docs-next](https://github.com/XTLS/Xray-docs-next)
您可以使用 [Git](https://git-scm.com/) 来获取代码。
Вы можете использовать [Git](https://git-scm.com/) для получения кода.
### 分支(Branch)
### Ветки (Branch)
- 本项目的主干分支为 main,
- 本项目的发布主分支同为 main,
- 需要确保 main 在任一时刻都是可编译,且可正常使用的。
- 如果需要开发新的功能,请新建分支进行开发,在开发完成并且经过充分测试后,合并回主干分支。
- 已经合并入主干且没有必要存在的分支,请删除。
- Основной веткой проекта является main.
- Основной веткой для выпуска релизов также является main.
- Необходимо убедиться, что main в любой момент времени может быть скомпилирован и работает корректно.
- Если вам нужно разработать новую функцию, создайте новую ветку для разработки. После завершения разработки и тщательного тестирования объедините ее с основной веткой.
- Удалите ветки, которые были объединены с основной веткой и больше не нужны.
### 发布(Release)
### Релизы (Release)
<Badge text="WIP" type="warning"/>
<Badge text="В РАЗРАБОТКЕ" type="warning"/>
- 建立尝鲜版本和稳定版本两个发布通道
- 尝鲜版本,可以为 daily build,主要用于特定情况的测试,尝鲜和获得即时反馈和再改进。
- 稳定版本,为定时更新(比如月更),合并稳定的修改并发布。
- Создайте два канала выпуска: для предварительных версий и для стабильных версий.
- Предварительные версии могут быть ежедневными сборками, в основном используются для тестирования в определенных ситуациях, ознакомления с новыми функциями и получения обратной связи для дальнейшего улучшения.
- Стабильные версии выпускаются по расписанию (например, ежемесячно) и содержат стабильные изменения.
### 引用其它项目
### Использование других проектов
- Golang
- 产品代码建议使用 Golang 标准库和 [golang.org/x/](https://pkg.go.dev/search?limit=25&m=package&q=golang.org%2Fx) 下的库;
- 如需引用其它项目,请事先创建 issue 讨论;
- 其它
- 不违反双方的协议,且对项目有帮助的工具,都可以使用。
- В коде рекомендуется использовать стандартную библиотеку Golang и библиотеки из [golang.org/x/](https://pkg.go.dev/search?limit=25&m=package&q=golang.org%2Fx).
- Если вам нужно использовать другие проекты, сначала создайте issue для обсуждения.
- Другие
- Можно использовать любые инструменты, которые не нарушают лицензии обеих сторон и полезны для проекта.
## 开发流程
## Процесс разработки
### 写代码之前
### Перед написанием кода
发现任何问题,或对项目有任何想法,请创建 [issue](https://github.com/XTLS/Xray-core/issues) 讨论以减少重复劳动和消耗在代码上的时间。
Если вы обнаружили какую-либо проблему или у вас есть идеи по улучшению проекта, создайте [issue](https://github.com/XTLS/Xray-core/issues) для обсуждения, чтобы избежать дублирования усилий и траты времени на написание кода.
### 修改代码
### Изменение кода
- Golang
- 请参考 [Effective Go](https://golang.org/doc/effective_go.html)
- 每一次 push 之前,请运行:`go generate core/format.go`;
- 如果需要修改 protobuf,例如增加新配置项,请运行:`go generate core/proto.go`;
- 提交 pull request 之前,建议测试通过:`go test ./...`;
- 提交 pull request 之前,建议新增代码有超过 70% 的代码覆盖率(code coverage);
- 其它
- 请注意代码的可读性。
- См. [Effective Go](https://golang.org/doc/effective_go.html).
- Перед каждой отправкой (push) выполните команду: `go generate core/format.go`.
- Если вам нужно изменить protobuf, например, добавить новый параметр конфигурации, выполните команду: `go generate core/proto.go`.
- Перед отправкой pull request рекомендуется запустить тесты: `go test ./...`.
- Перед отправкой pull request рекомендуется, чтобы новый код имел покрытие кода (code coverage) не менее 70%.
- Другие
- Обратите внимание на читаемость кода.
### Pull Request
### Запрос на включение изменений (Pull Request)
- 提交 PR 之前,请先运行 `git pull https://github.com/XTLS/Xray-core.git` 以确保 merge 可顺利进行;
- 一个 PR 只做一件事,如有对多个 bug 的修复,请对每一个 bug 提交一个 PR;
- 由于 Golang 的特殊需求(Package path),Go 项目的 PR 流程和其它项目有所不同,建议流程如下:
1. 先 Fork 本项目,创建你自己的 `github.com/<your_name>/Xray-core.git` 仓库;
2. 克隆你自己的 Xray 仓库到本地:`git clone https://github.com/<your_name>/Xray-core.git`;
3. 基于 `main` 分支创建新的分支,例如 `git branch issue24 main`
4. 在新创建的分支上作修改并提交修改(commit);
5. 在推送(push)修改完成的分支到自己的仓库前,先切换到 `main` 分支,运行 `git pull https://github.com/XTLS/Xray-core.git` 拉取最新的远端代码;
6. 如果上一步拉取得到了新的远端代码,则切换到之前自己创建的分支,运行 `git rebase main` 执行分支合并操作。如遇到文件冲突,则需要解决冲突;
7. 上一步处理完毕后,就可以把自己创建的分支推送到自己的仓库:`git push -u origin your-branch`
8. 最后,把自己仓库的新推送的分支往 `XTLS/Xray-core``main` 分支发 PR 即可;
9. 请在 PR 的标题和正文中,完整表述此次 PR 解决的问题 / 新增的功能 / 代码所做的修改的用意等;
10. 耐心等待开发者的回应。
- Перед отправкой PR сначала выполните команду `git pull https://github.com/XTLS/Xray-core.git`, чтобы убедиться, что слияние пройдет гладко.
- Один PR должен решать только одну задачу. Если вы исправляете несколько ошибок, отправьте по одному PR для каждой ошибки.
- Из-за особенностей Golang (пути к пакетам) процесс PR для проектов Go отличается от других проектов. Рекомендуемый процесс следующий:
1. Сначала сделайте форк (fork) проекта, создайте свой собственный репозиторий `github.com/<your_name>/Xray-core.git`.
2. Клонируйте свой репозиторий Xray локально: `git clone https://github.com/<your_name>/Xray-core.git`.
3. Создайте новую ветку на основе ветки `main`, например, `git branch issue24 main`.
4. Внесите изменения в новую ветку и зафиксируйте их (commit).
5. Перед отправкой (push) измененной ветки в свой репозиторий переключитесь на ветку `main` и выполните команду `git pull https://github.com/XTLS/Xray-core.git`, чтобы получить последнюю версию кода.
6. Если на предыдущем шаге были получены новые изменения, переключитесь на созданную вами ветку и выполните команду `git rebase main` для слияния веток. Если возникнут конфликты файлов, их необходимо разрешить.
7. После завершения предыдущего шага вы можете отправить свою ветку в свой репозиторий: `git push -u origin your-branch`.
8. Наконец, отправьте PR из своей ветки в ветку `main` репозитория `XTLS/Xray-core`.
9. В заголовке и описании PR четко опишите проблему, которую решает этот PR / новую функцию / цель изменений кода.
10. Дождитесь ответа разработчиков.
### 对代码的修改
### Изменения кода
#### 功能性问题
#### Проблемы с функциональностью
请提交至少一个测试用例(Test Case)来验证对现有功能的改动。
Отправьте хотя бы один тестовый пример (Test Case), чтобы проверить изменения в существующей функциональности.
#### 性能相关
#### Проблемы с производительностью
请提交必要的测试数据来证明现有代码的性能缺陷,或是新增代码的性能提升。
Отправьте необходимые тестовые данные, чтобы подтвердить проблемы с производительностью существующего кода или улучшение производительности нового кода.
#### 新功能
#### Новые функции
- 如果新增功能对已有功能不影响,请提供可以开启/关闭的开关(如 flag),并使新功能保持默认关闭的状态;
- 大型新功能(比如增加一个新的协议)开发之前,请先提交一个 issue,讨论完毕之后再进行开发。
- Если новая функция не влияет на существующую функциональность, предоставьте переключатель (например, флаг) для ее включения/отключения и оставьте ее отключенной по умолчанию.
- Перед разработкой новой крупной функции (например, добавления нового протокола) создайте issue для обсуждения.
#### 其它
#### Другое
视具体情况而定。
Зависит от конкретной ситуации.
## Xray 编码规范
## Стандарты кодирования Xray
以下内容适用于 Xray 中的 Golang 代码。
Следующие правила применяются к коду Golang в Xray.
### 代码结构
### Структура кода
```
Xray-core
├── app // 应用模块
│ ├── router // 路由
├── common // 公用代码
├── proxy // 通讯协议
├── app // Модули приложений
│ ├── router // Маршрутизация
├── common // Общий код
├── proxy // Протоколы связи
│ ├── blackhole
│ ├── dokodemo-door
│ ├── freedom
│ ├── socks
│ ├── vmess
├── transport // 传输模块
├── transport // Транспортные модули
```
### 编码规范
### Стандарты кодирования
基本与 Golang 官方所推荐做法一致,有一些例外。写在这里以方便大家熟悉 Golang。
В основном соответствуют рекомендациям Golang, за некоторыми исключениями. Приведены здесь для удобства ознакомления с Golang.
#### Именование
- Для имен файлов и каталогов по возможности используйте одно английское слово, например, hello.go.
- Если это невозможно, используйте дефисы для разделения слов в имени каталога и подчеркивания для разделения слов в имени файла, например, hello-world/hello_again.go.
- Тестовый код должен иметь суффикс _test.go.
- Для типов используйте нотацию PascalCase, например, ConnectionHandler.
- Сокращения не обязательно писать в нижнем регистре, то есть HTML не нужно писать как Html.
- Для публичных переменных-членов также используйте нотацию PascalCase.
- Для приватных переменных-членов используйте [нотацию camelCase](https://ru.wikipedia.org/wiki/CamelCase), например, `privateAttribute`.
- Для удобства рефакторинга рекомендуется использовать нотацию PascalCase для всех методов.
- Полностью приватные типы помещайте в каталог `internal`.
#### Организация кода
- Один файл должен содержать один основной тип и связанные с ним приватные функции.
- Тестовые файлы, такие как Mock и другие утилиты, помещайте в подкаталог testing.
#### 命名
- 文件和目录名尽量使用单个英文单词,比如 hello.go;
- 如果实在没办法,则目录使用连接线/文件名使用下划线连接两个(或多个单词),比如 hello-world/hello_again.go;
- 测试代码使用 \_test.go 结尾;
- 类型使用 Pascal 命名法,比如 ConnectionHandler;
- 对缩写不强制小写,即 HTML 不必写成 Html;
- 公开成员变量也使用 Pascal 命名法;
- 私有成员变量使用 [小驼峰式命名法](https://zh.wikipedia.org/wiki/%E9%A7%9D%E5%B3%B0%E5%BC%8F%E5%A4%A7%E5%B0%8F%E5%AF%AB) ,如 `privateAttribute`
- 为了方便重构,方法建议全部使用 Pascal 命名法;
- 完全私有的类型放入 `internal`
#### 内容组织
- 一个文件包含一个主要类型,及其相关的私有函数等;
- 测试相关的文件,如 Mock 等工具类,放入 testing 子目录。

130
docs/ru/development/protocols/mkcp.md

@ -1,92 +1,96 @@
# mKCP 协议
# Протокол mKCP
mKCP 是流式传输协议,由 [KCP 协议](https://github.com/skywind3000/kcp) 修改而来,可以按顺序传输任意的数据流。
mKCP - это потоковый транспортный протокол, основанный на [протоколе KCP](https://github.com/skywind3000/kcp), который может передавать любые потоки данных по порядку.
## 版本
## Версия
mKCP 没有版本号,不保证版本之间兼容性。
Протокол mKCP не имеет номера версии, совместимость между версиями не гарантируется.
## 依赖
## Зависимости
### 底层协议
### Базовый протокол
mKCP 是一个基于 UDP 的协议,所有通讯使用 UDP 传输。
mKCP - это протокол, основанный на UDP, все коммуникации осуществляются по UDP.
### 函数
### Функции
- fnv: [FNV-1a](https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function) 哈希函数
- 输入参数为任意长度的字符串;
- 输入出一个 32 位无符号整数;
- fnv: хэш-функция [FNV-1a](https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function)
- Входные данные: строка произвольной длины;
- Выходные данные: 32-битное беззнаковое целое число;
## 通讯过程
## Процесс коммуникации
1. mKCP 将数据流拆成若干个数据包进行发送。一个数据流有一个唯一标识,用以区分不同的数据流。数据流中的每一个数据包都携带了同样的标识。
1. mKCP 没有握手过程,当收到一个数据包时,根据其携带的数据流的标识来判断是否为新的通话,或是正在进行中的通话。
1. 每一个数据包中包含若干个片段(Segment),片段分为三类:数据(Data)、确认(ACK)、心跳(Ping)。每个片段需要单独处理。
1. mKCP разбивает поток данных на несколько пакетов для отправки. Каждый поток данных имеет уникальный идентификатор, который используется для различения разных потоков данных. Каждый пакет данных в потоке данных несет один и тот же идентификатор.
2. У mKCP нет процесса рукопожатия. При получении пакета данных определяется, является ли это новым вызовом или текущим вызовом, на основе идентификатора потока данных, который он несет.
3. Каждый пакет данных содержит несколько сегментов (Segment), которые делятся на три типа: данные (Data), подтверждение (ACK) и пульс (Ping). Каждый сегмент обрабатывается отдельно.
## 数据格式
## Формат данных
### 数据包
### Пакет данных
| 4 字节 | 2 字节 | L 字节 |
| ---------- | ---------- | -------- |
| 认证信息 A | 数据长度 L | 片段部分 |
| 4 байта | 2 байта | L байт |
|---------------------------------|----------------|------------------|
| Информация для аутентификации A | Длина данных L | Сегментная часть |
其中:
Где:
- 认证信息 A = fnv(片段部分),big endian;
- 片段部分可能包含多个片段;
- Информация для аутентификации A = fnv(сегментная часть), big endian;
- Сегментная часть может содержать несколько сегментов;
### 数据片段
### Сегмент данных
| 2 字节 | 1 字节 | 1 字节 | 4 字节 | 4 字节 | 4 字节 | 2 字节 | Len 字节 |
| --------- | -------- | -------- | --------- | --------- | ---------------- | -------- | -------- |
| 标识 Conv | 指令 Cmd | 选项 Opt | 时间戳 Ts | 序列号 Sn | 未确认序列号 Una | 长度 Len | 数据 |
| 2 байта | 1 байт | 1 байт | 4 байта | 4 байта | 4 байта | 2 байта | Len байт |
|--------------------|-------------|-----------|--------------------|---------------------|---------------------------------------|-----------|----------|
| Идентификатор Conv | Команда Cmd | Опция Opt | Временная метка Ts | Порядковый номер Sn | Неподтвержденный порядковый номер Una | Длина Len | Данные |
其中:
Где:
- 标识 Conv: mKCP 数据流的标识
- 指令 Cmd: 常量 0x01
- 选项 Opt: 可选的值有:
- 0x00: 空选项
- 0x01: 对方已发出所有数据
- 时间戳 Ts: 当前片段从远端发送出来时的时间,big endian
- 序列号 Sn: 该数据片段时数据流中的位置,起始片段的序列号为 0,之后每个新片段按顺序加 1
- 未确认序列号 Una: 远端主机正在发送的,且尚未收到确认的最小的 Sn
- Идентификатор Conv: идентификатор потока данных mKCP
- Команда Cmd: константа 0x01
- Опция Opt: возможные значения:
- 0x00: пустая опция
- 0x01: другая сторона отправила все данные
- Временная метка Ts: время отправки текущего сегмента с удаленной стороны, big endian
- Порядковый номер Sn: позиция сегмента данных в потоке данных, порядковый номер начального сегмента равен 0, каждый последующий сегмент увеличивается на 1
- Неподтвержденный порядковый номер Una: минимальный Sn, который отправляется удаленным хостом и еще не получил подтверждение
### 确认片段
### Сегмент подтверждения
| 2 字节 | 1 字节 | 1 字节 | 4 字节 | 4 字节 | 4 字节 | 2 字节 | Len \* 4 字节 |
| --------- | -------- | -------- | -------- | ----------------- | --------- | -------- | -------------- |
| 标识 Conv | 指令 Cmd | 选项 Opt | 窗口 Wnd | 下一接收序列号 Sn | 时间戳 Ts | 长度 Len | 已收到的序列号 |
| 2 байта | 1 байт | 1 байт | 4 байта | 4 байта | 4 байта | 2 байта | Len * 4 байта |
|--------------------|-------------|-----------|----------|------------------------------------------|--------------------|-----------|----------------------------------|
| Идентификатор Conv | Команда Cmd | Опция Opt | Окно Wnd | Следующий порядковый номер для приема Sn | Временная метка Ts | Длина Len | Подтвержденные порядковые номера |
其中:
Где:
- 标识 Conv: mKCP 数据流的标识
- 指令 Cmd: 常量 0x00
- 选项 Opt: 同上
- 窗口 Wnd: 远端主机可以接收的最大序列号
- 下一接收序列号 Sn: 远端主机未收到的数据片段中的最小序列号
- 时间戳 Ts: 远端主机最新收到的数据片段的时间戳,可用于计算延迟
- 已收到的序列号: 每个 4 字节,表示此序列号的数据已经确认收到
- Идентификатор Conv: идентификатор потока данных mKCP
- Команда Cmd: константа 0x00
- Опция Opt: как указано выше
- Окно Wnd: максимальный порядковый номер, который может принять удаленный хост
- Следующий порядковый номер для приема Sn: минимальный порядковый номер сегмента данных, который не получил удаленный хост
- Временная метка Ts: временная метка последнего полученного сегмента данных удаленным хостом, может использоваться для расчета задержки
- Подтвержденные порядковые номера: каждые 4 байта указывают, что данные с этим порядковым номером получены и подтверждены
注释:
Комментарий:
- 远程主机期待收到序列号 [Sn, Wnd) 范围内的数据
- Удаленный хост ожидает получения данных с порядковыми номерами в диапазоне [Sn, Wnd)
### Сегмент пульса
| 2 байта | 1 байт | 1 байт | 4 байта | 4 байта | 4 байта |
|--------------------|-------------|-----------|---------------------------------------|------------------------------------------|--------------|
| Идентификатор Conv | Команда Cmd | Опция Opt | Неподтвержденный порядковый номер Una | Следующий порядковый номер для приема Sn | Задержка Rto |
Где:
- Идентификатор Conv: идентификатор потока данных mKCP
- Команда Cmd: возможные значения:
- 0x02: удаленный хост принудительно завершает сеанс
- 0x03: обычный пульс
- Опция Opt: как указано выше
- Неподтвержденный порядковый номер Una: тот же, что и Una в сегменте данных
- Следующий порядковый номер для приема Sn: тот же, что и Sn в сегменте подтверждения
- Задержка Rto: задержка, рассчитанная самим удаленным хостом
### 心跳片段
| 2 字节 | 1 字节 | 1 字节 | 4 字节 | 4 字节 | 4 字节 |
| --------- | -------- | -------- | ---------------- | ----------------- | -------- |
| 标识 Conv | 指令 Cmd | 选项 Opt | 未确认序列号 Una | 下一接收序列号 Sn | 延迟 Rto |
其中:
- 标识 Conv: mKCP 数据流的标识
- 指令 Cmd: 可选的值有
- 0x02: 远端主机强行终止会话
- 0x03: 正常心跳
- 选项 Opt: 同上
- 未确认序列号 Una: 同数据片段的 Una
- 下一接收序列号 Sn: 同确认片段的 Sn
- 延迟 Rto: 远端主机自己计算出的延迟

168
docs/ru/development/protocols/muxcool.md

@ -1,129 +1,133 @@
# Mux.Cool 协议
# Протокол Mux.Cool
Mux.Cool 协议是一个多路复用传输协议,用于在一条已建立的数据流中传输多个各自独立的数据流。
Протокол Mux.Cool - это мультиплексирующий транспортный протокол, используемый для передачи нескольких независимых потоков данных по одному установленному потоку данных.
## 版本
## Версия
当前版本是 1 Beta。
Текущая версия - 1 Beta.
## 依赖
## Зависимости
### 底层协议
### Базовый протокол
Mux.Cool 必须运行在一个已建立的可靠数据流之上。
Mux.Cool должен работать поверх установленного надежного потока данных.
## 通讯过程
## Процесс коммуникации
一个 Mux.Cool 连接中可传输若干个子连接,每个子连接有一个独立的 ID 和状态。传输过程由帧(Frame)组成,每一帧用于传输一个特定的子连接的数据。
Одно соединение Mux.Cool может передавать несколько подсоединений, каждое из которых имеет свой собственный идентификатор и состояние. Процесс передачи состоит из кадров (Frame), каждый из которых используется для передачи данных определенного подсоединения.
### 客户端行为
### Поведение клиента
当有连接需求时并且没有现有可用的连接时,客户端向服务器发起一个新连接,以下称为“主连接”。
Когда требуется соединение и нет доступного существующего соединения, клиент инициирует новое соединение с сервером, которое далее называется "главным соединением".
1. 一个主连接可用于发送若干个子连接。客户端可自主决定主连接可承载的子连接数量。
1. 对于一个新的子连接,客户端必须发送状态`New`以通知服务器建立子连接,然后使用状态`Keep`来传送数据。
1. 当子连接结束时,客户端发送`End`状态来通知服务器关闭子连接。
1. 客户端可自行决定何时关闭主连接,但必须确定服务器也同时保持连接。
1. 客户端可使用 KeepAlive 状态来避免服务器关闭主连接。
1. Одно главное соединение может использоваться для отправки нескольких подсоединений. Клиент может самостоятельно определять количество подсоединений, которое может нести главное соединение.
2. Для нового подсоединения клиент должен отправить состояние `New`, чтобы уведомить сервер о создании подсоединения, а затем использовать состояние `Keep` для передачи данных.
3. Когда подсоединение завершается, клиент отправляет состояние `End`, чтобы уведомить сервер о закрытии подсоединения.
4. Клиент может самостоятельно решать, когда закрыть главное соединение, но должен убедиться, что сервер также поддерживает соединение.
5. Клиент может использовать состояние KeepAlive, чтобы предотвратить закрытие главного соединения сервером.
### 服务器端行为
### Поведение сервера
当服务器端接收到新的子连接时,服务器应当按正常的连接来处理。
Когда сервер получает новое подсоединение, он должен обрабатывать его как обычное соединение.
1. 当收到状态`End`时,服务器端可以关闭对目标地址的上行连接。
1. 在服务器的响应中,必须使用与请求相同的 ID 来传输子连接的数据。
1. 服务器不能使用`New`状态。
1. 服务器可使用 KeepAlive 状态来避免客户端关闭主连接。
1. При получении состояния `End` сервер может закрыть исходящее соединение с целевым адресом.
2. В ответе сервера для передачи данных подсоединения должен использоваться тот же идентификатор, что и в запросе.
3. Сервер не может использовать состояние `New`.
4. Сервер может использовать состояние KeepAlive, чтобы предотвратить закрытие главного соединения клиентом.
## 传输格式
## Формат передачи
Mux.Cool 使用对称传输格式,即客户端和服务器发送和接收相同格式的数据。
Mux.Cool использует симметричный формат передачи, то есть клиент и сервер отправляют и получают данные в одинаковом формате.
### 帧格式
### Формат кадра
| 2 字节 | L 字节 | X 字节 |
| ------------ | ------ | -------- |
| 元数据长度 L | 元数据 | 额外数据 |
| 2 байта | L байт | X байт |
|--------------------|------------|-----------------------|
| Длина метаданных L | Метаданные | Дополнительные данные |
### 元数据
### Метаданные
元数据有若干种类型。所有类型的元数据都包含 ID 和 Opt 两项,其含义为:
Существует несколько типов метаданных. Все типы метаданных содержат поля ID и Opt, которые означают следующее:
- ID: 子连接的唯一标识
- 对于一般 Mux 子连接,ID 由 1 开始累加
- 对于 Xray 实现的 [Single XUDP](https://github.com/XTLS/Xray-core/blob/main/common/xudp/xudp.go),ID 始终为 0
- ID: уникальный идентификатор подсоединения
- Для обычных подсоединений Mux ID начинается с 1 и увеличивается
- Для [Single XUDP](https://github.com/XTLS/Xray-core/blob/main/common/xudp/xudp.go), реализованного в Xray, ID всегда равен 0
- Opt:
- D(0x01): 有额外数据
- D(0x01): есть дополнительные данные
当选项 Opt(D) 开启时,额外数据格式如下:
Если опция Opt(D) включена, формат дополнительных данных следующий:
| 2 字节 | X-2 字节 |
| -------- | -------- |
| 长度 X-2 | 数据 |
| 2 байта | X-2 байта |
|-----------|-----------|
| Длина X-2 | Данные |
### 新建子连接 (New)
### Создание нового подсоединения (New)
| 2 字节 | 1 字节 | 1 字节 | 1 字节 | 2 字节 | 1 字节 | A 字节 | 8 字节 |
| ------ | ------ | -------- | ---------- | ------ | ---------- | ------ | ---------------- |
| ID | 0x01 | 选项 Opt | 网络类型 N | 端口 | 地址类型 T | 地址 A | Global ID (XUDP) |
| 2 байта | 1 байт | 1 байт | 1 байт | 2 байта | 1 байт | A байт | 8 байт |
|---------|--------|-----------|------------|---------|--------------|---------|------------------|
| ID | 0x01 | Опция Opt | Тип сети N | Порт | Тип адреса T | Адрес A | Global ID (XUDP) |
其中:
Где:
- 网络类型 N:
- 0x01:TCP,表示当前子连接的流量应当以 TCP 的方式发送至目标。
- 0x02:UDP,表示当前子连接的流量应当以 UDP 的方式发送至目标。
- 地址类型 T:
- 0x01IPv4
- 0x02:域名
- 0x03IPv6
- 地址 A:
- 当 T = 0x01 时,A 为 4 字节 IPv4 地址;
- 当 T = 0x02 时,A 为 1 字节长度(L) + L 字节域名;
- 当 T = 0x03 时,A 为 16 字节 IPv6 地址;
- Global ID (XUDP)
- 客户端计算出 UDP 来源二元组的全局独特 ID,服务端用以确保当 XUDP 断线重连时,仍使用同一个端口与目标通信。
- Тип сети N:
- 0x01: TCP, указывает, что трафик текущего подсоединения должен быть отправлен на целевой адрес по TCP.
- 0x02: UDP, указывает, что трафик текущего подсоединения должен быть отправлен на целевой адрес по UDP.
- Тип адреса T:
- 0x01: IPv4
- 0x02: доменное имя
- 0x03: IPv6
- Адрес A:
- Если T = 0x01, A - это 4-байтовый адрес IPv4;
- Если T = 0x02, A - это 1 байт длины (L) + L байт доменного имени;
- Если T = 0x03, A - это 16-байтовый адрес IPv6;
- Global ID (XUDP):
- Клиент вычисляет глобально уникальный идентификатор исходного кортежа UDP, который сервер использует, чтобы гарантировать, что при переподключении XUDP будет использоваться тот же порт для связи с целевым адресом.
在新建子连接时,若 Opt(D) 开启,则这一帧所带的数据需要被发往目标主机。
При создании нового подсоединения, если Opt(D) включена, данные, переносимые этим кадром, должны быть отправлены на целевой хост.
### 保持子连接 (Keep)
### Поддержание подсоединения (Keep)
TCP
| 2 字节 | 1 字节 | 1 字节 |
| ------ | ------ | -------- |
| ID | 0x02 | 选项 Opt |
| 2 байта | 1 байт | 1 байт |
|---------|--------|-----------|
| ID | 0x02 | Опция Opt |
UDP
| 2 字节 | 1 字节 | 1 字节 | 1 字节 | 2 字节 | 1 字节 | A 字节 |
| ------ | ------ | -------- | ---------- | ------ | ---------- | ------ |
| ID | 0x02 | 选项 Opt | 网络类型 N | 端口 | 地址类型 T | 地址 A |
| 2 байта | 1 байт | 1 байт | 1 байт | 2 байта | 1 байт | A байт |
|---------|--------|-----------|------------|---------|--------------|---------|
| ID | 0x02 | Опция Opt | Тип сети N | Порт | Тип адреса T | Адрес A |
在保持子连接时,若 Opt(D) 开启,则这一帧所带的数据需要被发往目标主机。
XUDP 在 Opt(D) 之后加 UDP 地址,格式同新建子连接,但没有 Global ID。
При поддержании подсоединения, если Opt(D) включена, данные, переносимые этим кадром, должны быть отправлены на целевой хост.
XUDP добавляет адрес UDP после Opt(D) в том же формате, что и при создании нового подсоединения, но без Global ID.
### 关闭子连接 (End)
### Закрытие подсоединения (End)
| 2 字节 | 1 字节 | 1 字节 |
| ------ | ------ | -------- |
| ID | 0x03 | 选项 Opt |
| 2 байта | 1 байт | 1 байт |
|---------|--------|-----------|
| ID | 0x03 | Опция Opt |
在保持子连接时,若 Opt(D) 开启,则这一帧所带的数据需要被发往目标主机。
При поддержании подсоединения, если Opt(D) включена, данные, переносимые этим кадром, должны быть отправлены на целевой хост.
### 保持连接 (KeepAlive)
### Поддержание соединения (KeepAlive)
| 2 字节 | 1 字节 | 1 字节 |
| ------ | ------ | -------- |
| ID | 0x04 | 选项 Opt |
| 2 байта | 1 байт | 1 байт |
|---------|--------|-----------|
| ID | 0x04 | Опция Opt |
在保持连接时:
При поддержании соединения:
- Если Opt(D) включена, данные, переносимые этим кадром, должны быть отброшены.
- ID может быть случайным значением.
## Применение
Протокол Mux.Cool не зависит от базового протокола и теоретически может использовать любое надежное потоковое соединение для передачи данных протокола Mux.Cool.
В протоколах, ориентированных на целевой адрес, таких как Shadowsocks и VMess, при установлении соединения должен быть указан целевой адрес.
Для обеспечения совместимости протокол Mux.Cool определяет адрес "v1.mux.cool". То есть, если целевой адрес главного соединения совпадает с этим адресом, пересылка осуществляется в режиме Mux.Cool, в противном случае пересылка осуществляется традиционным способом. (Примечание: это внутренняя метка программы, VMess и VLESS не отправляют адрес "v1.mux.cool" в пакетах данных).
- 若 Opt(D) 开启,则这一帧所带的数据必须被丢弃。
- ID 可为随机值。
## 应用
Mux.Cool 协议与底层协议无关,理论上可以使用任何可靠的流式连接来传输 Mux.Cool 的协议数据。
在目标导向的协议如 Shadowsocks 和 VMess 协议中,连接建立时必须包含一个指定的地址。
为了保持兼容性,Mux.Cool 协议指定地址为“v1.mux.cool”。即当主连接的目标地址与之匹配时,则进行 Mux.Cool 方式的转发,否则按传统方式进行转发。(注:这是一个程序内的标记,VMess 和 VLESS 并不会在数据包中发送“v1.mux.cool”地址)

100
docs/ru/development/protocols/vless.md

@ -1,91 +1,93 @@
# VLESS 协议
# Протокол VLESS
VLESS 是一个无状态的轻量传输协议,可以作为 Xray 客户端和服务器之间的桥梁。
VLESS - это легковесный, не сохраняющий состояние транспортный протокол, который может служить мостом между клиентом и сервером Xray.
## Request & Response
## Запрос и ответ
| 1 字节 | 16 字节 | 1 字节 | M 字节 | 1 字节 | 2 字节 | 1 字节 | S 字节 | X 字节 |
| -------- | --------- | -------------- | ----------------- | ------ | ------ | -------- | ------ | -------- |
| 协议版本 | 等价 UUID | 附加信息长度 M | 附加信息 ProtoBuf | 指令 | 端口 | 地址类型 | 地址 | 请求数据 |
| 1 байт | 16 байт | 1 байт | M байт | 1 байт | 2 байта | 1 байт | S байт | X байт |
|------------------|--------------------|-----------------------------------|------------------------------------|---------|---------|------------|--------|----------------|
| Версия протокола | Эквивалентный UUID | Длина дополнительной информации M | Дополнительная информация ProtoBuf | Команда | Порт | Тип адреса | Адрес | Данные запроса |
| 1 字节 | 1 字节 | N 字节 | Y 字节 |
| ---------------------- | -------------- | ----------------- | -------- |
| 协议版本,与请求的一致 | 附加信息长度 N | 附加信息 ProtoBuf | 响应数据 |
| 1 байт | 1 байт | N байт | Y байт |
|-----------------------------------------------|-----------------------------------|------------------------------------|---------------|
| Версия протокола, совпадает с версией запроса | Длина дополнительной информации N | Дополнительная информация ProtoBuf | Данные ответа |
VLESS 早在第二个测试版 ALPHA 2 时就已经是上述结构了(BETA 是第五个测试版):
Структура VLESS была такой же, как указано выше, еще во второй альфа-версии (ALPHA 2) (BETA - это пятая бета-версия):
> “响应认证”被替换为“协议版本”并移至最前,使 VLESS 可以升级换代,同时消除了生成伪随机数的开销。混淆相关结构被替换为附加信息(ProtoBuf)并前移,赋予协议本身可扩展性,相关开销也极小([gogo/protobuf](https://github.com/gogo/protobuf)),若无附加信息则无相关开销。
> "Аутентификация ответа" была заменена на "версию протокола" и перемещена в начало, что позволяет VLESS обновляться, одновременно устраняя накладные расходы на генерацию псевдослучайных чисел. Структура, связанная с обфускацией, была заменена на дополнительную информацию (ProtoBuf) и перемещена вперед, что придало самому протоколу расширяемость с минимальными накладными расходами ([gogo/protobuf](https://github.com/gogo/protobuf)). Если нет дополнительной информации, то нет и связанных с ней накладных расходов.
我一直觉得“响应认证”不是必要的,ALPHA 时为了提升生成随机数的性能,还用 math/rand 替换 crypto/rand,而现在都不需要了。
Я всегда считал, что "аутентификация ответа" не является обязательной. В версии ALPHA для повышения производительности генерации случайных чисел мы заменили crypto/rand на math/rand, а теперь в этом нет необходимости.
“协议版本”不仅能起到“响应认证”的作用,还赋予了 VLESS 无痛升级协议结构的能力,带来无限的可能性。
“协议版本”在测试版本中均为 0,正式版本中为 1,以后若有不兼容的协议结构变更则应升级版本。
"Версия протокола" не только выполняет функцию "аутентификации ответа", но и дает VLESS возможность безболезненно обновлять структуру протокола, открывая бесконечные возможности.
"Версия протокола" во всех бета-версиях равна 0, в официальной версии - 1, а в будущем, если будут несовместимые изменения в структуре протокола, версия должна быть обновлена.
VLESS 服务端的设计是 switch version,即同时支持所有 VLESS 版本。若需要升级协议版本(可能到不了这一步),推荐的做法是服务端提前一个月支持,一个月后再改客户端。VMess 请求也有协议版本,但它的认证信息在外面,指令部分则高度耦合且有固定加密,导致里面的协议版本毫无意义,服务端也没有进行判断,响应则没有协议版本。Trojan 的协议结构中没有协议版本。
Сервер VLESS спроектирован по принципу switch version, то есть он одновременно поддерживает все версии VLESS. Если требуется обновить версию протокола (что маловероятно), рекомендуется сначала добавить поддержку на сервере за месяц до обновления клиентов. Запрос VMess также имеет версию протокола, но его информация для аутентификации находится снаружи, а часть с командой сильно связана и имеет фиксированное шифрование, что делает версию протокола внутри бессмысленной. Сервер также не проверяет ее, а ответ не имеет версии протокола. В структуре протокола Trojan нет версии протокола.
接下来是 UUID,我本来觉得 16 字节有点长,曾经考虑过缩短它,但后来看到 Trojan 用了 56 个可打印字符(56 字节),就彻底打消了这个念头。服务端每次都要验证 UUID,所以性能也很重要:VLESS 的 Validator 经历了多次重构/升级,相较于 VMess,它十分简洁且耗资源很少,可以同时支持非常多的用户,性能也十分强悍,验证速度极快(sync.Map)。API 动态增删用户则更高效顺滑。
Далее идет UUID. Сначала я думал, что 16 байт - это многовато, и подумывал о его сокращении, но потом увидел, что Trojan использует 56 печатаемых символов (56 байт), и полностью отказался от этой идеи. Сервер каждый раз проверяет UUID, поэтому производительность также важна: валидатор VLESS прошел через несколько рефакторингов/обновлений, он очень прост и потребляет мало ресурсов по сравнению с VMess, может одновременно поддерживать очень большое количество пользователей, имеет очень высокую производительность и очень высокую скорость проверки (sync.Map). Динамическое добавление и удаление пользователей через API еще более эффективно и плавно.
https://github.com/XTLS/Xray-core/issues/158
引入 ProtoBuf 是一个创举,等下会详细讲解。“指令”到“地址”的结构目前与 VMess 完全相同,同样支持 Mux。
Внедрение ProtoBuf - это инновация, о которой мы подробнее поговорим ниже. Структура от "команды" до "адреса" в настоящее время полностью идентична VMess и также поддерживает Mux.
总体上,ALPHA 2 到 BETA 主要是:结构进化、清理整合、性能提升、更加完善。这些都是一点一滴的,详见 [VLESS Changes](https://github.com/rprx/v2ray-vless/releases)
В целом, изменения от ALPHA 2 до BETA в основном заключаются в следующем: эволюция структуры, очистка и консолидация, повышение производительности и улучшение. Все это происходило постепенно, подробнее см. [VLESS Changes](https://github.com/rprx/v2ray-vless/releases).
## ProtoBuf
似乎只有 VLESS 可选内嵌 ProtoBuf,它是一种数据交换格式,信息被紧密编码成二进制,TLV 结构(Tag Length Value)。
Кажется, только VLESS опционально поддерживает встроенный ProtoBuf. Это формат обмена данными, в котором информация плотно упакована в двоичный код, структура TLV (Tag Length Value).
起因是我看到一篇文章称 SS 有一些缺点,如没有设计错误回报机制,客户端没办法根据不同的错误采取进一步的动作。
(但我并不认同所有错误都要回报,不然防不了主动探测。下一个测试版中,服务器可以返回一串自定义信息。)
于是想到一个可扩展的结构是很重要的,未来它也可以承载如动态端口指令。不止响应,请求也需要类似的结构。
本来打算自己设计 TLV,接着发觉 ProtoBuf 就是此结构、现成的轮子,完全适合用来做这件事,各语言支持等也不错。
Причиной этого послужила статья, в которой утверждалось, что у SS есть некоторые недостатки, например, отсутствие механизма сообщения об ошибках, что не позволяет клиенту предпринимать дальнейшие действия в зависимости от типа ошибки.
(Однако я не согласен с тем, что обо всех ошибках нужно сообщать, иначе нельзя будет предотвратить активное зондирование. В следующей бета-версии сервер сможет возвращать пользовательское сообщение об ошибке.)
Поэтому я подумал, что важно иметь расширяемую структуру, которая в будущем сможет нести, например, команды динамического порта. И не только в ответе, но и в запросе нужна подобная структура.
Сначала я хотел разработать TLV самостоятельно, но потом обнаружил, что ProtoBuf - это именно та структура, готовое решение, которое идеально подходит для этой задачи, и имеет хорошую поддержку различных языков программирования.
目前“附加信息”只有 Scheduler 和 SchedulerV,它们是 MessName 和 MessSeed 的替代者,**当你不需要它们时,“附加信息长度”为 0,也就不会有 ProtoBuf 序列化/反序列化的开销**。其实我更愿意称这个过程为“拼接”,因为 pb 实际原理上也只是这么做而已,相关开销极小。拼接后的 bytes 十分紧凑,和 ALPHA 的方案相差无几,有兴趣的可以分别输出并对比。
В настоящее время "дополнительная информация" содержит только Scheduler и SchedulerV, которые являются заменой MessName и MessSeed. **Если они вам не нужны, "длина дополнительной информации" будет равна 0, и не будет никаких накладных расходов на сериализацию/десериализацию ProtoBuf**. На самом деле я предпочитаю называть этот процесс "склейкой", поскольку pb по сути делает именно это, и накладные расходы минимальны. Склеенные байты очень компактны, практически не отличаются от решения в ALPHA. Желающие могут вывести их и сравнить.
为了指示对附加信息(Addons,也可以理解成插件,以后可以有很多个插件)的不同支持程度,下个测试版会在“附加信息长度”前新增“附加信息版本”。256 - 1 = 255 字节是够用且合理的(65535 就太多了,还可能有人恶意填充),现有的只用了十分之一,以后也不会同时有那么多附加信息,且大多数情况下是完全没有附加信息的。真不够用的话,可以升级 VLESS 版本。
Чтобы указать различный уровень поддержки дополнительной информации (Addons, которые можно рассматривать как плагины, в будущем их может быть много), в следующей бета-версии перед "длиной дополнительной информации" будет добавлена "версия дополнительной информации". 256 - 1 = 255 байт - это достаточно и разумно (65535 - это слишком много, и кто-то может злонамеренно заполнить их), существующие используют только десятую часть, и в будущем не будет такого количества дополнительной информации, а в большинстве случаев дополнительная информация вообще отсутствует. Если этого действительно не хватит, можно обновить версию VLESS.
为了减少逻辑判断等开销,暂定 Addons 不使用多级结构。一个月前出现过“可变协议格式”的想法,pb 是可以做到打乱顺序,但没必要,因为现代加密的设计不会让旁观者看出两次传输的头部相同。
Чтобы сократить накладные расходы на логические проверки и т.д., Addons пока не будут использовать многоуровневую структуру. Месяц назад появилась идея "изменяемого формата протокола", pb может переставлять поля, но в этом нет необходимости, поскольку современное шифрование не позволяет стороннему наблюдателю увидеть, что заголовки двух передач одинаковы.
下面介绍 Schedulers 和 Encryption 的构想,**它们都是可选的**,一个应对流量时序特征问题,一个应对密码学上的问题。
Ниже представлены концепции Schedulers и Encryption, **они обе являются необязательными**: одна решает проблему временных характеристик трафика, другая - криптографические проблемы.
## ~~Schedulers~~ Flow
~~中文名暂称:流量调度器~~(2020-09-03 更新:中文名确定为“流控”),指令由 ProtoBuf 承载,控制的是数据部分。
~~Предварительное китайское название: Планировщик трафика~~ (обновление от 03.09.2020: официальное китайское название - "Управление потоком"). Команда передается через ProtoBuf и управляет частью данных.
我之前发现,VMess 原有的 shake “元数据混淆”在 TLS 上完全不会带来有意义的改变,只会降低性能,所以 VLESS 弃用了它。并且,“混淆”这个表述容易被误解成伪装,也弃用了。顺便一提,我一直是不看好伪装的:做不到完全一样,那不就是强特征吗?做得到完全一样,那为什么不直接用伪装目标?我一开始用的是 SSR,后来发现它只是表面伪装骗运营商,就再也没用过了。
Я обнаружил, что оригинальная "обфускация метаданных" shake в VMess не вносит никаких значимых изменений при использовании TLS, а только снижает производительность, поэтому в VLESS от нее отказались. Кроме того, термин "обфускация" может быть неверно истолкован как маскировка, поэтому от него тоже отказались. Кстати, я всегда скептически относился к маскировке: если она не может быть полностью идентичной, то это же явная сигнатура? А если может быть полностью идентичной, то почему бы не использовать саму маскировку? Сначала я использовал SSR, но потом понял, что он маскирует трафик только для провайдера, и больше им не пользовался.
那么,“流量调度器”要解决什么问题?它影响的是宏观流量时序特征,而不是微观特征,后者是加密要解决的事情。流量时序特征可以是协议带来的,比如 Socks5 over TLS 时的 Socks5 握手 ,TLS 上不同的这种特征对于监测者来说就是不同的协议,此时无限 Schedulers 就相当于无限协议(重新分配每次发送的数据量大小等)。流量时序特征也可以是行为带来的,比如访问 Google 首页时加载了多少文件、顺序、每个文件的大小,多套一层加密并不能有效掩盖这些信息。
Так какую же проблему решает "Планировщик трафика"? Он влияет на макроскопические временные характеристики трафика, а не на микроскопические, которые должны решаться шифрованием. Временные характеристики трафика могут быть обусловлены протоколом, например, рукопожатием Socks5 при использовании Socks5 over TLS. Для наблюдателя различные временные характеристики в TLS соответствуют разным протоколам, поэтому бесконечное количество планировщиков эквивалентно бесконечному количеству протоколов (перераспределение размера отправляемых данных и т.д.). Временные характеристики трафика также могут быть обусловлены поведением, например, сколько файлов загружается при посещении главной страницы Google, в каком порядке и какого размера. Добавление еще одного уровня шифрования не может эффективно скрыть эту информацию.
Schedulers 没必要像下面的 Encryption 一样整个套在外面,因为头部的一丁点数据相对于后面的数据量来说太微不足道了。
Schedulers не нужно располагать снаружи, как Encryption, поскольку небольшое количество данных в заголовке ничтожно мало по сравнению с объемом данных, которые следуют за ними.
BETA 2 预计推出两个初级的 Scheduler:Zstd 压缩、数据量动态扩充。进阶操作才是从宏观层面来控制、分配,暂时咕咕。
В BETA 2 планируется выпустить два базовых планировщика: сжатие Zstd и динамическое увеличение объема данных. Более продвинутые операции - это управление и распределение на макроскопическом уровне, которые пока отложены.
## Encryption
与 VMess 的高度耦合不同,VLESS 的服务端、客户端不久后可以提前约定好加密方式,仅在外面套一层加密。这有点类似于使用 TLS,不影响承载的任何数据,也可以理解成底层就是从 TLS 换成预设约定加密。相对于高度耦合,这种方式更合理且灵活:一种加密方式出了安全性问题,直接扔掉并换用其它的就行了,十分方便。VLESS 服务端还会允许不同的加密方式共存。
В отличие от VMess, где шифрование жестко связано с протоколом, в VLESS сервер и клиент смогут заранее договариваться о методе шифрования и шифровать только внешний слой. Это похоже на использование TLS, которое не влияет на передаваемые данные, и можно рассматривать как замену TLS на заранее согласованное шифрование. По сравнению с жесткой связью такой подход более рационален и гибок: если в одном методе шифрования обнаруживается проблема безопасности, его можно просто заменить на другой. Сервер VLESS также позволит использовать разные методы шифрования одновременно.
对比 VMess,VLESS 相当于把 security 换成 encryption,把 disableInsecureEncryption 换成 decryption,就解决了所有问题。目前 encryption 和 decryption 只接受 \"none\" 且不能留空(即使以后有连接安全性检查),详见 [VLESS 配置文档](https://github.com/rprx/v2fly-github-io/blob/master/docs/config/protocols/vless.md)。encryption 并不需要往外移一级,一是因为无法复用很多代码,二是因为会影响控制粒度,看未来的应用就明白了。
По сравнению с VMess, в VLESS достаточно заменить security на encryption, а disableInsecureEncryption на decryption, чтобы решить все проблемы. В настоящее время encryption и decryption принимают только значение "none" и не могут быть пустыми (даже если в будущем будет добавлена проверка безопасности соединения), подробнее см. [документацию по настройке VLESS](https://github.com/rprx/v2fly-github-io/blob/master/docs/config/protocols/vless.md). Encryption не нужно перемещать на уровень выше, во-первых, потому что это не позволит повторно использовать много кода, во-вторых, потому что это повлияет на степень контроля, что станет понятно в будущем.
加密支持两类形式,一类是加密完全独立,需要额外密码,适合私用,另一类是结合已有的 UUID 来加密,适合公用。
(若用第一类加密形式,且密码是以某种形式公开的,比如多人共用,那么中间人攻击就不远了)
重新设计的动态端口可能会随加密同时推出,指令由 ProtoBuf 承载,具体实现和 VMess 的动态端口也会有很多不同。
Поддерживаются два типа шифрования: одно - полностью независимое шифрование, требующее дополнительного пароля, подходит для личного использования, другое - шифрование с использованием существующего UUID, подходит для общего использования.
(Если используется первый тип шифрования и пароль раскрывается каким-либо образом, например, при совместном использовании несколькими людьми, то атака "человек посередине" не за горами.)
Переработанный динамический порт может быть выпущен вместе с шифрованием, команда будет передаваться через ProtoBuf, реализация будет отличаться от динамического порта VMess.
套现成加密是件很简单的事情,也就多一层 writer & reader。BETA 3 预计支持 SS 的 aes-128-gcm 和 chacha20-ietf-poly1305:
客户端的 encryption 可以填 “auto: ss_aes-128-gcm_0_123456, ss_chacha20-ietf-poly1305_0_987654”,auto 会选择最适合当前机器的,0 代表测试版,最后的是密码。服务端的 decryption 也是类似填法,收到请求时会逐一尝试解密。
Добавить готовое шифрование довольно просто, нужно добавить всего лишь один уровень writer & reader. В BETA 3 планируется добавить поддержку aes-128-gcm и chacha20-ietf-poly1305 из SS:
в encryption на клиенте можно указать "auto: ss_aes-128-gcm_0_123456, ss_chacha20-ietf-poly1305_0_987654", auto выберет наиболее подходящий для текущей машины, 0 означает бета-версию, а в конце указывается пароль. В decryption на сервере указывается аналогичная строка, и при получении запроса сервер будет пытаться расшифровать его с помощью каждого указанного метода.
并不是所有组合都需逐一尝试:VMess 的加密分为三段,第一段是认证信息,结合了 UUID、alterId、时间因素,第二段是指令部分,以固定算法加密,指令中含有数据部分使用的加密算法,第三段才是重要的数据部分。可以看出,VMess 的加解密方式实际上是多对一(服务端适配),而不仅是结合 UUID。但仅是结合 UUID 来加密也是件相对麻烦的事情,短时间内不会出,鉴于我们现在有 VMessAEAD 可用,也并不着急。若 VLESS 推出了结合 UUID 的加密方式,相当于重构了整个 VMess。
Не все комбинации нужно перебирать: шифрование в VMess состоит из трех частей, первая часть - это информация для аутентификации, которая включает UUID, alterId и временной фактор, вторая часть - это часть с командой, которая шифруется с помощью фиксированного алгоритма, команда содержит информацию об алгоритме шифрования, используемом для части с данными, третья часть - это сами данные. Как видно, VMess фактически использует шифрование "многие ко одному" (адаптация на стороне сервера), а не просто шифрование с помощью UUID. Но шифрование только с помощью UUID тоже довольно сложно, и в ближайшее время оно не будет реализовано, учитывая, что у нас уже есть VMessAEAD. Если в VLESS будет реализован способ шифрования с помощью UUID, это будет означать переработку всего VMess.
## UDP issues
## Проблемы с UDP
[XUDPVLESS & VMess & Mux UDP FullCone NAT](https://github.com/XTLS/Xray-core/discussions/252)
[XUDP: VLESS & VMess & Mux UDP FullCone NAT](https://github.com/XTLS/Xray-core/discussions/252)
## 客户端开发指引
## Руководство по разработке клиентов
1. VLESS 协议本身还会有不兼容升级,但客户端配置文件参数基本上是只增不减的。iOS 客户端的协议实现则需紧跟升级。
2. **视觉标准:UI 标识请统一用 VLESS**,而不是 VLess / Vless / vless,配置文件不受影响,代码内则顺其自然。
3. `encryption` 应做成输入框而不是选择框,新配置的默认值应为 `none`,若用户置空则应代填 `none`
1. Протокол VLESS сам по себе будет обновляться несовместимым образом, но параметры конфигурации клиента в основном будут только добавляться. Реализация протокола в iOS-клиенте должна обновляться соответствующим образом.
2. **Визуальный стандарт: используйте VLESS в качестве идентификатора в пользовательском интерфейсе**, а не VLess / Vless / vless. Настройки в файле конфигурации не затрагиваются, в коде используйте естественный стиль.
3. `encryption` должен быть реализован в виде текстового поля, а не выпадающего списка. Значение по умолчанию для новых настроек должно быть `none`. Если пользователь оставит поле пустым, туда должно быть автоматически подставлено `none`.
## VLESS 分享链接标准
## Стандарт общих ссылок VLESS
Спасибо <img src="https://avatars2.githubusercontent.com/u/7822648?s=32" width="32px" height="32px" alt="a"/> [@DuckSoft](https://github.com/DuckSoft) за предложение!
Подробнее см. [Предложение по стандарту общих ссылок VMessAEAD / VLESS](https://github.com/XTLS/Xray-core/issues/91)
感谢 <img src="https://avatars2.githubusercontent.com/u/7822648?s=32" width="32px" height="32px" alt="a"/> [@DuckSoft](https://github.com/DuckSoft) 的提案!
详情请见 [VMessAEAD / VLESS 分享链接标准提案](https://github.com/XTLS/Xray-core/issues/91)

307
docs/ru/development/protocols/vmess.md

@ -1,175 +1,178 @@
# VMess 协议
# Протокол VMess
VMess 是一个加密传输协议,可以作为 Xray 客户端和服务器之间的桥梁。
VMess - это зашифрованный транспортный протокол, который может служить мостом между клиентом и сервером Xray.
## 版本
## Версия
当前版本号为 1。
Текущая версия протокола - 1.
## 依赖
## Зависимости
### 底层协议
### Базовый протокол
VMess 是一个基于 TCP 的协议,所有数据使用 TCP 传输。
VMess - это протокол, основанный на TCP, все данные передаются по TCP.
### 用户 ID
### Идентификатор пользователя
ID 等价于 [UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier),是一个 16 字节长的随机数,它的作用相当于一个令牌(Token)。
一个 ID 形如:de305d54-75b4-431b-adb2-eb6b9e546014,几乎完全随机,可以使用任何的 UUID 生成器来生成,比如[这个](https://www.uuidgenerator.net/)。
ID эквивалентен [UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier) - это 16-байтовое случайное число, которое действует как токен.
ID выглядит следующим образом: de305d54-75b4-431b-adb2-eb6b9e546014, он практически полностью случаен и может быть сгенерирован с помощью любого генератора UUID, например [этого](https://www.uuidgenerator.net/).
用户 ID 可在[配置文件](../../config)中指定。
Идентификатор пользователя можно указать в [файле конфигурации](../../config).
### 函数
### Функции
- MD5: [MD5 函数](https://en.wikipedia.org/wiki/MD5)
- 输入参数为任意长度的 byte 数组
- 输出为一个 16 byte 的数组
- HMAC: [HMAC 函数](https://en.wikipedia.org/wiki/Hash-based_message_authentication_code)
- 输入参数为:
- H:散列函数
- K:密钥,任意长度的 byte 数组
- M:消息,任意长度的 byte 数组
- Shake: [SHA3-Shake128 函数](https://en.wikipedia.org/wiki/SHA-3)
- 输入参数为任意长度的字符串
- 输出为任意长度的字符串
- MD5: функция [MD5](https://en.wikipedia.org/wiki/MD5)
- Входные данные: массив байтов произвольной длины
- Выходные данные: массив из 16 байтов
- HMAC: функция [HMAC](https://en.wikipedia.org/wiki/Hash-based_message_authentication_code)
- Входные данные:
- H: хэш-функция
- K: ключ, массив байтов произвольной длины
- M: сообщение, массив байтов произвольной длины
- Shake: функция [SHA3-Shake128](https://en.wikipedia.org/wiki/SHA-3)
- Входные данные: строка произвольной длины
- Выходные данные: строка произвольной длины
## 通讯过程
## Процесс коммуникации
VMess 是一个无状态协议,即客户端和服务器之间不需要握手即可直接传输数据,每一次数据传输对之前和之后的其它数据传输没有影响。
VMess - это протокол без сохранения состояния, то есть клиент и сервер могут передавать данные напрямую без рукопожатия, и каждая передача данных не влияет на предыдущие или последующие передачи.
VMess 的客户端发起一次请求,服务器判断该请求是否来自一个合法的客户端。如验证通过,则转发该请求,并把获得的响应发回给客户端。
Клиент VMess отправляет запрос, а сервер проверяет, исходит ли этот запрос от легитимного клиента. Если проверка пройдена, сервер пересылает запрос и отправляет полученный ответ клиенту.
VMess 使用非对称格式,即客户端发出的请求和服务器端的响应使用了不同的格式。
VMess использует асимметричный формат, то есть запрос, отправляемый клиентом, и ответ сервера имеют разные форматы.
## 客户端请求
## Запрос клиента
| 16 字节 | X 字节 | 余下部分 |
| -------- | -------- | -------- |
| 认证信息 | 指令部分 | 数据部分 |
| 16 байт | X байт | Оставшаяся часть |
|-------------------------------|------------------|------------------|
| Информация для аутентификации | Часть с командой | Часть с данными |
### 认证信息
### Информация для аутентификации
认证信息是一个 16 字节的哈希(hash)值,它的计算方式如下:
Информация для аутентификации - это 16-байтовое хэш-значение, которое вычисляется следующим образом:
- H = MD5
- K = 用户 ID (16 字节)
- M = UTC 时间,精确到秒,取值为当前时间的前后 30 秒随机值(8 字节, Big Endian)
- K = идентификатор пользователя (16 байт)
- M = время UTC с точностью до секунды, случайное значение в диапазоне ±30 секунд от текущего времени (8 байт, Big Endian)
- Hash = HMAC(H, K, M)
### 指令部分
指令部分经过 AES-128-CFB 加密:
- Key:MD5(用户 ID + []byte('c48619fe-8f02-49e0-b9e9-edf763e17e21'))
- IV:MD5(X + X + X + X),X = []byte(认证信息生成的时间) (8 字节, Big Endian)
| 1 字节 | 16 字节 | 16 字节 | 1 字节 | 1 字节 | 4 位 | 4 位 | 1 字节 | 1 字节 | 2 字节 | 1 字节 | N 字节 | P 字节 | 4 字节 |
| :--------: | :---------: | :----------: | :--------: | :------: | :----: | :----------: | :----: | :------: | :-------: | :--------: | :----: | :----: | :----: |
| 版本号 Ver | 数据加密 IV | 数据加密 Key | 响应认证 V | 选项 Opt | 余量 P | 加密方式 Sec | 保留 | 指令 Cmd | 端口 Port | 地址类型 T | 地址 A | 随机值 | 校验 F |
选项 Opt 细节:(当某一位为 1 时,表示该选项启用)
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
| :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: |
| X | X | X | X | X | M | R | S |
其中:
- 版本号 Ver:始终为 1;
- 数据加密 IV:随机值;
- 数据加密 Key:随机值;
- 响应认证 V:随机值;
- 选项 Opt:
- S (0x01):标准格式的数据流(建议开启);
- R (0x02):客户端期待重用 TCP 连接(Xray 2.23+ 弃用);
- 只有当 S 开启时,这一项才有效;
- M (0x04):开启元数据混淆(建议开启);
- 只有当 S 开启时,这一项才有效;
- 当其项开启时,客户端和服务器端需要分别构造两个 Shake 实例,分别为 RequestMask = Shake(请求数据 IV), ResponseMask = Shake(响应数据 IV)。
- X:保留
- 余量 P:在校验值之前加入 P 字节的随机值;
- 加密方式:指定数据部分的加密方式,可选的值有:
- 0x00:AES-128-CFB;
- 0x01:不加密;
- 0x02:AES-128-GCM;
- 0x03:ChaCha20-Poly1305;
- 指令 Cmd:
- 0x01:TCP 数据;
- 0x02:UDP 数据;
- 端口 Port:Big Endian 格式的整型端口号;
- 地址类型 T:
- 0x01:IPv4
- 0x02:域名
- 0x03:IPv6
- 地址 A:
- 当 T = 0x01 时,A 为 4 字节 IPv4 地址;
- 当 T = 0x02 时,A 为 1 字节长度(L) + L 字节域名;
- 当 T = 0x03 时,A 为 16 字节 IPv6 地址;
- 校验 F:指令部分除 F 外所有内容的 FNV1a hash;
### 数据部分
当 Opt(S) 开启时,数据部分使用此格式。实际的请求数据被分割为若干个小块,每个小块的格式如下。服务器校验完所有的小块之后,再按基本格式的方式进行转发。
| 2 字节 | L 字节 |
| :----: | :----: |
| 长度 L | 数据包 |
其中:
- 长度 L:Big Endian 格式的整型,最大值为 2^14;
- 当 Opt(M) 开启时,L 的值 = 真实值 xor Mask。Mask = (RequestMask.NextByte() << 8) + RequestMask.NextByte()
- 数据包:由指定的加密方式加密过的数据包;
在传输结束之前,数据包中必须有实际数据,即除了长度和认证数据之外的数据。当传输结束时,客户端必须发送一个空的数据包,即 L = 0(不加密) 或认证数据长度(有加密),来表示传输结束。
按加密方式不同,数据包的格式如下:
- 不加密:
- L 字节:实际数据;
- AES-128-CFB:整个数据部分使用 AES-128-CFB 加密
- 4 字节:实际数据的 FNV1a hash;
- L - 4 字节:实际数据;
- AES-128-GCM:Key 为指令部分的 Key,IV = count (2 字节) + IV (10 字节)。count 从 0 开始递增,每个数据包加 1;IV 为 指令部分 IV 的第 3 至第 12 字节。
- L - 16 字节:实际数据;
- 16 字节:GCM 认证信息
- ChaCha20-Poly1305:Key = MD5(指令部分 Key) + MD5(MD5(指令部分 Key)),IV = count (2 字节) + IV (10 字节)。count 从 0 开始递增,每个数据包加 1;IV 为 指令部分 IV 的第 3 至第 12 字节。
- L - 16 字节:实际数据;
- 16 字节:Poly1305 认证信息
## 服务器应答
应答头部数据使用 AES-128-CFB 加密,IV 为 MD5(数据加密 IV),Key 为 MD5(数据加密 Key)。实际应答数据视加密设置不同而不同。
| 1 字节 | 1 字节 | 1 字节 | 1 字节 | M 字节 | 余下部分 |
| ---------- | -------- | -------- | ---------- | -------- | ------------ |
| 响应认证 V | 选项 Opt | 指令 Cmd | 指令长度 M | 指令内容 | 实际应答数据 |
其中:
- 响应认证 V:必须和客户端请求中的响应认证 V 一致;
- 选项 Opt:
- 0x01:服务器端准备重用 TCP 连接(Xray 2.23+ 弃用);
- 指令 Cmd:
- 0x01:动态端口指令
- 实际应答数据:
- 如果请求中的 Opt(S) 开启,则使用标准格式,否则使用基本格式。
- 格式均和请求数据相同。
- 当 Opt(M) 开启时,长度 L 的值 = 真实值 xor Mask。Mask = (ResponseMask.NextByte() << 8) + ResponseMask.NextByte()
### 动态端口指令
| 1 字节 | 2 字节 | 16 字节 | 2 字节 | 1 字节 | 1 字节 |
| ------ | --------- | ------- | ------- | -------- | ---------- |
| 保留 | 端口 Port | 用户 ID | AlterID | 用户等级 | 有效时间 T |
其中:
- 端口 Port:Big Endian 格式的整型端口号;
- 有效时间 T:分钟数;
客户端在收到动态端口指令时,服务器已开放新的端口用于通信,这时客户端可以将数据发往新的端口。在 T 分钟之后,这个端口将失效,客户端必须重新使用主端口进行通信。
## 注释
- 为确保向前兼容性,所有保留字段的值必须为 0。
### Часть с командой
Часть с командой шифруется с помощью AES-128-CFB:
- Ключ: MD5(идентификатор пользователя + []byte('c48619fe-8f02-49e0-b9e9-edf763e17e21'))
- Вектор инициализации: MD5(X + X + X + X), X = []byte(время генерации информации для аутентификации) (8 байт, Big Endian)
| 1 байт | 16 байт | 16 байт | 1 байт | 1 байт | 4 бита | 4 бита | 1 байт | 1 байт | 2 байта | 1 байт | N байт | P байт | 4 байта |
|------------------|--------------------------------------------|----------------------------|-------------------------|-----------|-----------|----------------------|-----------------|-------------|-----------|--------------|---------|------------------|---------------------|
| Номер версии Ver | Вектор инициализации для шифрования данных | Ключ для шифрования данных | Аутентификация ответа V | Опция Opt | Остаток P | Метод шифрования Sec | Зарезервировано | Команда Cmd | Порт Port | Тип адреса T | Адрес A | Случайные данные | Контрольная сумма F |
Подробности опции Opt: (если бит равен 1, опция включена)
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
|---|---|---|---|---|---|---|---|
| X | X | X | X | X | M | R | S |
Где:
- Номер версии Ver: всегда равен 1;
- Вектор инициализации для шифрования данных: случайное значение;
- Ключ для шифрования данных: случайное значение;
- Аутентификация ответа V: случайное значение;
- Опция Opt:
- S (0x01): стандартный формат потока данных (рекомендуется включать);
- R (0x02): клиент ожидает повторного использования TCP-соединения (устарело в Xray 2.23+);
- Действительна только при включенной опции S;
- M (0x04): включить обфускацию метаданных (рекомендуется включать);
- Действительна только при включенной опции S;
- Если эта опция включена, клиент и сервер должны создать два экземпляра Shake: RequestMask = Shake(вектор инициализации для шифрования данных запроса), ResponseMask = Shake(вектор инициализации для шифрования данных ответа).
- X: зарезервировано
- Остаток P: добавить P байт случайных данных перед контрольной суммой;
- Метод шифрования: указывает метод шифрования для части с данными, возможные значения:
- 0x00: AES-128-CFB;
- 0x01: без шифрования;
- 0x02: AES-128-GCM;
- 0x03: ChaCha20-Poly1305;
- Команда Cmd:
- 0x01: данные TCP;
- 0x02: данные UDP;
- Порт Port: номер порта в формате Big Endian;
- Тип адреса T:
- 0x01: IPv4
- 0x02: доменное имя
- 0x03: IPv6
- Адрес A:
- Если T = 0x01, A - это 4-байтовый адрес IPv4;
- Если T = 0x02, A - это 1 байт длины (L) + L байт доменного имени;
- Если T = 0x03, A - это 16-байтовый адрес IPv6;
- Контрольная сумма F: хэш FNV1a всей части с командой, кроме F;
### Часть с данными
Если Opt(S) включена, для части с данными используется следующий формат. Фактические данные запроса разбиваются на несколько блоков, каждый из которых имеет следующий формат. После проверки всех блоков сервер пересылает их в соответствии с базовым форматом.
| 2 байта | L байт |
|---------|--------------|
| Длина L | Пакет данных |
Где:
- Длина L: целое число в формате Big Endian, максимальное значение 2^14;
- Если Opt(M) включена, значение L = истинное значение xor Mask. Mask = (RequestMask.NextByte() << 8) + RequestMask.NextByte();
- Пакет данных: пакет данных, зашифрованный указанным методом шифрования;
До завершения передачи в пакете данных должны быть фактические данные, то есть данные, отличные от длины и данных аутентификации. При завершении передачи клиент должен отправить пустой пакет данных, то есть L = 0 (без шифрования) или длину данных аутентификации (с шифрованием), чтобы сигнализировать о завершении передачи.
Формат пакета данных зависит от метода шифрования:
- Без шифрования:
- L байт: фактические данные;
- AES-128-CFB: вся часть с данными шифруется с помощью AES-128-CFB
- 4 байта: хэш FNV1a фактических данных;
- L - 4 байта: фактические данные;
- AES-128-GCM: ключ - это ключ из части с командой, вектор инициализации = count (2 байта) + IV (10 байт). count начинается с 0 и увеличивается на 1 для каждого пакета данных; IV - это байты с 3 по 12 из вектора инициализации части с командой.
- L - 16 байт: фактические данные;
- 16 байт: данные аутентификации GCM
- ChaCha20-Poly1305: ключ = MD5(ключ из части с командой) + MD5(MD5(ключ из части с командой)), вектор инициализации = count (2 байта) + IV (10 байт). count начинается с 0 и увеличивается на 1 для каждого пакета данных; IV - это байты с 3 по 12 из вектора инициализации части с командой.
- L - 16 байт: фактические данные;
- 16 байт: данные аутентификации Poly1305
## Ответ сервера
Данные заголовка ответа шифруются с помощью AES-128-CFB, вектор инициализации - MD5(вектор инициализации для шифрования данных), ключ - MD5(ключ для шифрования данных). Фактические данные ответа зависят от настроек шифрования.
| 1 байт | 1 байт | 1 байт | 1 байт | M байт | Оставшаяся часть |
|-------------------------|-----------|-------------|-----------------|--------------------|---------------------------|
| Аутентификация ответа V | Опция Opt | Команда Cmd | Длина команды M | Содержимое команды | Фактические данные ответа |
Где:
- Аутентификация ответа V: должна совпадать с аутентификацией ответа V в запросе клиента;
- Опция Opt:
- 0x01: сервер готов повторно использовать TCP-соединение (устарело в Xray 2.23+);
- Команда Cmd:
- 0x01: команда динамического порта
- Фактические данные ответа:
- Если Opt(S) в запросе включена, используется стандартный формат, в противном случае используется базовый формат.
- Формат такой же, как и у данных запроса.
- Если Opt(M) включена, значение длины L = истинное значение xor Mask. Mask = (ResponseMask.NextByte() << 8) + ResponseMask.NextByte();
### Команда динамического порта
| 1 байт | 2 байта | 16 байт | 2 байта | 1 байт | 1 байт |
|-----------------|-----------|----------------------------|---------|----------------------|------------------|
| Зарезервировано | Порт Port | Идентификатор пользователя | AlterID | Уровень пользователя | Время действия T |
Где:
- Порт Port: номер порта в формате Big Endian;
- Время действия T: количество минут;
Когда клиент получает команду динамического порта, сервер уже открыл новый порт для связи, и клиент может отправлять данные на этот новый порт. Через T минут этот порт станет недействительным, и клиент должен будет снова использовать основной порт для связи.
## Примечания
- Для обеспечения обратной совместимости все зарезервированные поля должны иметь значение 0.

Loading…
Cancel
Save