You've already forked Xray-docs-next
mirror of
https://github.com/XTLS/Xray-docs-next.git
synced 2025-12-18 10:03:58 +08:00
Add: development
This commit is contained in:
92
docs/development/protocols/mkcp.md
Normal file
92
docs/development/protocols/mkcp.md
Normal file
@@ -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: 远端主机自己计算出的延迟
|
||||
116
docs/development/protocols/muxcool.md
Normal file
116
docs/development/protocols/muxcool.md
Normal file
@@ -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 方式的转发,否则按传统方式进行转发。
|
||||
5
docs/development/protocols/vless.md
Normal file
5
docs/development/protocols/vless.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# VLESS 协议
|
||||
|
||||
VLESS 是一个无状态的轻量传输协议,可以作为 Xray 客户端和服务器之间的桥梁。
|
||||
|
||||
<Badge text="WIP" type="warning"/>
|
||||
175
docs/development/protocols/vmess.md
Normal file
175
docs/development/protocols/vmess.md
Normal file
@@ -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。
|
||||
Reference in New Issue
Block a user