CI/CD / Build Frontend (push) Failing after 11s
CI/CD / Test (macos-latest) (push) Has been cancelled
CI/CD / Test (windows-latest) (push) Has been cancelled
CI/CD / Build Desktop (linux) (push) Has been cancelled
CI/CD / Build Desktop (macos) (push) Has been cancelled
CI/CD / Build Desktop (windows) (push) Has been cancelled
CI/CD / Release (push) Has been cancelled
CI/CD / Test (ubuntu-latest) (push) Failing after 2s
- tscore: Protocol implementation (packets, crypto, connection handshake) - tsaudio: Audio engine (capture, playback, codec, VAD, jitter buffer) - tsdb: SQLite database (identities, bookmarks, messages, settings) - shared: Core types and events - tauri-app: Tauri v2 desktop application with React frontend - docs: SRS, SAD, SDD documentation - CI/CD: GitHub Actions workflow - 32 unit tests passing
417 lines
10 KiB
Markdown
417 lines
10 KiB
Markdown
# TeamSpeak 3 协议分析
|
|
|
|
## 概述
|
|
|
|
TeamSpeak 3 使用基于 UDP 的自定义协议进行通信。协议设计支持加密、压缩和可靠传输。
|
|
|
|
## 协议层次
|
|
|
|
```
|
|
应用层 (Commands/Notifications)
|
|
↓
|
|
消息层 (Messages)
|
|
↓
|
|
数据包层 (Packets)
|
|
↓
|
|
传输层 (UDP)
|
|
```
|
|
|
|
## 1. 数据包结构
|
|
|
|
### 1.1 数据包头
|
|
|
|
**客户端 → 服务器**:
|
|
```
|
|
+--+--+--+--+--+--+--+--+--+--+--+--+--+---------//----------+
|
|
| MAC | PId | CId |PT| Data |
|
|
+--+--+--+--+--+--+--+--+--+--+--+--+--+---------//----------+
|
|
| \ Meta |
|
|
\ Header /
|
|
```
|
|
|
|
**服务器 → 客户端**:
|
|
```
|
|
+--+--+--+--+--+--+--+--+--+--+--+------------//-------------+
|
|
| MAC | PId |PT| Data |
|
|
+--+--+--+--+--+--+--+--+--+--+--+------------//-------------+
|
|
| \ Meta |
|
|
\ Header /
|
|
```
|
|
|
|
| 字段 | 大小 | 类型 | 说明 |
|
|
|------|------|------|------|
|
|
| MAC | 8 字节 | [u8] | EAX 消息认证码 |
|
|
| PId | 2 字节 | u16 | 数据包 ID |
|
|
| CId | 2 字节 | u16 | 客户端 ID (仅客户端→服务器) |
|
|
| PT | 1 字节 | u8 | 数据包类型 + 标志 |
|
|
| Data | ≤487/489 字节 | [u8] | 数据包负载 |
|
|
|
|
### 1.2 数据包类型
|
|
|
|
| 类型 | 值 | 说明 |
|
|
|------|-----|------|
|
|
| Voice | 0x00 | 语音数据 |
|
|
| VoiceWhisper | 0x01 | 私语数据 |
|
|
| Command | 0x02 | 命令数据 |
|
|
| CommandLow | 0x03 | 低优先级命令 |
|
|
| Ping | 0x04 | Ping 包 |
|
|
| Pong | 0x05 | Pong 包 |
|
|
| Ack | 0x06 | 确认包 |
|
|
| AckLow | 0x07 | 低优先级确认 |
|
|
| Init1 | 0x08 | 初始化包 |
|
|
|
|
### 1.3 标志位
|
|
|
|
```
|
|
MSB LSB
|
|
+--+--+--+--+--+--+--+--+
|
|
|UE|CP|NP|FR| Type |
|
|
+--+--+--+--+--+--+--+--+
|
|
```
|
|
|
|
| 标志 | 位 | 说明 |
|
|
|------|-----|------|
|
|
| UE | 0x80 | 未加密 |
|
|
| CP | 0x40 | 已压缩 |
|
|
| NP | 0x20 | 新协议 |
|
|
| FR | 0x10 | 已分片 |
|
|
|
|
## 2. 初始化握手
|
|
|
|
### 2.1 低级握手 (Init1)
|
|
|
|
握手过程包含 5 个步骤:
|
|
|
|
1. **Packet 0 (客户端→服务器)**:
|
|
- 客户端版本 (4 字节时间戳)
|
|
- 步骤号: 0x00
|
|
- 当前时间戳 (4 字节)
|
|
- 随机数 A0 (4 字节)
|
|
- 保留字节 (8 字节)
|
|
|
|
2. **Packet 1 (服务器→客户端)**:
|
|
- 步骤号: 0x01
|
|
- 服务器数据 A1 (16 字节)
|
|
- A0 反转 (4 字节)
|
|
|
|
3. **Packet 2 (客户端→服务器)**:
|
|
- 客户端版本
|
|
- 步骤号: 0x02
|
|
- A1 (16 字节)
|
|
- A0r (4 字节)
|
|
|
|
4. **Packet 3 (服务器→客户端)**:
|
|
- 步骤号: 0x03
|
|
- x (64 字节)
|
|
- n (64 字节)
|
|
- level (4 字节)
|
|
- 服务器数据 A2 (100 字节)
|
|
|
|
5. **Packet 4 (客户端→服务器)**:
|
|
- 客户端版本
|
|
- 步骤号: 0x04
|
|
- x, n, level
|
|
- A2 (100 字节)
|
|
- y = x^(2^level) mod n (64 字节)
|
|
- clientinitiv 命令
|
|
|
|
### 2.2 高级握手
|
|
|
|
#### 2.2.1 clientinitiv (客户端→服务器)
|
|
```
|
|
clientinitiv alpha={alpha} omega={omega} ot={ot} ip={ip}
|
|
```
|
|
- `alpha`: 10 随机字节的 base64 编码
|
|
- `omega`: ASN.1-DER 编码的 ECDH 公钥
|
|
- `ot`: 固定为 1
|
|
- `ip`: 服务器 IP 地址
|
|
|
|
#### 2.2.2 initivexpand/initivexpand2 (服务器→客户端)
|
|
|
|
**旧协议 (<3.1)**:
|
|
```
|
|
initivexpand alpha={alpha} beta={beta} omega={omega}
|
|
```
|
|
|
|
**新协议 (≥3.1)**:
|
|
```
|
|
initivexpand2 l={l} beta={beta} omega={omega} ot={ot} proof={proof} tvd={tvd}
|
|
```
|
|
|
|
#### 2.2.3 共享密钥计算
|
|
|
|
**旧协议**:
|
|
```rust
|
|
sharedSecret = ECDH(serverPublicKey, ownPrivateKey)
|
|
x = sharedSecret.x.AsByteArray()
|
|
sharedData = x[0..32] (填充到 32 字节)
|
|
SharedIV = sha1(sharedData)
|
|
SharedIV[0..10] ^= alpha.decode64()
|
|
SharedIV[10..20] ^= beta.decode64()
|
|
SharedMac = sha1(SharedIV)[0..8]
|
|
```
|
|
|
|
**新协议**:
|
|
```rust
|
|
// 处理许可证链
|
|
next_key = public_key * clamp(sha512(block[1..])[0..32]) + parent
|
|
|
|
// 计算共享密钥
|
|
sharedData = next_key * client_private_key
|
|
SharedIV = sha512(sharedData[0..32])
|
|
SharedIV[0..10] ^= alpha.decode64()
|
|
SharedIV[10..64] ^= beta.decode64()
|
|
SharedMac = sha1(SharedIV)[0..8]
|
|
```
|
|
|
|
## 3. 加密机制
|
|
|
|
### 3.1 EAX 模式加密
|
|
|
|
使用 AES-128-CTR + OMAC (EAX 模式) 加密数据包。
|
|
|
|
**加密参数生成**:
|
|
```rust
|
|
temporary[0] = 0x30 (服务器→客户端) 或 0x31 (客户端→服务器)
|
|
temporary[1] = PT
|
|
temporary[2..6] = PGId (网络字节序)
|
|
temporary[6..26] = SIV[0..20] (旧协议) 或 temporary[6..70] = SIV[0..64] (新协议)
|
|
|
|
keynonce = sha256(temporary)
|
|
key = keynonce[0..16]
|
|
nonce = keynonce[16..32]
|
|
key[0] ^= ((PId & 0xFF00) >> 8)
|
|
key[1] ^= ((PId & 0x00FF) >> 0)
|
|
```
|
|
|
|
### 3.2 数据包栈
|
|
|
|
```
|
|
发送 接收
|
|
+-----------+ +-----------+
|
|
| Data | | Λ | Data |
|
|
+-----------+ | | +-----------+
|
|
| Compress | | | | Decompress|
|
|
+-----------+ | | +-----------+
|
|
| Split | | | | Merge |
|
|
+-----------+ | | +-----------+
|
|
| Encrypt | V | | Decrypt |
|
|
+-----------+ +-----------+
|
|
```
|
|
|
|
## 4. 命令协议
|
|
|
|
### 4.1 命令格式
|
|
|
|
命令使用类似 TeamSpeak 3 Query 的文本格式,UTF-8 编码。
|
|
|
|
**示例**:
|
|
```
|
|
clientinit client_nickname=MyName client_version=3.0.19.3 client_platform=Windows ...
|
|
```
|
|
|
|
### 4.2 消息类型
|
|
|
|
1. **请求-响应**: 客户端发送命令,服务器返回响应
|
|
2. **通知**: 服务器主动推送的事件通知
|
|
3. **列表**: 分批返回的列表数据
|
|
|
|
### 4.3 关键命令
|
|
|
|
#### 客户端初始化
|
|
```
|
|
clientinit client_nickname client_version client_platform client_input_hardware client_output_hardware client_default_channel client_default_channel_password client_server_password client_meta_data client_version_sign client_key_offset client_nickname_phonetic client_default_token hwid
|
|
```
|
|
|
|
#### 服务器初始化响应
|
|
```
|
|
initserver server_name server_platform server_version ...
|
|
```
|
|
|
|
#### 频道列表
|
|
```
|
|
channellist -topic -flags -limits
|
|
channellistfinished
|
|
```
|
|
|
|
#### 客户端进入视图
|
|
```
|
|
notifycliententerview cfid ctid reasonid clid client_database_id client_nickname ...
|
|
```
|
|
|
|
## 5. 数据结构
|
|
|
|
### 5.1 客户端数据
|
|
|
|
| 字段 | 类型 | 说明 |
|
|
|------|------|------|
|
|
| client_id | ClientId | 客户端 ID |
|
|
| client_database_id | ClientDbId | 数据库 ID |
|
|
| client_unique_identifier | Uid | 唯一标识符 |
|
|
| client_nickname | str | 昵称 |
|
|
| client_type | ClientType | 客户端类型 |
|
|
| client_servergroups | ServerGroupId | 服务器组 |
|
|
| client_channel_group_id | ChannelGroupId | 频道组 |
|
|
| client_away | bool | 是否离开 |
|
|
| client_away_message | str | 离开消息 |
|
|
| client_talk_power | i32 | 说话权限 |
|
|
| client_is_talker | bool | 是否有说话权 |
|
|
| client_is_priority_speaker | bool | 是否优先发言者 |
|
|
| client_is_channel_commander | bool | 是否频道指挥官 |
|
|
| client_is_recording | bool | 是否录音中 |
|
|
| client_input_muted | bool | 输入是否静音 |
|
|
| client_output_muted | bool | 输出是否静音 |
|
|
|
|
### 5.2 频道数据
|
|
|
|
| 字段 | 类型 | 说明 |
|
|
|------|------|------|
|
|
| channel_id | ChannelId | 频道 ID |
|
|
| channel_name | str | 频道名称 |
|
|
| channel_topic | str | 频道主题 |
|
|
| channel_codec | Codec | 编解码器 |
|
|
| channel_codec_quality | u8 | 编解码器质量 |
|
|
| channel_maxclients | i32 | 最大客户端数 |
|
|
| channel_maxfamilyclients | i32 | 最大系列客户端数 |
|
|
| channel_flag_permanent | bool | 是否永久频道 |
|
|
| channel_flag_semi_permanent | bool | 是否半永久频道 |
|
|
| channel_flag_default | bool | 是否默认频道 |
|
|
| channel_flag_password | bool | 是否有密码 |
|
|
| channel_needed_talk_power | i32 | 所需说话权限 |
|
|
| channel_forced_silence | bool | 是否强制静音 |
|
|
|
|
### 5.3 服务器数据
|
|
|
|
| 字段 | 类型 | 说明 |
|
|
|------|------|------|
|
|
| virtualserver_name | str | 服务器名称 |
|
|
| virtualserver_platform | str | 平台 |
|
|
| virtualserver_version | str | 版本 |
|
|
| virtualserver_maxclients | u16 | 最大客户端数 |
|
|
| virtualserver_clientsonline | u16 | 在线客户端数 |
|
|
| virtualserver_channelsonline | u64 | 频道数 |
|
|
| virtualserver_uptime | DurationSeconds | 运行时间 |
|
|
| virtualserver_codec_encryption_mode | CodecEncryptionMode | 编解码器加密模式 |
|
|
| virtualserver_hostmessage | str | 主机消息 |
|
|
| virtualserver_hostmessage_mode | HostMessageMode | 主机消息模式 |
|
|
|
|
## 6. 错误处理
|
|
|
|
### 6.1 错误码格式
|
|
|
|
错误响应格式:
|
|
```
|
|
error id=0 msg=ok
|
|
```
|
|
|
|
### 6.2 常见错误码
|
|
|
|
| 错误码 | 名称 | 说明 |
|
|
|--------|------|------|
|
|
| 0x0000 | ok | 成功 |
|
|
| 0x0200 | client_invalid_id | 无效客户端 ID |
|
|
| 0x0201 | client_nickname_inuse | 昵称已被使用 |
|
|
| 0x0208 | client_invalid_password | 无效密码 |
|
|
| 0x0300 | channel_invalid_id | 无效频道 ID |
|
|
| 0x0400 | server_invalid_id | 无效服务器 ID |
|
|
| 0x0403 | server_maxclients_reached | 服务器已满 |
|
|
|
|
## 7. 版本兼容性
|
|
|
|
### 7.1 协议版本
|
|
|
|
- **旧协议**: <3.1,使用 initivexpand
|
|
- **新协议**: ≥3.1,使用 initivexpand2,支持许可证验证
|
|
|
|
### 7.2 客户端版本
|
|
|
|
客户端版本使用时间戳格式:
|
|
```
|
|
3.0.19.3 [Build: 1466672534]
|
|
```
|
|
|
|
版本时间戳计算:
|
|
```
|
|
version_timestamp = unix_timestamp - 1356998400
|
|
```
|
|
|
|
## 8. 安全机制
|
|
|
|
### 8.1 RSA 拼图
|
|
|
|
防止 DoS 攻击的机制:
|
|
- 服务器发送 RSA 模数 n、底数 x 和难度 level
|
|
- 客户端计算 y = x^(2^level) mod n
|
|
- 计算时间随 level 指数增长
|
|
|
|
### 8.2 Hashcash
|
|
|
|
身份验证的 hashcash 机制:
|
|
```rust
|
|
data = sha1(publicKey + keyOffset)
|
|
level = count_leading_zero_bits(data)
|
|
```
|
|
|
|
### 8.3 身份识别
|
|
|
|
客户端唯一标识符计算:
|
|
```rust
|
|
uid = base64(sha1(publicKey))
|
|
```
|
|
|
|
## 9. 语音传输
|
|
|
|
### 9.1 编解码器
|
|
|
|
| 编解码器 | 说明 |
|
|
|----------|------|
|
|
| SpeexNarrowband | 8kHz, 单声道 |
|
|
| SpeexWideband | 16kHz, 单声道 |
|
|
| SpeexUltrawideband | 32kHz, 单声道 |
|
|
| CeltMono | 48kHz, 单声道 |
|
|
| OpusVoice | 48kHz, 单声道, 语音优化 |
|
|
| OpusMusic | 48kHz, 立体声, 音乐优化 |
|
|
|
|
### 9.2 语音包格式
|
|
|
|
**客户端→服务器**:
|
|
```
|
|
+--+--+--+---------//---------+
|
|
| VId |C | Data |
|
|
+--+--+--+---------//---------+
|
|
```
|
|
|
|
**服务器→客户端**:
|
|
```
|
|
+--+--+--+--+--+---------//---------+
|
|
| VId | CId |C | Data |
|
|
+--+--+--+--+--+---------//---------+
|
|
```
|
|
|
|
### 9.3 私语
|
|
|
|
支持两种私语模式:
|
|
1. **直接目标**: 指定客户端/频道 ID
|
|
2. **组目标**: 指定服务器组/频道组
|
|
|
|
## 10. 连接管理
|
|
|
|
### 10.1 心跳
|
|
|
|
- 服务器定期发送 Ping 包
|
|
- 客户端必须回复 Pong 包
|
|
- 客户端也应主动发送 Ping 包
|
|
|
|
### 10.2 可靠传输
|
|
|
|
- 使用选择性重传机制
|
|
- 超时后重传数据包
|
|
- 30 秒无响应则断开连接
|
|
- 使用指数退避算法避免网络拥塞
|
|
|
|
### 10.3 数据包 ID 管理
|
|
|
|
- 每种数据包类型和方向有独立的 ID 计数器
|
|
- 客户端有 9 个出站计数器
|
|
- ID 从 1 开始,溢出时增加代计数器
|
|
- 代计数器用于加密参数生成 |