Files
ReTeamSpeak ea08823c97
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
Initial commit: ReTeamSpeak cross-platform TeamSpeak client
- 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
2026-05-12 14:41:54 +09:00

10 KiB

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 共享密钥计算

旧协议:

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]

新协议:

// 处理许可证链
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 模式) 加密数据包。

加密参数生成:

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 机制:

data = sha1(publicKey + keyOffset)
level = count_leading_zero_bits(data)

8.3 身份识别

客户端唯一标识符计算:

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 开始,溢出时增加代计数器
  • 代计数器用于加密参数生成