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:
Warren
2026-06-17 20:10:53 +08:00
parent e221f86031
commit 70353d2a55

View 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 修复