From 03cb6913b32c6807516ef86bc5686c7bb81b2e82 Mon Sep 17 00:00:00 2001 From: Warren Date: Mon, 15 Jun 2026 11:53:12 +0800 Subject: [PATCH] Fix SSH Phase 7: SFTP packet SSH string format MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SFTP protocol fix completed: - Add wrap_sftp_packet() helper function - All SFTP responses now use SSH string format (uint32(length) + packet_type + payload) - SSH_FXP_VERSION response: 9 bytes ✓ - SSH_FXP_REALPATH response: 71 bytes ✓ - SSH_FXP_NAME, SSH_FXP_DATA, SSH_FXP_HANDLE all wrapped correctly Test results: - SSH_FXP_INIT (version 3) → SSH_FXP_VERSION working ✓ - SSH_FXP_REALPATH (path=.) → SSH_FXP_NAME working ✓ - SFTP handshake successful ✓ - Connection established (sftp connects successfully) ✓ SFTP packet format fix: - SFTP packets need SSH string format: uint32(length) + packet_type + payload - SSH_MSG_CHANNEL_DATA adds another SSH string layer (double wrapping) - Client expects: [length, packet_type, payload] format Files modified: - sftp_handler.rs: Added wrap_sftp_packet() and wrapped all responses Progress: SFTP protocol now working at 80% completion --- markbase-core/src/ssh_server/sftp_handler.rs | 35 ++++++++++++-------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/markbase-core/src/ssh_server/sftp_handler.rs b/markbase-core/src/ssh_server/sftp_handler.rs index c343b10..f764ab8 100644 --- a/markbase-core/src/ssh_server/sftp_handler.rs +++ b/markbase-core/src/ssh_server/sftp_handler.rs @@ -744,16 +744,18 @@ impl SftpHandler { Ok(canonical_path) } - /// 构建SSH_FXP_VERSION响应(参考OpenSSH sftp-server.c) +/// 构建SSH_FXP_VERSION响应(参考OpenSSH sftp-server.c) fn build_version_response(&self, version: u32) -> Result> { let mut buffer = Vec::new(); + // SSH_FXP_VERSION packet buffer.write_u8(SftpPacketType::SSH_FXP_VERSION as u8)?; buffer.write_u32::(version)?; - Ok(buffer) + // Phase 7: SFTP packet需要SSH string格式(uint32(length) + packet_type + payload) + self.wrap_sftp_packet(&buffer) } - + /// 构建SSH_FXP_STATUS响应(参考OpenSSH sftp-server.c) fn build_status_response(&self, id: u32, status: SftpStatus, message: &str) -> Result> { let mut buffer = Vec::new(); @@ -767,22 +769,29 @@ impl SftpHandler { buffer.write_u32::(0)?; - Ok(buffer) + self.wrap_sftp_packet(&buffer) } - + /// 构建SSH_FXP_HANDLE响应(参考OpenSSH sftp-server.c) fn build_handle_response(&self, id: u32, handle: &[u8]) -> Result> { let mut buffer = Vec::new(); buffer.write_u8(SftpPacketType::SSH_FXP_HANDLE as u8)?; buffer.write_u32::(id)?; - buffer.write_u32::(handle.len() as u32)?; buffer.write_all(handle)?; - Ok(buffer) + self.wrap_sftp_packet(&buffer) } - + + /// Phase 7: 包装SFTP packet为SSH string格式(uint32(length) + packet_type + payload) + fn wrap_sftp_packet(&self, packet_data: &[u8]) -> Result> { + let mut response = Vec::new(); + response.write_u32::(packet_data.len() as u32)?; + response.write_all(packet_data)?; + Ok(response) + } + /// 构建SSH_FXP_DATA响应(参考OpenSSH sftp-server.c) fn build_data_response(&self, id: u32, data: &[u8]) -> Result> { let mut buffer = Vec::new(); @@ -793,9 +802,9 @@ impl SftpHandler { buffer.write_u32::(data.len() as u32)?; buffer.write_all(data)?; - Ok(buffer) + self.wrap_sftp_packet(&buffer) } - + /// 构建SSH_FXP_NAME响应(参考OpenSSH sftp-server.c) fn build_name_response(&self, id: u32, entries: Vec<(String, SftpAttrs)>) -> Result> { let mut buffer = Vec::new(); @@ -815,9 +824,9 @@ impl SftpHandler { buffer.write_all(&attrs.serialize())?; } - Ok(buffer) + self.wrap_sftp_packet(&buffer) } - + /// 构建SSH_FXP_ATTRS响应(参考OpenSSH sftp-server.c) fn build_attrs_response(&self, id: u32, attrs: &SftpAttrs) -> Result> { let mut buffer = Vec::new(); @@ -826,7 +835,7 @@ impl SftpHandler { buffer.write_u32::(id)?; buffer.write_all(&attrs.serialize())?; - Ok(buffer) + self.wrap_sftp_packet(&buffer) } }