# 协议规范

## 握手消息

握手消息由客户端发送给服务器,无论认证是否通过,服务器都不会产生任何响应.

- Type: 用于区分数据包类型，始终为 0
- TUN IP: 用于建立目的地址与 WebSocket 之间的映射
- Timestamp: 用于检查握手时间,避免重放攻击
- Hash: 用于身份认证,由密码,TUN IP 和时间戳生成
- Confusion: 用于隐藏报文的固定长度特征,占用随机长度,填充随机内容

```plaintext
+--------------------------------------------------------------------------------------------------+
| Type (1 Byte) | TUN IP (4 Bytes) | Timestamp (8 Bytes) | Hash (32 Bytes) | Confusion (n Byte[s]) |
+--------------------------------------------------------------------------------------------------+
```

## IP 数据包转发消息

客户端和服务器互相发送,客户端将从 TUN 读取的数据转发到服务器,将从服务器接收到的数据转发到 TUN.服务器收到数据包后,解析源地址 IP, 验证 IP 与Websocket 的映射关系是否建立,获取目的地址 IP, 并将数据包转发给对应的 WebSocket.

- Type: 用于区分数据包类型,始终为 1
- Raw: IP 层原始数据

```plaintext
+-------------------------------+
| Type (1 Byte) | Raw (n Bytes) |
+-------------------------------+
```

## 动态地址消息

客户端使用动态地址消息向服务器请求可用地址.

- Type: 用于区分数据包类型,始终为 2
- Timestamp: 用于检查握手时间,避免重放攻击
- CIDR: 以“\0”结尾的字符串,客户端携带想要使用的地址,服务端优先尝试分配这个地址
- Hash: 用于身份认证,由密码,TUN IP 和时间戳生成
- Confusion: 用于隐藏报文固定长度特征,占用随机长度,填充随机内容

```plaintext
+-------------------------------------------------------------------------------------------------+
| Type (1 Byte) | Timestamp (8 Bytes) | CIDR (32 Bytes) | Hash (32 Bytes) | Confusion (n Byte[s]) |
+-------------------------------------------------------------------------------------------------+
```

## 对等连接公网信息交换消息

对等连接的客户端双方通过服务端传递双方公网信息.

- Type: 用于区分数据包类型,始终为 3
- Src: 虚拟源地址
- Dst: 虚拟目的地址
- IP: 本客户端用于对等连接的公网地址
- Port: 本客户端用于对等连接监听的公网端口

```plaintext
+-------------------------------------------------------------------------------+
| Type (1 Byte) | Src (4 Bytes) | Dst (4 Bytes) | IP (4 Bytes) | Port (2 Bytes) |
+-------------------------------------------------------------------------------+
```

## 虚拟硬件地址消息

在原本的设计中,同一个客户端应当先断开再连接.在实际使用中发现,由于网络原因会出现某个客户端重连一段时间后,服务端才断开上一个连接的情况,这将导致自动分配地址的客户端被重新分配新地址.为了解决这个问题引入虚拟硬件地址,类似传输层的 MAC 地址,这个值随机生成.随机生成的地址有碰撞的风险,当且仅当两个不同的客户端生成了相同的虚拟硬件地址并且虚拟 IP 地址都相同时,才会产生冲突,此时需要手动操作删除缓存的虚拟硬件地址.

- Type: 用于区分数据包类型,始终为 4
- VMac: 虚拟硬件地址
- Timestamp: 用于检查握手时间,避免重放攻击
- Hash: 用于身份认证,由密码,虚拟硬件地址和时间戳生成
- Confusion: 用于隐藏报文固定长度特征,占用随机长度,填充随机内容

```plaintext
+--------------------------------------------------------------------------------------------- --+
| Type (1 Byte) | VMac(16 Bytes) | Timestamp (8 Bytes) | Hash (32 Bytes) | Confusion (n Byte[s]) |
+------------------------------------------------------------------------------------------------+
```

## 主动发现消息

向对方发送通知,用于在没有数据流量时主动尝试建立对等连接.目的地址可以是广播地址 `255.255.255.255`.

- Type: 用于区分数据包类型,始终为 5
- Src: 虚拟源地址
- Dst: 虚拟目的地址

```plaintext
+-----------------------------------------------+
| Type (1 Byte) | Src (4 Bytes) | Dst (4 Bytes) |
+-----------------------------------------------+
```

## GENERAL 消息

未来可能会有很多与主动发现消息类似的消息,这些消息只需要通过服务端转发,不需要服务端理解报文内容.因此添加一个通用的报文格式.

- Type: 用于区分数据包类型,始终为 255
- Subtype: 子类型
- Extra: 由子类型自行使用的自定义内容
- Src: 虚拟源地址
- Dst: 虚拟目的地址
- Data: 子类型的数据部分

```plaintext
+------------------------------------------------------------------------------------------------------+
| Type (1 Byte) | Subtype (1 Byte) | Extra (2 Byte) | Src (4 Bytes) | Dst (4 Bytes) | Data (n Byte[s]) |
+------------------------------------------------------------------------------------------------------+
```

后续消息由 GENERAL 实现

### 交换局域网地址端口

有些设备在同一个局域网内,他们可以不通过公网 IP 建立连接.因此新增一个与对等连接公网信息交换消息类似的消息,但把地址和端口替换成局域网信息.

- Subtype: 0
- Extra: 0
- IP: 局域网 IPv4 地址
- Port: 局域网端口号

```plaintext
+-------------------------------+
| IP (4 Bytes) | Port (2 Bytes) |
+-------------------------------+
```
