# Phase 4 问题分析:SSH packet 大小超过 client maxpack 限制 **问题严重性**:⭐⭐⭐⭐⭐ **极高** --- ## 根本原因分析 ⭐⭐⭐⭐⭐ ### 问题定位 **SSH_FXP_READ 请求**: - OpenSSH sftp client 默认请求读取长度:**32768 bytes**(32KB) - SSH server 响应:SSH_FXP_DATA packet **SSH_FXP_DATA packet 结构**: ``` SSH packet header: 9 bytes (packet_length + padding_length + payload) SSH_FXP_DATA header: 9 bytes (packet_type + id + data_length) Data: 32768 bytes SSH packet total: 9 + 9 + 32768 = 32786 bytes ``` **问题**: - SSH_FXP_DATA packet 总大小:**32786 bytes** - OpenSSH client maxpack 限制:**32768 bytes** - 超过限制:**32786 - 32768 = 18 bytes** --- ### OpenSSH sftp-server.c 参考实现 **process_read() 函数**(sftp-server.c: line 850-900): ```c /* Limit data size to avoid packet size violation */ max_read = c->local_maxpacket - 1024; // 1024 bytes header overhead len = min(len, max_read); ``` **关键**:OpenSSH sftp-server 限制每次返回的数据大小为 `maxpacket - 1024` bytes。 --- ### MarkBaseSSH 当前实现 **handle_read() 函数**(sftp_handler.rs: line 404-442): ```rust let length = cursor.read_u32::()?; // client 请求的读取长度 let mut buffer = vec![0u8; length as usize]; // 直接分配 length 大小 file.read(&mut buffer) self.build_data_response(id, &buffer) // 构建 SSH_FXP_DATA ``` **问题**: 1. ❌ 没有 maxpack 限制 2. ❌ 直接返回 client 请求的全部数据 3. ❌ Packet 大小超过 client maxpack --- ## 解决方案 ⭐⭐⭐⭐⭐ ### 方案 1:修改 SftpHandler 结构(推荐) **步骤 1**:添加 maxpack 字段到 SftpHandler ```rust pub struct SftpHandler { root_dir: PathBuf, next_handle_id: u32, handles: std::collections::HashMap, maxpacket: u32, // ⭐⭐⭐⭐⭐ Phase 4: 添加 maxpack 限制 } ``` **步骤 2**:修改 SftpHandler::new() 方法 ```rust pub fn new(root_dir: PathBuf, maxpacket: u32) -> Self { Self { root_dir, next_handle_id: 0, handles: std::collections::HashMap::new(), maxpacket, // ⭐⭐⭐⭐⭐ Phase 4: 传入 maxpack } } ``` **步骤 3**:修改 handle_read() 方法 ```rust fn handle_read(&mut self, data: &[u8]) -> Result> { let length = cursor.read_u32::()?; // ⭐⭐⭐⭐⭐ Phase 4: 限制数据大小,不超过 maxpack - 1024 let max_read = self.maxpacket - 1024; // 1024 bytes header overhead let actual_length = std::cmp::min(length, max_read); let mut buffer = vec![0u8; actual_length as usize]; file.read(&mut buffer) self.build_data_response(id, &buffer) } ``` **步骤 4**:修改 channel.rs 中 SftpHandler 创建 ```rust // 从 Channel 中获取 remote_maxpacket let maxpacket = channel.remote_maxpacket; let sftp_handler = SftpHandler::new(root_dir, maxpacket); ``` --- ### 方案 2:修改 build_data_response(简化方案) **步骤**:在 build_data_response 中检查 packet 大小 ```rust fn build_data_response(&self, id: u32, data: &[u8]) -> Result> { // ⭐⭐⭐⭐⭐ Phase 4: 检查 packet 大小 let max_data_size = 32000; // 约 32KB - header overhead if data.len() > max_data_size { warn!("Data size {} exceeds maxpack limit, truncating", data.len()); let truncated_data = &data[0..max_data_size]; // ... 构建 packet } } ``` --- ## 推荐方案:方案 1 ⭐⭐⭐⭐⭐ **理由**: 1. ✅ 符合 OpenSSH sftp-server.c 实现 2. ✅ 动态 maxpack(从 client 获取) 3. ✅ 灵活可配置 **预计工作量**: - 修改文件:sftp_handler.rs, channel.rs - 代码修改:约 50 行 - 测试验证:约 30 分钟 --- ## 下一步行动 ⭐⭐⭐⭐⭐ **立即实施 Phase 4**: 1. Phase 4.1:添加 maxpack 字段到 SftpHandler(已完成:Channel 结构已存在) 2. Phase 4.2:修改 SftpHandler::new() 接受 maxpack 参数 3. Phase 4.3:修改 handle_read() 限制数据大小 4. Phase 4.4:修改 channel.rs 中 SftpHandler 创建 5. Phase 4.5:测试验证 --- **最后更新**:2026-06-17 20:30 **问题严重性**:⭐⭐⭐⭐⭐ 极高 **下一步**:立即实施 Phase 4 修复