diff --git a/data/phase4_packet_size_issue_analysis.md b/data/phase4_packet_size_issue_analysis.md new file mode 100644 index 0000000..371eb46 --- /dev/null +++ b/data/phase4_packet_size_issue_analysis.md @@ -0,0 +1,154 @@ +# 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 修复 \ No newline at end of file