# TeamSpeak 3 协议栈分析 ## 1. 协议栈层次结构 ``` ┌─────────────────────────────────────────────────────────────┐ │ 应用层 (Application Layer) │ │ - 命令/通知 (Commands/Notifications) │ │ - 文本消息、频道管理、客户端管理 │ ├─────────────────────────────────────────────────────────────┤ │ 消息层 (Message Layer) │ │ - 命令解析 (Command Parsing) │ │ - 参数编码/解码 (Parameter Encoding/Decoding) │ │ - BBCode 格式 │ ├─────────────────────────────────────────────────────────────┤ │ 数据包层 (Packet Layer) │ │ - 数据包格式 (Packet Format) │ │ - 数据包类型 (Packet Types) │ │ - 分片/重组 (Fragmentation/Reassembly) │ │ - 压缩/解压 (Compression/Decompression) │ ├─────────────────────────────────────────────────────────────┤ │ 加密层 (Encryption Layer) │ │ - AES-128-EAX 加密/解密 │ │ - ECDH 密钥交换 │ │ - 密钥派生 (Key Derivation) │ ├─────────────────────────────────────────────────────────────┤ │ 可靠传输层 (Reliable Transport Layer) │ │ - 选择性重传 (Selective Repeat) │ │ - 拥塞控制 (Congestion Control) │ │ - 流量控制 (Flow Control) │ ├─────────────────────────────────────────────────────────────┤ │ 传输层 (Transport Layer) │ │ - UDP 协议 │ │ - 最大包大小: 500 字节 │ └─────────────────────────────────────────────────────────────┘ ``` ## 2. 数据包格式详解 ### 2.1 数据包头结构 #### 客户端 → 服务器 (C2S) ``` 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | MAC (8 bytes) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Packet ID | Client ID | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | PT | Data (≤487 bytes) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ``` #### 服务器 → 客户端 (S2C) ``` 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | MAC (8 bytes) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Packet ID | PT | Data (≤489 bytes) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ``` **字段说明**: | 字段 | 大小 | 类型 | 说明 | |------|------|------|------| | MAC | 8 字节 | [u8; 8] | EAX 消息认证码 | | PId | 2 字节 | u16 | 数据包 ID (网络字节序) | | CId | 2 字节 | u16 | 客户端 ID (仅 C2S) | | PT | 1 字节 | u8 | 数据包类型 + 标志位 | | Data | 变长 | [u8] | 数据包负载 | ### 2.2 数据包类型和标志位 #### PT 字段结构 ``` 7 6 5 4 3 2 1 0 +---+---+---+---+---+---+---+---+ |UE |CP |NP |FR | Type | +---+---+---+---+---+---+---+---+ ``` | 标志位 | 位 | 十六进制 | 说明 | |--------|-----|----------|------| | UE | 7 | 0x80 | 未加密 (Unencrypted) | | CP | 6 | 0x40 | 已压缩 (Compressed) | | NP | 5 | 0x20 | 新协议 (Newprotocol) | | FR | 4 | 0x10 | 已分片 (Fragmented) | | Type | 3-0 | 0x00-0x08 | 数据包类型 | #### 数据包类型 | 类型 | 值 | 说明 | 方向 | |------|-----|------|------| | Voice | 0x00 | 语音数据 | 双向 | | VoiceWhisper | 0x01 | 私语数据 | 双向 | | Command | 0x02 | 命令数据 | 双向 | | CommandLow | 0x03 | 低优先级命令 | 双向 | | Ping | 0x04 | Ping 包 | C2S | | Pong | 0x05 | Pong 包 | S2C | | Ack | 0x06 | 确认包 | 双向 | | AckLow | 0x07 | 低优先级确认 | 双向 | | Init1 | 0x08 | 初始化包 | 双向 | ### 2.3 数据包类型特性 | 类型 | 需要确认 | 可重传 | 可加密 | 可分片 | 可压缩 | |------|----------|--------|--------|--------|--------| | Voice | ✗ | ✗ | 可选 | ✗ | ✗ | | VoiceWhisper | ✗ | ✗ | 可选 | ✗ | ✗ | | Command | ✓ (Ack) | ✓ | ✓ | ✓ | ✓ | | CommandLow | ✓ (AckLow) | ✓ | ✓ | ✓ | ✓ | | Ping | ✓ (Pong) | ✗ | ✗ | ✗ | ✗ | | Pong | ✗ | ✗ | ✗ | ✗ | ✗ | | Ack | ✗ | ✓ | ✓ | ✗ | ✗ | | AckLow | ✗ | ✓ | ✓ | ✗ | ✗ | | Init1 | ✓ (Init1) | ✓ | ✗ | ✗ | ✗ | ## 3. 数据包处理流程 ### 3.1 发送流程 ``` 应用数据 ↓ ┌─────────────────────────────────────┐ │ 1. 命令序列化 │ │ - 参数编码 (key=value) │ │ - UTF-8 编码 │ │ - BBCode 格式化 │ └─────────────────────────────────────┘ ↓ ┌─────────────────────────────────────┐ │ 2. 压缩 (QuickLZ Level 1) │ │ - 仅 Command/CommandLow │ │ - 仅当压缩后更小时 │ └─────────────────────────────────────┘ ↓ ┌─────────────────────────────────────┐ │ 3. 分片 │ │ - 最大 500 字节 (含头) │ │ - 仅 Command/CommandLow │ │ - 首尾包设置 FR 标志 │ │ - 首包设置 CP 标志 │ └─────────────────────────────────────┘ ↓ ┌─────────────────────────────────────┐ │ 4. 加密 (AES-128-EAX) │ │ - 生成密钥和 Nonce │ │ - EAX 模式加密 │ │ - 生成 MAC │ └─────────────────────────────────────┘ ↓ ┌─────────────────────────────────────┐ │ 5. 分配 Packet ID │ │ - 每种类型独立计数器 │ │ - 溢出时增加 Generation ID │ └─────────────────────────────────────┘ ↓ ┌─────────────────────────────────────┐ │ 6. 发送 │ │ - UDP 发送 │ │ - 加入重传队列 (如需要) │ └─────────────────────────────────────┘ ``` ### 3.2 接收流程 ``` UDP 数据包 ↓ ┌─────────────────────────────────────┐ │ 1. 验证 │ │ - 检查地址 │ │ - 检查客户端 ID │ │ - 检查接收窗口 │ └─────────────────────────────────────┘ ↓ ┌─────────────────────────────────────┐ │ 2. 解密 (AES-128-EAX) │ │ - 生成密钥和 Nonce │ │ - EAX 模式解密 │ │ - 验证 MAC │ └─────────────────────────────────────┘ ↓ ┌─────────────────────────────────────┐ │ 3. 重组 │ │ - 处理分片队列 │ │ - 按 Packet ID 排序 │ └─────────────────────────────────────┘ ↓ ┌─────────────────────────────────────┐ │ 4. 解压 (QuickLZ) │ │ - 仅当 CP 标志设置时 │ │ - 最大解压大小: 2MB │ └─────────────────────────────────────┘ ↓ ┌─────────────────────────────────────┐ │ 5. 命令解析 │ │ - UTF-8 解码 │ │ - 参数解析 (key=value) │ │ - 转义序列处理 │ └─────────────────────────────────────┘ ↓ ┌─────────────────────────────────────┐ │ 6. 发送确认 │ │ - Command → Ack │ │ - CommandLow → AckLow │ │ - Ping → Pong │ └─────────────────────────────────────┘ ``` ## 4. 加密机制详解 ### 4.1 EAX 模式加密 TeamSpeak 3 使用 AES-128-EAX 模式进行加密,EAX 模式是一种认证加密模式,提供: - **机密性**: AES-128-CTR 加密 - **完整性**: OMAC (One-key MAC) 消息认证 - **真实性**: 8 字节 MAC 标签 ### 4.2 密钥派生 #### 密钥生成算法 ```rust fn create_key_nonce( p_type: PacketType, // 数据包类型 c_id: Option, // 客户端 ID (方向) p_id: u16, // 数据包 ID generation_id: u32, // 代 ID iv: &[u8; 64], // 共享 IV ) -> (Key, Nonce) { // 构建临时数组 let mut temp = [0; 70]; temp[0] = if c_id.is_some() { 0x31 } else { 0x30 }; // 方向 temp[1] = p_type as u8; // 类型 temp[2..6] = generation_id.to_be_bytes(); // 代 ID temp[6..] = iv; // 共享 IV // SHA-256 哈希 let keynonce = sha256(&temp); // 提取密钥和 Nonce let key = keynonce[0..16]; let nonce = keynonce[16..32]; // 用 Packet ID 修改密钥 key[0] ^= (p_id >> 8) as u8; key[1] ^= (p_id & 0xff) as u8; (key, nonce) } ``` #### 密钥缓存 为提高性能,可以缓存每个 `(PacketType, Direction, GenerationId)` 组合的密钥: - 缓存大小: 8 种类型 × 2 种方向 = 16 个条目 - 仅在 Generation ID 变化时重新计算 ### 4.3 假加密 (Fake Encryption) 某些数据包使用固定的假密钥进行加密: ```rust const FAKE_KEY: [u8; 16] = *b"c:\\windows\\syste"; const FAKE_NONCE: [u8; 16] = *b"m\\firewall32.cpl"; ``` **使用假加密的场景**: 1. 初始化期间的命令包 2. 客户端的第一个 Ack 包 3. 服务器的第一个命令包 ### 4.4 共享密钥计算 #### 旧协议 (<3.1) ```rust fn compute_shared_iv_mac_old( alpha: &[u8; 10], // 客户端随机数 beta: &[u8; 10], // 服务器随机数 server_pubkey: &PublicKey, // 服务器公钥 client_privkey: &PrivateKey, // 客户端私钥 ) -> (SharedIV, SharedMac) { // ECDH 密钥交换 let shared_secret = ecdh(server_pubkey, client_privkey); let x = shared_secret.x.to_bytes(); // 填充到 32 字节 let mut shared_data = [0; 32]; shared_data[32 - x.len()..].copy_from_slice(&x); // SHA-1 哈希 let mut shared_iv = sha1(&shared_data); // 与 alpha/beta 异或 shared_iv[0..10] ^= alpha; shared_iv[10..20] ^= beta; // 计算 MAC let shared_mac = sha1(&shared_iv)[0..8]; (shared_iv, shared_mac) } ``` #### 新协议 (≥3.1) ```rust fn compute_shared_iv_mac_new( alpha: &[u8; 10], // 客户端随机数 beta: &[u8; 54], // 服务器随机数 (更长) licenses: &Licenses, // 许可证链 client_privkey: &Ed25519PrivateKey, // 客户端临时私钥 ) -> (SharedIV, SharedMac) { // 从许可证链派生服务器公钥 let server_pubkey = derive_key_from_licenses(licenses); // Curve25519 密钥交换 let shared_secret = client_privkey.create_shared_secret(&server_pubkey); // SHA-512 哈希 let mut shared_iv = sha512(&shared_secret); // 与 alpha/beta 异或 shared_iv[0..10] ^= alpha; shared_iv[10..64] ^= beta; // 计算 MAC let shared_mac = sha1(&shared_iv)[0..8]; (shared_iv, shared_mac) } ``` ## 5. 可靠传输机制 ### 5.1 数据包确认 #### 确认机制 - **Command** 包需要 **Ack** 确认 - **CommandLow** 包需要 **AckLow** 确认 - **Ping** 包需要 **Pong** 确认 - **Init1** 包需要下一个 **Init1** 确认 #### 确认包格式 ``` +--+--+ | PId | +--+--+ ``` - PId: 被确认的数据包 ID (2 字节) ### 5.2 选择性重传 ```rust struct Resender { // 发送队列: 等待确认的数据包 send_queue: BTreeMap, // 重传超时计算 rtt_estimate: Duration, rtt_deviation: Duration, // 拥塞窗口 congestion_window: u32, } struct SentPacket { data: Vec, send_time: Instant, retry_count: u32, } ``` #### 重传策略 1. **超时计算**: 使用指数退避算法 ``` timeout = rtt_estimate + 4 * rtt_deviation timeout = min(timeout * 2^retry_count, MAX_TIMEOUT) ``` 2. **重传条件**: - 数据包超时未确认 - 收到重复的确认包 3. **放弃条件**: - 超过 30 秒未确认 - 达到最大重试次数 ### 5.3 拥塞控制 TeamSpeak 3 使用类似 TCP CUBIC 的拥塞控制算法: ```rust struct CongestionControl { // 拥塞窗口大小 (数据包数量) cwnd: u32, // 慢启动阈值 ssthresh: u32, // 丢包检测 loss_detector: LossDetector, } impl CongestionControl { fn on_ack(&mut self, acked_bytes: u32) { if self.cwnd < self.ssthresh { // 慢启动阶段: 指数增长 self.cwnd += acked_bytes; } else { // 拥塞避免阶段: 线性增长 self.cwnd += acked_bytes / self.cwnd; } } fn on_loss(&mut self) { // 丢包检测: 减小拥塞窗口 self.ssthresh = self.cwnd / 2; self.cwnd = self.ssthresh; } } ``` ### 5.4 流量控制 #### 接收窗口 ```rust struct ReceiveWindow { // 下一个期望的数据包 ID next_expected: u16, // 接收队列大小 queue_size: u16, // 最大队列长度 max_queue_len: u16, // 200 } ``` #### 发送窗口 ```rust struct SendWindow { // 当前发送的数据包 ID current_id: u16, // 拥塞窗口大小 congestion_window: u32, // 已发送未确认的数据包数量 in_flight: u32, } ``` ## 6. 命令协议详解 ### 6.1 命令格式 命令使用类似 TeamSpeak 3 Query 的文本格式,UTF-8 编码: ``` command_name key1=value1 key2=value2 ... ``` #### 转义序列 | 原始字符 | 转义序列 | 说明 | |----------|----------|------| | `\` | `\\` | 反斜杠 | | ` ` | `\s` | 空格 | | `|` | `\p` | 管道符 | | `/` | `\/` | 斜杠 | | `\n` | `\n` | 换行符 | ### 6.2 命令类型 #### 请求-响应命令 ``` 客户端发送: clientinit client_nickname=MyName client_version=3.0.19.3 ... 服务器响应: initserver server_name=MyServer server_platform=Linux ... ``` #### 通知命令 ``` 服务器主动推送: notifycliententerview cfid=1 ctid=0 reasonid=0 clid=1 client_database_id=1 ... ``` #### 列表命令 ``` 客户端请求: channellist -topic -flags -limits 服务器响应 (多行): cid=1 cpid=0 channel_name=Default\sChannel ... cid=2 cpid=1 channel_name=Sub\sChannel ... channellistfinished ``` ### 6.3 关键命令 #### 连接初始化 ```rust // 客户端初始化 clientinit { client_nickname: str, // 昵称 client_version: str, // 版本 client_platform: str, // 平台 client_input_hardware: bool, // 输入设备 client_output_hardware: bool, // 输出设备 client_default_channel: str, // 默认频道 client_default_channel_password: str, // 频道密码 client_server_password: str, // 服务器密码 client_meta_data: str, // 元数据 client_version_sign: str, // 版本签名 client_key_offset: u64, // Hash Cash 偏移 client_nickname_phonetic: str, // 语音昵称 client_default_token: str, // 权限令牌 hwid: str, // 硬件 ID } // 服务器初始化响应 initserver { server_name: str, // 服务器名称 server_platform: str, // 平台 server_version: str, // 版本 server_maxclients: u16, // 最大客户端数 // ... 更多参数 } ``` #### 频道操作 ```rust // 创建频道 channelcreate { channel_name: str, // 频道名称 channel_topic: str, // 主题 channel_codec: Codec, // 编解码器 channel_codec_quality: u8, // 质量 channel_maxclients: i32, // 最大客户端数 channel_flag_permanent: bool, // 永久频道 channel_password: str, // 密码 // ... 更多参数 } // 频道列表 channellist { cid: ChannelId, // 频道 ID cpid: ChannelId, // 父频道 ID channel_name: str, // 频道名称 channel_topic: str, // 主题 channel_codec: Codec, // 编解码器 channel_maxclients: i32, // 最大客户端数 channel_flag_permanent: bool, // 永久频道 // ... 更多参数 } ``` #### 客户端操作 ```rust // 发送消息 sendtextmessage { targetmode: TextMessageTargetMode, // 目标模式 target: ClientId, // 目标客户端 msg: str, // 消息内容 } // 客户端进入视图 notifycliententerview { cfid: ChannelId, // 来源频道 ctid: ChannelId, // 目标频道 reasonid: Reason, // 原因 clid: ClientId, // 客户端 ID client_database_id: ClientDbId, // 数据库 ID client_nickname: str, // 昵称 client_unique_identifier: Uid, // 唯一标识符 client_type: ClientType, // 客户端类型 // ... 更多参数 } ``` ## 7. 语音传输协议 ### 7.1 语音包格式 #### 客户端 → 服务器 (C2S) ``` +--+--+--+---------//---------+ | VId |C | Data | +--+--+--+---------//---------+ ``` | 字段 | 类型 | 说明 | |------|------|------| | VId | u16 | 语音包 ID | | C | u8 | 编解码器类型 | | Data | [u8] | 语音数据 | #### 服务器 → 客户端 (S2C) ``` +--+--+--+--+--+---------//---------+ | VId | CId |C | Data | +--+--+--+--+--+---------//---------+ ``` | 字段 | 类型 | 说明 | |------|------|------| | VId | u16 | 语音包 ID | | CId | u16 | 说话客户端 ID | | C | u8 | 编解码器类型 | | Data | [u8] | 语音数据 | ### 7.2 私语包格式 #### 直接目标模式 (NP=0) ``` +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+---------//---------+ | VId |C |N |M | U* | T* | Data | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+---------//---------+ ``` | 字段 | 类型 | 说明 | |------|------|------| | VId | u16 | 语音包 ID | | C | u8 | 编解码器类型 | | N | u8 | 目标频道数 | | M | u8 | 目标客户端数 | | U | [u64] | 目标频道 ID (N 个) | | T | [u16] | 目标客户端 ID (M 个) | | Data | [u8] | 语音数据 | #### 组目标模式 (NP=1) ``` +--+--+--+--+--+--+--+--+--+--+--+--+--+---------//---------+ | VId |C |TY|TA| U | Data | +--+--+--+--+--+--+--+--+--+--+--+--+--+---------//---------+ ``` | 字段 | 类型 | 说明 | |------|------|------| | VId | u16 | 语音包 ID | | C | u8 | 编解码器类型 | | TY | u8 | 组私语类型 | | TA | u8 | 组私语目标 | | U | u64 | 目标频道/组 ID | | Data | [u8] | 语音数据 | #### 组私语类型 ```rust enum GroupWhisperType : u8 { ServerGroup = 0, // 服务器组 ChannelGroup = 1, // 频道组 ChannelCommander = 2, // 频道指挥官 AllClients = 3, // 所有客户端 } enum GroupWhisperTarget : u8 { AllChannels = 0, // 所有频道 CurrentChannel = 1, // 当前频道 ParentChannel = 2, // 父频道 AllParentChannel = 3, // 所有父频道 ChannelFamily = 4, // 频道家族 CompleteChannelFamily = 5, // 完整频道家族 Subchannels = 6, // 子频道 } ``` ### 7.3 编解码器 | 编解码器 | 值 | 采样率 | 声道 | 说明 | |----------|-----|--------|------|------| | SpeexNarrowband | 0 | 8 kHz | 单声道 | 窄带语音 | | SpeexWideband | 1 | 16 kHz | 单声道 | 宽带语音 | | SpeexUltrawideband | 2 | 32 kHz | 单声道 | 超宽带语音 | | CeltMono | 3 | 48 kHz | 单声道 | CELT 编码 | | OpusVoice | 4 | 48 kHz | 单声道 | Opus 语音优化 | | OpusMusic | 5 | 48 kHz | 立体声 | Opus 音乐优化 | ### 7.4 语音流处理 ```rust struct VoiceStream { // 语音包 ID packet_id: u16, // 编解码器 codec: Codec, // 解码器 decoder: OpusDecoder, // 抖动缓冲 jitter_buffer: JitterBuffer, // 丢包隐藏 packet_loss_concealment: PlcState, } impl VoiceStream { fn process_packet(&mut self, packet: &InAudio) -> Vec { // 1. 检查丢包 let lost_packets = self.check_packet_loss(packet.id); // 2. 丢包隐藏 if lost_packets > 0 { self.conceal_packet_loss(lost_packets); } // 3. 解码音频 let samples = self.decoder.decode(&packet.data); // 4. 添加到抖动缓冲 self.jitter_buffer.push(samples); // 5. 获取输出 self.jitter_buffer.get() } } ``` ## 8. 初始化握手详解 ### 8.1 低级握手 (Init1) ``` 客户端 服务器 | | |──── Init0 (version, timestamp, A0) ────>| | | |<─── Init1 (A1, A0r) ────────────────────| | | |──── Init2 (version, A1, A0r) ──────────>| | | |<─── Init3 (x, n, level, A2) ────────────| | | |──── Init4 (version, x, n, level, A2, | | y, clientinitiv) ────────────>| | | ``` #### Init0 (客户端 → 服务器) ```rust struct Init0 { version: u32, // 客户端版本时间戳 step: u8, // 步骤号: 0x00 timestamp: u32, // 当前时间戳 random0: [u8; 4], // 随机数 A0 reserved: [u8; 8], // 保留字节 } ``` #### Init1 (服务器 → 客户端) ```rust struct Init1 { step: u8, // 步骤号: 0x01 random1: [u8; 16], // 服务器随机数 A1 random0_r: [u8; 4], // A0 反转 (通常) } ``` #### Init3 (服务器 → 客户端) ```rust struct Init3 { step: u8, // 步骤号: 0x03 x: [u8; 64], // RSA 底数 x n: [u8; 64], // RSA 模数 n level: u32, // 难度级别 random2: [u8; 100], // 服务器随机数 A2 } ``` #### Init4 (客户端 → 服务器) ```rust struct Init4 { version: u32, // 客户端版本时间戳 step: u8, // 步骤号: 0x04 x: [u8; 64], // 接收的 x n: [u8; 64], // 接收的 n level: u32, // 接收的 level random2: [u8; 100], // 接收的 A2 y: [u8; 64], // y = x^(2^level) mod n command: Command, // clientinitiv 命令 } ``` ### 8.2 高级握手 #### clientinitiv (客户端 → 服务器) ``` clientinitiv alpha={alpha} omega={omega} ot={ot} ip={ip} ``` - **alpha**: 10 随机字节的 base64 编码 - **omega**: ASN.1-DER 编码的 ECDH 公钥 - **ot**: 固定为 1 - **ip**: 服务器 IP 地址 #### 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} ``` #### clientek (客户端 → 服务器) ``` clientek ek={ek} proof={proof} ``` - **ek**: 客户端临时公钥 (base64) - **proof**: 签名的客户端公钥 + beta ### 8.3 许可证验证 (新协议) ```rust struct License { version: u8, // 版本: 0x01 blocks: Vec, // 许可证块 } struct LicenseBlock { key_type: u8, // 密钥类型: 0x00 public_key: [u8; 32], // 块公钥 block_type: LicenseBlockType, // 块类型 not_before: u32, // 有效期开始 not_after: u32, // 有效期结束 content: Vec, // 内容 } enum LicenseBlockType { Intermediate = 0x00, // 中间证书 Website = 0x01, // 网站证书 Code = 0x03, // 代码证书 Server = 0x02, // 服务器证书 TS5Server = 0x08, // TS5 服务器证书 Ephemeral = 0x32, // 临时证书 } ``` ## 9. 数据包 ID 管理 ### 9.1 数据包 ID 计数器 每种数据包类型和方向有独立的 ID 计数器: ```rust struct PacketIdManager { // 出站计数器 (客户端有 9 个) outgoing: [PartialPacketId; 9], // 入站计数器 incoming: [PartialPacketId; 9], } struct PartialPacketId { generation_id: u32, // 代 ID packet_id: u16, // 数据包 ID } ``` ### 9.2 代 ID (Generation ID) 数据包 ID 存储为 u16,范围 0-65535: - 当 ID 从 65535 溢出到 0 时,代 ID 增加 1 - 代 ID 仅用于加密参数生成 - 新的代 ID 立即应用于溢出的数据包 ### 9.3 接收窗口 ```rust struct ReceiveWindow { next_expected: u16, // 下一个期望的 ID max_queue_len: u16, // 最大队列长度 (200) queue: Vec>, // 乱序数据包队列 } impl ReceiveWindow { fn in_window(&self, id: u16) -> bool { let diff = id.wrapping_sub(self.next_expected); diff < self.max_queue_len } } ``` ## 10. 心跳机制 ### 10.1 Ping/Pong ``` 客户端 服务器 | | |──── Ping (空) ─────────────────────────>| | | |<─── Pong (PId) ─────────────────────────| | | |<─── Ping (空) ──────────────────────────| | | |──── Pong (PId) ────────────────────────>| ``` ### 10.2 心跳配置 ```rust struct HeartbeatConfig { // 客户端 Ping 间隔 client_ping_interval: Duration, // 通常 30 秒 // 服务器 Ping 间隔 server_ping_interval: Duration, // 通常 60 秒 // 超时时间 timeout: Duration, // 通常 120 秒 } ``` ## 11. 错误处理 ### 11.1 错误码 ```rust enum Ts3ErrorCode { // 成功 Ok = 0x0000, // 客户端错误 (0x0200-0x020F) ClientInvalidId = 0x0200, ClientNicknameInuse = 0x0201, ClientInvalidPassword = 0x0208, // 频道错误 (0x0300-0x030F) ChannelInvalidId = 0x0300, ChannelNameInuse = 0x0303, // 服务器错误 (0x0400-0x040D) ServerInvalidId = 0x0400, ServerMaxclientsReached = 0x0403, // 数据库错误 (0x0500-0x0505) Database = 0x0500, // 参数错误 (0x0600-0x0607) ParameterQuote = 0x0600, ParameterInvalidCount = 0x0601, // 连接错误 (0x0700-0x070C) ConnectionLost = 0x0701, NotConnected = 0x0702, } ``` ### 11.2 错误响应格式 ``` error id=0 msg=ok error id=256 msg=invalid\sclientID ``` ## 12. 性能优化 ### 12.1 密钥缓存 ```rust struct KeyCache { // 缓存每个 (类型, 方向, 代ID) 的密钥 cache: [[CachedKey; 2]; 8], } struct CachedKey { generation_id: u32, key: [u8; 16], nonce: [u8; 16], } ``` ### 12.2 数据包批处理 ```rust struct PacketBatch { // 批量发送的数据包 packets: Vec, // 批量大小 batch_size: usize, // 批量超时 batch_timeout: Duration, } ``` ### 12.3 音频优化 ```rust struct AudioOptimization { // 抖动缓冲大小 jitter_buffer_size: usize, // 丢包隐藏 packet_loss_concealment: bool, // 前向纠错 (FEC) forward_error_correction: bool, // 速度调整 speed_adjustment: bool, } ``` ## 13. 安全考虑 ### 13.1 防 DoS 攻击 RSA 拼图机制: ```rust fn solve_rsa_puzzle(x: &[u8; 64], n: &[u8; 64], level: u32) -> [u8; 64] { let x = BigUint::from_bytes_be(x); let n = BigUint::from_bytes_be(n); // y = x^(2^level) mod n let mut y = x.clone(); for _ in 0..(1 << level) { y = y.pow(2) % &n; } biguint_to_array(&y) } ``` ### 13.2 Hash Cash 防止身份伪造: ```rust fn get_hash_cash_level(omega: &str, offset: u64) -> u8 { let data = sha1(format!("{}{}", omega, offset)); let mut level = 0; for byte in data { if byte == 0 { level += 8; } else { level += byte.trailing_zeros() as u8; break; } } level } ``` ### 13.3 身份验证 ```rust fn verify_identity( public_key: &PublicKey, signature: &[u8], data: &[u8], ) -> bool { // 使用 P-256 曲线验证签名 public_key.verify(signature, data) } ``` ## 14. 协议版本兼容性 ### 14.1 版本检测 ```rust fn detect_protocol_version(server_response: &str) -> ProtocolVersion { if server_response.contains("initivexpand2") { ProtocolVersion::New // ≥3.1 } else { ProtocolVersion::Old // <3.1 } } ``` ### 14.2 兼容性处理 ```rust struct ProtocolHandler { version: ProtocolVersion, // 根据版本选择不同的处理逻辑 fn handle_init(&self, packet: &InPacket) -> Result<()> { match self.version { ProtocolVersion::Old => self.handle_init_old(packet), ProtocolVersion::New => self.handle_init_new(packet), } } } ``` ## 15. 实现参考 ### 15.1 Rust 实现 (tsproto) ```rust // 核心类型 pub struct Connection { pub is_client: bool, pub params: Option, pub address: SocketAddr, pub resender: Resender, pub codec: PacketCodec, pub udp_socket: Box, } // 加密参数 pub struct ConnectedParams { pub shared_iv: [u8; 64], pub shared_mac: [u8; 8], pub key_cache: [[CachedKey; 2]; 8], pub c_id: u16, pub voice_encryption: bool, } // 数据包编解码器 pub struct PacketCodec { pub outgoing_p_ids: [PartialPacketId; 8], pub incoming_p_ids: [PartialPacketId; 8], pub receive_queue: [Vec>; 2], pub fragmented_queue: [Option>; 2], } ``` ### 15.2 关键算法 ```rust // 压缩和分片 pub fn compress_and_split(is_client: bool, packet: OutPacket) -> Vec { // 1. 检查是否需要压缩 // 2. QuickLZ 压缩 // 3. 分片 (最大 500 字节) // 4. 设置标志位 } // 加密 pub fn encrypt( packet: &mut OutPacket, generation_id: u32, iv: &[u8; 64], cache: &mut [[CachedKey; 2]; 8], ) -> Result<()> { // 1. 生成密钥和 Nonce // 2. AES-128-EAX 加密 // 3. 生成 MAC } // 解密 pub fn decrypt( packet: &InPacket, generation_id: u32, iv: &[u8; 64], cache: &mut [[CachedKey; 2]; 8], ) -> Result> { // 1. 生成密钥和 Nonce // 2. AES-128-EAX 解密 // 3. 验证 MAC } ```