From 7da8e890b1e92bc3465e0d3606d0630db79e57cc Mon Sep 17 00:00:00 2001 From: JimhHan <50871214+JimhHan@users.noreply.github.com> Date: Sun, 11 Apr 2021 12:36:45 +0800 Subject: [PATCH] Add: development --- docs/.vuepress/config.ts | 5 + docs/.vuepress/config/sidebar.ts | 28 ++- docs/development/README.md | 45 +++++ .../{build.md => intro/compile.md} | 10 +- docs/development/intro/design.md | 43 +++++ docs/development/intro/framework.png | Bin 0 -> 67678 bytes docs/development/intro/guide.md | 134 ++++++++++++++ docs/development/protocols/mkcp.md | 92 +++++++++ docs/development/protocols/muxcool.md | 116 ++++++++++++ docs/development/protocols/vless.md | 5 + docs/development/protocols/vmess.md | 175 ++++++++++++++++++ docs/document/install.md | 2 +- 12 files changed, 652 insertions(+), 3 deletions(-) create mode 100644 docs/development/README.md rename docs/development/{build.md => intro/compile.md} (79%) create mode 100644 docs/development/intro/design.md create mode 100644 docs/development/intro/framework.png create mode 100644 docs/development/intro/guide.md create mode 100644 docs/development/protocols/mkcp.md create mode 100644 docs/development/protocols/muxcool.md create mode 100644 docs/development/protocols/vless.md create mode 100644 docs/development/protocols/vmess.md diff --git a/docs/.vuepress/config.ts b/docs/.vuepress/config.ts index e549814d0..0ebf7354a 100644 --- a/docs/.vuepress/config.ts +++ b/docs/.vuepress/config.ts @@ -52,6 +52,11 @@ export default defineUserConfig({ "进阶技巧", "/document/level-2/" ), + "/development/": sidebar.getDevelopmentSidebar( + "开发指南", + "协议详解", + "/development/" + ), }, navbar: navbar.hans, }, diff --git a/docs/.vuepress/config/sidebar.ts b/docs/.vuepress/config/sidebar.ts index 62d22651e..552ce2efe 100644 --- a/docs/.vuepress/config/sidebar.ts +++ b/docs/.vuepress/config/sidebar.ts @@ -143,4 +143,30 @@ export function getDocumentLv2Sidebar( ]; } -export const a = ""; +export function getDevelopmentSidebar( + title: string, + protocols: string, + path: string +): SidebarConfigArray { + return [ + { + text: title, + isGroup: true, + children: [ + path + "intro/compile.md", + path + "intro/design.md", + path + "intro/guide.md", + { + text: protocols, + isGroup: true, + children: [ + path + "protocols/vless.md", + path + "protocols/vmess.md", + path + "protocols/muxcool.md", + path + "protocols/mkcp.md", + ], + }, + ], + }, + ]; +} diff --git a/docs/development/README.md b/docs/development/README.md new file mode 100644 index 000000000..0b0bc3928 --- /dev/null +++ b/docs/development/README.md @@ -0,0 +1,45 @@ +--- +sidebar: auto +--- + +# 开发指南 + +## 编译文档 + +Xray 支持各种平台, 您可以在多种平台上自行进行交叉编译。 + +请点击[编译文档](./intro/compile.md)以查看具体编译相关内容。 + +## 设计思路 + +Xray 内核提供了一个平台,在其之上可以进二次开发。 + +这个章节阐述了 Xray 的设计目标和架构。 + +请点击[设计思路](./intro/design.md)以了解 Xray 的设计目标和架构。 + +## 开发规范 + +这个章节阐述了获取代码,进行开发,提交 PR 的流程中需要遵循的准则, 以及相关的编码规范。 + +请点击[开发规范](./intro/guide.md)查看 Xray 开发中应遵循的准则。 + +## 协议详解 + +Xray 用到了很多种协议, 您可以通过各种途径获得协议的详细描述。 + +### [mKCP 协议](./protocols/vless.md) + +VLESS 是一个无状态的轻量传输协议,可以作为 Xray 客户端和服务器之间的桥梁。 + +### [VMess 协议](./protocols/vmess.md) + +VMess 是一个加密传输协议,可以作为 Xray 客户端和服务器之间的桥梁。 + +### [Mux.Cool 协议](./protocols/muxcool.md) + +Mux.Cool 协议是一个多路复用传输协议,用于在一条已建立的数据流中传输多个各自独立的数据流。 + +### [mKCP 协议](./protocols/mkcp.md) + +mKCP 是流式传输协议,由 [KCP 协议](https://github.com/skywind3000/kcp)修改而来,可以按顺序传输任意的数据流。 diff --git a/docs/development/build.md b/docs/development/intro/compile.md similarity index 79% rename from docs/development/build.md rename to docs/development/intro/compile.md index 3cd9f71d6..720528c6a 100644 --- a/docs/development/build.md +++ b/docs/development/intro/compile.md @@ -46,6 +46,14 @@ CGO_ENABLED=0 go build -o xray -trimpath -ldflags "-s -w -buildid=" ./main 运行以上命令会在目录下生成 xray 可执行文件。 +::: tip +如果需要编译可以进行 debug 的程序,即可以用 dlv 附加到运行的程序进行调试, 请去掉 ldflags 中的 '-w -s' 选项. + +-w 禁止生成 debug 信息。使用该选项后,将无法使用 gdb 进行调试。 +-s 禁用符号表 +PS:其实用 vscode 或其他 IDE 调试似乎更方便。 +::: + ## 交叉编译: 这里以在 Windows(Powershell) 环境中,编译到 Linux 服务器为例: @@ -66,7 +74,7 @@ go build -o xray -trimpath -ldflags "-s -w -buildid=" ./main ## 可复现构建: -按照上述步骤,能够编译出与 Release 中完全相同的二进制文件。 +按照上述步骤,能够编译与 Release 中完全相同的二进制文件。 ::: warning 请先确认您使用的 Golang 版本与编译 Release 的一致。 diff --git a/docs/development/intro/design.md b/docs/development/intro/design.md new file mode 100644 index 000000000..fdb6aed47 --- /dev/null +++ b/docs/development/intro/design.md @@ -0,0 +1,43 @@ +# 设计目标 + +- Xray 内核提供了一个平台,支持必要的网络代理功能,在其之上可以进二次开发,以提供更好的用户体验; +- 以跨平台为首要原则,以减少二次开发的成本; + +## 架构 + +![Architecture](./framework.png) + +内核分为三层:应用层、代理层和传输层。 + +每一层内包含数个模块,模块间互相独立,同类型的模块可无缝替换。 + +### 应用层 + +应用层包含一些代理层中常用的功能,这些功能被抽象出来,以便在不同的代理模块中复用。 + +应用层的模块应为纯软件实现,与硬件或平台相关的技术无关。 + +重要模块列表: + +- Dispatcher: 用于把入站代理所接收到的数据,传送给出站代理; +- Router: 路由模块,详见 [路由配置](../../config/routing.md); +- DNS: 内置的 DNS 服务器模块; +- Proxy Manager: 代理管理器; + +### 代理层 + +代理层分为两部分:入站代理(Inbound Proxy)和出站代理(Outbound Proxy)。 + +两部分相互独立,入站代理不依赖于某个特定的出站代理,反之亦然。 + +#### 入站代理 + +- 实现 [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) 接口; + +### 传输层 + +传输层提供一些网络数据传输相关的工具模块。 diff --git a/docs/development/intro/framework.png b/docs/development/intro/framework.png new file mode 100644 index 0000000000000000000000000000000000000000..194dff8c5cf304ecb6e1eceffb6c17e03d0643ba GIT binary patch literal 67678 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 literal 0 HcmV?d00001 diff --git a/docs/development/intro/guide.md b/docs/development/intro/guide.md new file mode 100644 index 000000000..58bea2241 --- /dev/null +++ b/docs/development/intro/guide.md @@ -0,0 +1,134 @@ +# 开发规范 + +## 基本 + +### 版本控制 + +project X 的代码被托管在 github 上: + +- xray 核心 [xray-core](https://github.com/XTLS/Xray-core) +- xray-flutter [xray-flutter](https://github.com/XTLS/Xray-flutter) +- 安装脚本 [Xray-install](https://github.com/XTLS/Xray-install) +- 数据文件 [Xray-rules-dat](https://github.com/XTLS/Xray-rules-dat) +- 配置模板 [Xray-examples](https://github.com/XTLS/Xray-examples) +- xray 文档 [XTLS.github.io](https://github.com/XTLS/XTLS.github.io) + +您可以使用 [Git](https://git-scm.com/) 来获取代码. + +### 分支(Branch) + +本项目的主干分支为 main, main 分支也是发布时所使用的代码分支, 因此需要确保 master 在任一时刻都是可编译可使用的。 + +如果需要开发新的功能 + +- 请新开分支进行开发, 在开发完成并且经过充分测试后, 合并回主干分支. +- 新开分支如没有必要再存在时, 可以去除. + +### 发布(Release) + + + +- 建立尝鲜版本和稳定版本两个发布通道 + - 临时版本, 主要用于特定情况的测试(比如从分支 build 的), 于 TG 群内/issue 回复等渠道 发布特定版本 + - 尝鲜版本可以为 daily build , 用于尝鲜和获得即时反馈和再改进. + - 稳定版本为定时更新(比如周更), 合并稳定的修改并发布. + +### 引用其它项目 + +- Golang + - 产品代码建议使用 Golang 标准库和 [golang.org/x/](https://pkg.go.dev/search?q=golang.org%2Fx) 下的库; + - 如需引用其它项目,请事先创建 issue 讨论; +- 其它 + - 不违反双方的协议,且对项目有帮助的工具,都可以使用。 + +## 开发流程 + +### 写代码之前 + +发现任何问题,或对项目有任何想法,请创建 Issue 讨论以减少重复劳动和消耗在代码上的时间。 + +### 修改代码 + +- Golang + - 请参考 [Effective Go](https://golang.org/doc/effective_go.html); + - 每一次 push 之前,请运行:`go fmt ./...` 和 `go fmt -s -l -e -w $(find . -type f -name "*.go" ! -name "*.pb.go")`; + - 每一次 push 之前,请确保测试通过:`go test ./...`; + - 提交 pull request 之前,请确保新增代码有超过 70% 的代码覆盖率(code coverage); +- 其它 + - 请注意代码的可读性。 + +### Pull Request + +- 提交 PR 之前,请先运行 `git pull https://github.com/xray/xray-core.git` 以确保 merge 可顺利进行; +- 一个 PR 只做一件事,如有对多个 bug 的修复,请对每一个 bug 提交一个 PR; +- 由于 Golang 的特殊需求(Package path),Go 项目的 PR 流程和其它项目有所不同 ,建议流程如下: + 1. 先 Fork 本项目,创建自己的 `github.com/your/Xray-core` 仓库; + 2. 克隆自己的 Xray 仓库到本地:`git clone https://github.com/your/Xray-core.git`; + 3. 基于 `main` 分支创建新的分支; + 4. 在自行创建的分支上作修改并提交修改(commit); + 5. 在推送(push)修改完成的分支到自己的仓库前,先切换到 `main` 分支,运行 `git pull https://github.com/v2fly/Xray-core.git` 拉取最新的远端代码; + 6. 如果上一步拉取得到了新的远端代码,则切换到之前自己创建的分支,运行 `git rebase master` 执行分支合并操作。如遇到文件冲突,则需要解决冲突; + 7. 上一步处理完毕后,就可以把自己创建的分支推送到自己的仓库:`git push -u origin your-branch` + 8. 最后,把自己仓库的新推送的分支往 `xtls/Xray-core` 的 `main` 分支发 PR 即可; + 9. 请在 PR 的标题和正文中,完整表述此次 PR 解决的问题 / 新增的功能 / 代码所做的修改的用意等; + 10. 耐心等待开发者的回应。 + +### 对代码的修改 + +#### 功能性问题 + +请提交至少一个测试用例(Test Case)来验证对现有功能的改动。 + +#### 性能相关 + +请提交必要的测试数据来证明现有代码的性能缺陷,或是新增代码的性能提升。 + +#### 新功能 + +- 如果新增功能对已有功能不影响,请提供可以开启/关闭的开关(如 flag),并使新功能保持默认关闭的状态; +- 大型新功能(比如增加一个新的协议)开发之前,请先提交一个 issue,讨论完毕之后再进行开发。 + +#### 其它 + +视具体情况而定。 + +## Xray 编码规范 + +以下内容适用于 Xray 中的 Golang 代码。 + +### 代码结构 + +``` +Xray-core +├── app // 应用模块 +│ ├── router // 路由 +├── common // 公用代码 +├── proxy // 通讯协议 +│ ├── blackhole +│ ├── dokodemo-door +│ ├── freedom +│ ├── socks +│ ├── vmess +├── transport // 传输模块 +``` + +### 编码规范 + +基本与 Golang 官方所推荐做法一致,有一些例外。写在这里以方便大家熟悉 Golang。 + +#### 命名 + +- 文件和目录名尽量使用单个英文单词,比如 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 子目录。 diff --git a/docs/development/protocols/mkcp.md b/docs/development/protocols/mkcp.md new file mode 100644 index 000000000..17fde9838 --- /dev/null +++ b/docs/development/protocols/mkcp.md @@ -0,0 +1,92 @@ +# mKCP 协议 + +mKCP 是流式传输协议,由 [KCP 协议](https://github.com/skywind3000/kcp) 修改而来,可以按顺序传输任意的数据流。 + +## 版本 + +mKCP 没有版本号,不保证版本之间兼容性。 + +## 依赖 + +### 底层协议 + +mKCP 是一个基于 UDP 的协议,所有通讯使用 UDP 传输。 + +### 函数 + +- 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)。每个片段需要单独处理。 + +## 数据格式 + +### 数据包 + +| 4 字节 | 2 字节 | L 字节 | +| ---------- | ---------- | -------- | +| 认证信息 A | 数据长度 L | 片段部分 | + +其中: + +- 认证信息 A = fnv(片段部分),big endian; +- 片段部分可能包含多个片段; + +### 数据片段 + +| 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 + +### 确认片段 + +| 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 字节,表示此序列号的数据已经确认收到 + +注释: + +- 远程主机期待收到序列号 [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: 远端主机自己计算出的延迟 diff --git a/docs/development/protocols/muxcool.md b/docs/development/protocols/muxcool.md new file mode 100644 index 000000000..42c3e6cf3 --- /dev/null +++ b/docs/development/protocols/muxcool.md @@ -0,0 +1,116 @@ +# Mux.Cool 协议 + +Mux.Cool 协议是一个多路复用传输协议,用于在一条已建立的数据流中传输多个各自独立的数据流。 + +## 版本 + +当前版本是 1 Beta。 + +## 依赖 + +### 底层协议 + +Mux.Cool 必须运行在一个已建立的可靠数据流之上。 + +## 通讯过程 + +一个 Mux.Cool 连接中可传输若干个子连接,每个子连接有一个独立的 ID 和状态。传输过程由帧(Frame)组成,每一帧用于传输一个特定的子连接的数据。 + +### 客户端行为 + +当有连接需求时并且没有现有可用的连接时,客户端向服务器发起一个新连接,以下称为“主连接”。 + +1. 一个主连接可用于发送若干个子连接。客户端可自主决定主连接可承载的子连接数量。 +1. 对于一个新的子连接,客户端必须发送状态`New`以通知服务器建立子连接,然后使用状态`Keep`来传送数据。 +1. 当子连接结束时,客户端发送`End`状态来通知服务器关闭子连接。 +1. 客户端可自行决定何时关闭主连接,但必须确定服务器也同时保持连接。 +1. 客户端可使用 KeepAlive 状态来避免服务器关闭主连接。 + +### 服务器端行为 + +当服务器端接收到新的子连接时,服务器应当按正常的连接来处理。 + +1. 当收到状态`End`时,服务器端可以关闭对目标地址的上行连接。 +1. 在服务器的响应中,必须使用与请求相同的 ID 来传输子连接的数据。 +1. 服务器不能使用`New`状态。 +1. 服务器可使用 KeepAlive 状态来避免客户端关闭主连接。 + +## 传输格式 + +Mux.Cool 使用对称传输格式,即客户端和服务器发送和接收相同格式的数据。 + +### 帧格式 + +| 2 字节 | L 字节 | X 字节 | +| ------------ | ------ | -------- | +| 元数据长度 L | 元数据 | 额外数据 | + +### 元数据 + +元数据有若干种类型,由状态 S 来区分。所有类型的元数据都包含 ID 和 Opt 两项,其含义为: + +- ID: 子连接的唯一标识 +- Opt: + - D(0x01): 有额外数据 + +当选项 Opt(D) 开启时,额外数据格式如下: + +| 2 字节 | L 字节 | +| ------ | ------ | +| 长度 L | 数据 | + +### 新建子连接 (New) + +| 2 字节 | 1 字节 | 1 字节 | 1 字节 | 2 字节 | 1 字节 | X 字节 | +| ------ | ------ | -------- | ---------- | ------ | ---------- | ------ | +| ID | 0x01 | 选项 Opt | 网络类型 N | 端口 | 地址类型 T | 地址 A | + +其中: + +- 网络类型 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 地址; + +在新建子连接时,若 Opt(D) 开启,则这一帧所带的数据需要被发往目标主机。 + +### 保持子连接 (Keep) + +| 2 字节 | 1 字节 | 1 字节 | +| ------ | ------ | -------- | +| ID | 0x02 | 选项 Opt | + +在保持子连接时,若 Opt(D) 开启,则这一帧所带的数据需要被发往目标主机。 + +### 关闭子连接 (End) + +| 2 字节 | 1 字节 | 1 字节 | +| ------ | ------ | -------- | +| ID | 0x03 | 选项 Opt | + +在保持子连接时,若 Opt(D) 开启,则这一帧所带的数据需要被发往目标主机。 + +### 保持连接 (KeepAlive) + +| 2 字节 | 1 字节 | 1 字节 | +| ------ | ------ | -------- | +| ID | 0x04 | 选项 Opt | + +在保持连接时: + +- 若 Opt(D) 开启,则这一帧所带的数据必须被丢弃。 +- ID 可为随机值。 + +## 应用 + +Mux.Cool 协议与底层协议无关,理论上可以使用任何可靠的流式连接来传输 Mux.Cool 的协议数据。 + +在目标导向的协议如 Shadowsocks 和 VMess 协议中,连接建立时必须包含一个指定的地址。 +为了保持兼容性,Mux.Cool 协议指定地址为“v1.mux.cool”。即当主连接的目标地址与之匹配时,则进行 Mux.Cool 方式的转发,否则按传统方式进行转发。 diff --git a/docs/development/protocols/vless.md b/docs/development/protocols/vless.md new file mode 100644 index 000000000..9756068bb --- /dev/null +++ b/docs/development/protocols/vless.md @@ -0,0 +1,5 @@ +# VLESS 协议 + +VLESS 是一个无状态的轻量传输协议,可以作为 Xray 客户端和服务器之间的桥梁。 + + diff --git a/docs/development/protocols/vmess.md b/docs/development/protocols/vmess.md new file mode 100644 index 000000000..1a1ee8d01 --- /dev/null +++ b/docs/development/protocols/vmess.md @@ -0,0 +1,175 @@ +# VMess 协议 + +VMess 是一个加密传输协议,可以作为 Xray 客户端和服务器之间的桥梁。 + +## 版本 + +当前版本号为 1。 + +## 依赖 + +### 底层协议 + +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 可在[配置文件](../../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) + - 输入参数为任意长度的字符串 + - 输出为任意长度的字符串 + +## 通讯过程 + +VMess 是一个无状态协议,即客户端和服务器之间不需要握手即可直接传输数据,每一次数据传输对之前和之后的其它数据传输没有影响。 + +VMess 的客户端发起一次请求,服务器判断该请求是否来自一个合法的客户端。如验证通过,则转发该请求,并把获得的响应发回给客户端。 + +VMess 使用非对称格式,即客户端发出的请求和服务器端的响应使用了不同的格式。 + +## 客户端请求 + +| 16 字节 | X 字节 | 余下部分 | +| -------- | -------- | -------- | +| 认证信息 | 指令部分 | 数据部分 | + +### 认证信息 + +认证信息是一个 16 字节的哈希(hash)值,它的计算方式如下: + +- H = MD5 +- K = 用户 ID (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。 diff --git a/docs/document/install.md b/docs/document/install.md index 6ba2548ae..66eda7dca 100644 --- a/docs/document/install.md +++ b/docs/document/install.md @@ -23,7 +23,7 @@ Xray 在以下平台中可用: Xray 提供两种验证方式: - ZIP 压缩包的 SHA1 / SHA256 摘要 -- 可复现构建:请参照 [编译 Xray](../development/build.html) +- 可复现构建:请参照 [编译 Xray](../development/intro/compile.md) ## Windows 安装方式