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