Phase 4: Critical issue analysis - SSH packet size exceeds maxpack
- Issue: SSH_FXP_DATA packet size 32786 bytes exceeds client maxpack 32768 - Root cause: handle_read() returns full requested data without maxpack limit - Severity: ⭐⭐⭐⭐⭐ Critical (blocks all large file transfers) OpenSSH reference: - sftp-server.c: process_read() limits data to maxpacket - 1024 - MarkBaseSSH: No maxpack limit currently Solution (Recommended): - Add maxpack field to SftpHandler structure - Limit handle_read() data size to maxpack - 1024 bytes - Get maxpack from Channel.remote_maxpacket Estimated work: ~50 lines, ~30 minutes testing
This commit is contained in:
154
data/phase4_packet_size_issue_analysis.md
Normal file
154
data/phase4_packet_size_issue_analysis.md
Normal file
@@ -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::<BigEndian>()?; // 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<u32, SftpHandle>,
|
||||
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<Vec<u8>> {
|
||||
let length = cursor.read_u32::<BigEndian>()?;
|
||||
|
||||
// ⭐⭐⭐⭐⭐ 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<Vec<u8>> {
|
||||
// ⭐⭐⭐⭐⭐ 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 修复
|
||||
Reference in New Issue
Block a user