- Modify Channel struct to add direct_tcpip and forwarded_tcpip fields - Modify handle_channel_open to support 'direct-tcpip' and 'forwarded-tcpip' channel types - Add handle_session_channel_open() function (Phase 6) - Add handle_direct_tcpip_channel_open() function (Phase 13.3: Remote port forwarding) - Add handle_forwarded_tcpip_channel_open() function (Phase 13.3: Local port forwarding) - Integrate security validation in direct-tcpip channel open - Modify server.rs to pass security_config to handle_channel_open - Add 128 lines of new channel handling functions - All compilation tests passed successfully Phase 13.1-13.3 completed: Enterprise security + Global request + Channel support
680 lines
26 KiB
Rust
680 lines
26 KiB
Rust
// SSH Channel协议实现(Phase 6 + Phase 13端口转发)
|
||
// 参考OpenSSH channel.c
|
||
|
||
use crate::ssh_server::packet::{SshPacket, PacketType};
|
||
use crate::ssh_server::ssh_security_config::SshSecurityConfig; // Phase 13.3: 安全配置
|
||
use crate::ssh_server::port_forward::{PortForwardManager, DirectTcpipChannel, ForwardedTcpipChannel}; // Phase 13.3
|
||
use std::io::{Read, Write}; // 导入Write trait(OpenSSH标准)
|
||
use anyhow::{Result, anyhow};
|
||
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
|
||
use log::{info, warn, debug};
|
||
use std::collections::HashMap;
|
||
use std::sync::{Arc, Mutex};
|
||
use crate::ssh_server::sftp_handler::SftpHandler; // Phase 7: SFTP handler
|
||
use crate::ssh_server::scp_handler::ScpHandler; // Phase 8: SCP handler
|
||
use crate::ssh_server::rsync_handler::RsyncHandler; // Phase 8: rsync handler
|
||
use std::path::PathBuf; // Phase 7-8: Path for SFTP/SCP/rsync root directory
|
||
|
||
/// SSH Channel管理器(参考OpenSSH channel.c: struct channel)
|
||
pub struct ChannelManager {
|
||
channels: HashMap<u32, Channel>,
|
||
next_channel_id: u32,
|
||
}
|
||
|
||
impl ChannelManager {
|
||
pub fn new() -> Self {
|
||
Self {
|
||
channels: HashMap::new(),
|
||
next_channel_id: 0,
|
||
}
|
||
}
|
||
|
||
/// 处理SSH_MSG_CHANNEL_OPEN(参考OpenSSH channel.c: channel_open())
|
||
/// Phase 13.3: 支持direct-tcpip和forwarded-tcpip channel
|
||
pub fn handle_channel_open(&mut self, packet: &SshPacket, security_config: Option<&SshSecurityConfig>) -> Result<SshPacket> {
|
||
info!("Processing SSH_MSG_CHANNEL_OPEN");
|
||
|
||
let mut cursor = std::io::Cursor::new(packet.payload.as_slice());
|
||
|
||
// Packet type
|
||
let packet_type = cursor.read_u8()?;
|
||
if packet_type != PacketType::SSH_MSG_CHANNEL_OPEN as u8 {
|
||
return Err(anyhow!("Invalid packet type for CHANNEL_OPEN"));
|
||
}
|
||
|
||
// 读取channel类型(SSH string)
|
||
let channel_type = read_ssh_string(&mut cursor)?;
|
||
|
||
// 读取sender channel ID(u32)
|
||
let sender_channel = cursor.read_u32::<BigEndian>()?;
|
||
|
||
// 读取初始窗口大小(u32)
|
||
let initial_window_size = cursor.read_u32::<BigEndian>()?;
|
||
|
||
// 读取最大packet大小(u32)
|
||
let maximum_packet_size = cursor.read_u32::<BigEndian>()?;
|
||
|
||
info!("Channel open: type={}, sender_channel={}, window={}, max_packet={}",
|
||
channel_type, sender_channel, initial_window_size, maximum_packet_size);
|
||
|
||
// Phase 13.3: 检查channel类型(支持session、direct-tcpip、forwarded-tcpip)
|
||
match channel_type.as_str() {
|
||
"session" => {
|
||
// 传统的session channel(Phase 6)
|
||
self.handle_session_channel_open(sender_channel, initial_window_size, maximum_packet_size)
|
||
}
|
||
|
||
"direct-tcpip" => {
|
||
// Phase 13.3: Remote port forwarding channel
|
||
info!("Received direct-tcpip channel open (Remote port forwarding)");
|
||
self.handle_direct_tcpip_channel_open(packet, sender_channel, initial_window_size, maximum_packet_size, security_config)
|
||
}
|
||
|
||
"forwarded-tcpip" => {
|
||
// Phase 13.3: Local port forwarding channel
|
||
info!("Received forwarded-tcpip channel open (Local port forwarding)");
|
||
self.handle_forwarded_tcpip_channel_open(packet, sender_channel, initial_window_size, maximum_packet_size)
|
||
}
|
||
|
||
_ => {
|
||
warn!("Unsupported channel type: {}", channel_type);
|
||
self.build_channel_open_failure(
|
||
sender_channel,
|
||
3, // SSH_OPEN_UNKNOWN_CHANNEL_TYPE
|
||
"Unsupported channel type",
|
||
"en"
|
||
)
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
/// 处理session channel open(Phase 6)
|
||
fn handle_session_channel_open(&mut self, sender_channel: u32, initial_window_size: u32, maximum_packet_size: u32) -> Result<SshPacket> {
|
||
info!("Processing session channel open");
|
||
|
||
let server_channel = self.next_channel_id;
|
||
self.next_channel_id += 1;
|
||
|
||
let channel = Channel {
|
||
server_channel,
|
||
sender_channel,
|
||
channel_type: "session".to_string(),
|
||
window_size: initial_window_size,
|
||
maximum_packet_size,
|
||
state: ChannelState::Open,
|
||
output_buffer: None,
|
||
sftp_handler: None,
|
||
scp_handler: None,
|
||
rsync_handler: None,
|
||
direct_tcpip: None,
|
||
forwarded_tcpip: None,
|
||
};
|
||
|
||
self.channels.insert(server_channel, channel);
|
||
|
||
info!("Session channel created: server_channel={}, sender_channel={}", server_channel, sender_channel);
|
||
|
||
self.build_channel_open_confirmation(server_channel, sender_channel, initial_window_size, maximum_packet_size)
|
||
}
|
||
|
||
/// 处理direct-tcpip channel open(Phase 13.3: Remote port forwarding)
|
||
fn handle_direct_tcpip_channel_open(
|
||
&mut self,
|
||
packet: &SshPacket,
|
||
sender_channel: u32,
|
||
initial_window_size: u32,
|
||
maximum_packet_size: u32,
|
||
security_config: Option<&SshSecurityConfig>,
|
||
) -> Result<SshPacket> {
|
||
info!("Processing direct-tcpip channel open");
|
||
|
||
// 解析direct-tcpip参数
|
||
let mut port_forward_manager = PortForwardManager::new();
|
||
let direct_tcpip = port_forward_manager.handle_direct_tcpip_channel(&packet.payload)?;
|
||
|
||
// Phase 13.3: 安全配置验证
|
||
if let Some(security) = security_config {
|
||
if let Err(e) = security.validate_direct_tcpip_channel(&direct_tcpip.host_to_connect, direct_tcpip.port_to_connect) {
|
||
warn!("direct-tcpip security validation failed: {}", e);
|
||
return self.build_channel_open_failure(
|
||
sender_channel,
|
||
2, // SSH_OPEN_CONNECT_FAILED
|
||
"Security validation failed",
|
||
"en"
|
||
);
|
||
}
|
||
info!("direct-tcpip security validation passed");
|
||
}
|
||
|
||
let server_channel = self.next_channel_id;
|
||
self.next_channel_id += 1;
|
||
|
||
let channel = Channel {
|
||
server_channel,
|
||
sender_channel,
|
||
channel_type: "direct-tcpip".to_string(),
|
||
window_size: initial_window_size,
|
||
maximum_packet_size,
|
||
state: ChannelState::Open,
|
||
output_buffer: None,
|
||
sftp_handler: None,
|
||
scp_handler: None,
|
||
rsync_handler: None,
|
||
direct_tcpip: Some(direct_tcpip),
|
||
forwarded_tcpip: None,
|
||
};
|
||
|
||
self.channels.insert(server_channel, channel);
|
||
|
||
info!("direct-tcpip channel created: server_channel={}, host={}, port={}",
|
||
server_channel,
|
||
self.channels.get(&server_channel).unwrap().direct_tcpip.as_ref().unwrap().host_to_connect,
|
||
self.channels.get(&server_channel).unwrap().direct_tcpip.as_ref().unwrap().port_to_connect);
|
||
|
||
self.build_channel_open_confirmation(server_channel, sender_channel, initial_window_size, maximum_packet_size)
|
||
}
|
||
|
||
/// 处理forwarded-tcpip channel open(Phase 13.3: Local port forwarding)
|
||
fn handle_forwarded_tcpip_channel_open(
|
||
&mut self,
|
||
packet: &SshPacket,
|
||
sender_channel: u32,
|
||
initial_window_size: u32,
|
||
maximum_packet_size: u32,
|
||
) -> Result<SshPacket> {
|
||
info!("Processing forwarded-tcpip channel open");
|
||
|
||
// 解析forwarded-tcpip参数
|
||
let mut port_forward_manager = PortForwardManager::new();
|
||
let forwarded_tcpip = port_forward_manager.handle_forwarded_tcpip_channel(&packet.payload)?;
|
||
|
||
let server_channel = self.next_channel_id;
|
||
self.next_channel_id += 1;
|
||
|
||
let channel = Channel {
|
||
server_channel,
|
||
sender_channel,
|
||
channel_type: "forwarded-tcpip".to_string(),
|
||
window_size: initial_window_size,
|
||
maximum_packet_size,
|
||
state: ChannelState::Open,
|
||
output_buffer: None,
|
||
sftp_handler: None,
|
||
scp_handler: None,
|
||
rsync_handler: None,
|
||
direct_tcpip: None,
|
||
forwarded_tcpip: Some(forwarded_tcpip),
|
||
};
|
||
|
||
self.channels.insert(server_channel, channel);
|
||
|
||
info!("forwarded-tcpip channel created: server_channel={}, bind={}, originator={}",
|
||
server_channel,
|
||
self.channels.get(&server_channel).unwrap().forwarded_tcpip.as_ref().unwrap().bind_port,
|
||
self.channels.get(&server_channel).unwrap().forwarded_tcpip.as_ref().unwrap().originator_address);
|
||
|
||
self.build_channel_open_confirmation(server_channel, sender_channel, initial_window_size, maximum_packet_size)
|
||
}
|
||
/// 处理SSH_MSG_CHANNEL_REQUEST(参考OpenSSH channel.c: channel_request())
|
||
pub fn handle_channel_request(&mut self, packet: &SshPacket) -> Result<Option<SshPacket>> {
|
||
info!("Processing SSH_MSG_CHANNEL_REQUEST");
|
||
|
||
let mut cursor = std::io::Cursor::new(packet.payload.as_slice()); // 使用as_slice()(Rust标准)
|
||
|
||
// Packet type
|
||
let packet_type = cursor.read_u8()?;
|
||
if packet_type != PacketType::SSH_MSG_CHANNEL_REQUEST as u8 {
|
||
return Err(anyhow!("Invalid packet type for CHANNEL_REQUEST"));
|
||
}
|
||
|
||
// 读取recipient channel(u32)
|
||
let recipient_channel = cursor.read_u32::<BigEndian>()?;
|
||
|
||
// 读取请求类型(SSH string)
|
||
let request_type = read_ssh_string(&mut cursor)?;
|
||
|
||
// 读取want reply标志(boolean)
|
||
let want_reply = cursor.read_u8()? != 0;
|
||
|
||
info!("Channel request: channel={}, type={}, want_reply={}",
|
||
recipient_channel, request_type, want_reply);
|
||
|
||
// 处理不同请求类型(参考OpenSSH channel.c)
|
||
if request_type == "exec" {
|
||
self.handle_exec_request(&mut cursor, recipient_channel, want_reply) // 移除?操作符(返回Option不是Result)
|
||
} else if request_type == "subsystem" {
|
||
self.handle_subsystem_request(&mut cursor, recipient_channel, want_reply) // 移除?操作符
|
||
} else if request_type == "shell" {
|
||
self.handle_shell_request(recipient_channel, want_reply) // 移除?操作符
|
||
} else if request_type == "env" {
|
||
self.handle_env_request(&mut cursor, recipient_channel, want_reply) // 移除?操作符
|
||
} else if request_type == "pty-req" {
|
||
self.handle_pty_request(&mut cursor, recipient_channel, want_reply) // 移除?操作符
|
||
} else {
|
||
warn!("Unsupported channel request: {}", request_type);
|
||
if want_reply {
|
||
Ok(Some(self.build_channel_failure(recipient_channel)?))
|
||
} else {
|
||
Ok(None)
|
||
}
|
||
}
|
||
}
|
||
|
||
/// 处理exec请求(参考OpenSSH channel.c: channel_request_exec())
|
||
fn handle_exec_request(&mut self, cursor: &mut std::io::Cursor<&[u8]>, channel: u32, want_reply: bool) -> Result<Option<SshPacket>> {
|
||
info!("Handling exec request for channel {}", channel);
|
||
|
||
// 读取命令(SSH string)
|
||
let command = read_ssh_string(cursor)?;
|
||
|
||
info!("Exec command: {}", command);
|
||
|
||
// Phase 8: SCP/rsync命令直接执行(使用系统命令)
|
||
// 不需要自己实现SCP协议,让系统的scp/rsync命令处理
|
||
let output = self.execute_command(&command)?;
|
||
|
||
// 存储输出,等待后续发送CHANNEL_DATA
|
||
if let Some(ch) = self.channels.get_mut(&channel) {
|
||
ch.output_buffer = Some(output);
|
||
}
|
||
|
||
if want_reply {
|
||
Ok(Some(self.build_channel_success(channel)?))
|
||
} else {
|
||
Ok(None)
|
||
}
|
||
}
|
||
|
||
/// 执行命令并捕获输出(Phase 6基础实现)
|
||
fn execute_command(&self, command: &str) -> Result<Vec<u8>> {
|
||
use std::process::{Command, Stdio};
|
||
|
||
info!("Executing command: {}", command);
|
||
|
||
// 使用shell执行命令(参考OpenSSH session.c)
|
||
let output = Command::new("sh")
|
||
.arg("-c")
|
||
.arg(command)
|
||
.output()?;
|
||
|
||
// 返回stdout + stderr
|
||
let mut result = output.stdout;
|
||
result.extend_from_slice(&output.stderr);
|
||
|
||
info!("Command output: {} bytes", result.len());
|
||
Ok(result)
|
||
}
|
||
|
||
/// 处理subsystem请求(参考OpenSSH channel.c: channel_request_subsystem())
|
||
fn handle_subsystem_request(&mut self, cursor: &mut std::io::Cursor<&[u8]>, channel: u32, want_reply: bool) -> Result<Option<SshPacket>> {
|
||
info!("Handling subsystem request for channel {}", channel);
|
||
|
||
// 读取subsystem名称(SSH string)
|
||
let subsystem = read_ssh_string(cursor)?;
|
||
|
||
info!("Subsystem: {}", subsystem);
|
||
|
||
// 检查subsystem支持(OpenSSH支持:sftp)
|
||
if subsystem == "sftp" {
|
||
info!("SFTP subsystem requested");
|
||
|
||
// Phase 7: 初始化SFTP handler
|
||
let root_dir = PathBuf::from("/Users/accusys/markbase"); // 默认root目录
|
||
let sftp_handler = SftpHandler::new(root_dir);
|
||
|
||
// 存储到channel
|
||
if let Some(ch) = self.channels.get_mut(&channel) {
|
||
ch.sftp_handler = Some(sftp_handler);
|
||
info!("SFTP handler initialized for channel {}", channel);
|
||
}
|
||
|
||
if want_reply {
|
||
Ok(Some(self.build_channel_success(channel)?))
|
||
} else {
|
||
Ok(None)
|
||
}
|
||
} else {
|
||
warn!("Unsupported subsystem: {}", subsystem);
|
||
if want_reply {
|
||
Ok(Some(self.build_channel_failure(channel)?))
|
||
} else {
|
||
Ok(None)
|
||
}
|
||
}
|
||
}
|
||
|
||
/// 处理shell请求(参考OpenSSH channel.c)
|
||
fn handle_shell_request(&mut self, channel: u32, want_reply: bool) -> Result<Option<SshPacket>> {
|
||
info!("Handling shell request for channel {}", channel);
|
||
|
||
// Phase 9将实现shell
|
||
warn!("Shell not implemented in Phase 6");
|
||
|
||
if want_reply {
|
||
Ok(Some(self.build_channel_failure(channel)?))
|
||
} else {
|
||
Ok(None)
|
||
}
|
||
}
|
||
|
||
/// 处理env请求(参考OpenSSH channel.c)
|
||
fn handle_env_request(&mut self, cursor: &mut std::io::Cursor<&[u8]>, channel: u32, want_reply: bool) -> Result<Option<SshPacket>> {
|
||
info!("Handling env request for channel {}", channel);
|
||
|
||
// 读取环境变量名和值
|
||
let name = read_ssh_string(cursor)?;
|
||
let value = read_ssh_string(cursor)?;
|
||
|
||
info!("Env: {}={}", name, value);
|
||
|
||
if want_reply {
|
||
Ok(Some(self.build_channel_success(channel)?))
|
||
} else {
|
||
Ok(None)
|
||
}
|
||
}
|
||
|
||
/// 处理pty请求(参考OpenSSH channel.c)
|
||
fn handle_pty_request(&mut self, cursor: &mut std::io::Cursor<&[u8]>, channel: u32, want_reply: bool) -> Result<Option<SshPacket>> {
|
||
info!("Handling pty request for channel {}", channel);
|
||
|
||
// 读取terminal类型(SSH string)
|
||
let term = read_ssh_string(cursor)?;
|
||
|
||
// 读取窗口大小(4个uint32)
|
||
let width = cursor.read_u32::<BigEndian>()?;
|
||
let height = cursor.read_u32::<BigEndian>()?;
|
||
let _pixel_width = cursor.read_u32::<BigEndian>()?;
|
||
let _pixel_height = cursor.read_u32::<BigEndian>()?;
|
||
|
||
// 读取terminal modes(SSH string格式)
|
||
let modes_len = cursor.read_u32::<BigEndian>()?;
|
||
let mut modes = vec![0u8; modes_len as usize];
|
||
cursor.read_exact(&mut modes)?;
|
||
|
||
info!("PTY: term={}, width={}, height={}, modes_len={}", term, width, height, modes_len);
|
||
|
||
if want_reply {
|
||
Ok(Some(self.build_channel_success(channel)?))
|
||
} else {
|
||
Ok(None)
|
||
}
|
||
}
|
||
|
||
/// 处理SSH_MSG_CHANNEL_DATA(参考OpenSSH channel.c: channel_input_data())
|
||
pub fn handle_channel_data(&mut self, packet: &SshPacket) -> Result<Option<SshPacket>> {
|
||
info!("Processing SSH_MSG_CHANNEL_DATA");
|
||
|
||
let mut cursor = std::io::Cursor::new(packet.payload.as_slice());
|
||
|
||
// Packet type
|
||
let packet_type = cursor.read_u8()?;
|
||
if packet_type != PacketType::SSH_MSG_CHANNEL_DATA as u8 {
|
||
return Err(anyhow!("Invalid packet type for CHANNEL_DATA"));
|
||
}
|
||
|
||
// 读取recipient channel
|
||
let recipient_channel = cursor.read_u32::<BigEndian>()?;
|
||
|
||
// 读取数据(SSH string)
|
||
let data_length = cursor.read_u32::<BigEndian>()?;
|
||
let mut data = vec![0u8; data_length as usize];
|
||
cursor.read_exact(&mut data)?;
|
||
|
||
info!("Channel data: channel={}, length={}", recipient_channel, data.len());
|
||
info!("Channel data content (first 20 bytes): {:?}", &data[..std::cmp::min(20, data.len())]);
|
||
|
||
// Phase 7: 检查是否是SFTP channel
|
||
if let Some(channel) = self.channels.get_mut(&recipient_channel) {
|
||
if let Some(sftp_handler) = &mut channel.sftp_handler {
|
||
info!("Processing SFTP request ({} bytes)", data.len());
|
||
|
||
// SFTP data是SSH string格式:前4 bytes是length field
|
||
// 真正的SFTP packet从data[4]开始(跳过length field)
|
||
if data.len() < 4 {
|
||
warn!("SFTP data too short (less than 4 bytes)");
|
||
return Ok(None);
|
||
}
|
||
|
||
let sftp_packet_length = u32::from_be_bytes([data[0], data[1], data[2], data[3]]) as usize;
|
||
let sftp_packet = &data[4..4 + sftp_packet_length];
|
||
|
||
info!("SFTP packet: length={}, content={:?}", sftp_packet_length, &sftp_packet[..std::cmp::min(20, sftp_packet.len())]);
|
||
|
||
// 处理SFTP请求
|
||
let response = sftp_handler.handle_request(sftp_packet)?;
|
||
info!("SFTP response: {} bytes", response.len());
|
||
|
||
// 构建SSH_MSG_CHANNEL_DATA返回SFTP响应(需要SSH string格式)
|
||
return Ok(Some(self.build_channel_data(recipient_channel, &response)?));
|
||
}
|
||
}
|
||
|
||
// 如果不是SFTP,返回None(Phase 6的普通channel data处理)
|
||
Ok(None)
|
||
}
|
||
|
||
/// 处理SSH_MSG_CHANNEL_CLOSE(参考OpenSSH channel.c: channel_input_close())
|
||
pub fn handle_channel_close(&mut self, packet: &SshPacket) -> Result<Option<SshPacket>> {
|
||
info!("Processing SSH_MSG_CHANNEL_CLOSE");
|
||
|
||
let mut cursor = std::io::Cursor::new(packet.payload.as_slice()); // 使用as_slice()(Rust标准)
|
||
|
||
// Packet type
|
||
let packet_type = cursor.read_u8()?;
|
||
if packet_type != PacketType::SSH_MSG_CHANNEL_CLOSE as u8 {
|
||
return Err(anyhow!("Invalid packet type for CHANNEL_CLOSE"));
|
||
}
|
||
|
||
// 读取recipient channel
|
||
let recipient_channel = cursor.read_u32::<BigEndian>()?;
|
||
|
||
info!("Channel close: channel={}", recipient_channel);
|
||
|
||
// 移除channel(参考OpenSSH channel.c)
|
||
if let Some(channel) = self.channels.remove(&recipient_channel) {
|
||
info!("Channel {} removed", recipient_channel);
|
||
|
||
// 发送SSH_MSG_CHANNEL_CLOSE回应
|
||
Ok(Some(self.build_channel_close(channel.sender_channel)?))
|
||
} else {
|
||
warn!("Channel {} not found", recipient_channel);
|
||
Ok(None)
|
||
}
|
||
}
|
||
|
||
/// 构建SSH_MSG_CHANNEL_OPEN_CONFIRMATION(参考OpenSSH channel.c)
|
||
fn build_channel_open_confirmation(
|
||
&self,
|
||
server_channel: u32,
|
||
sender_channel: u32,
|
||
window_size: u32,
|
||
packet_size: u32,
|
||
) -> Result<SshPacket> {
|
||
let mut payload = Vec::new();
|
||
|
||
// Packet type
|
||
payload.write_u8(PacketType::SSH_MSG_CHANNEL_OPEN_CONFIRMATION as u8)?;
|
||
|
||
// Server channel number
|
||
payload.write_u32::<BigEndian>(server_channel)?;
|
||
|
||
// Sender channel number
|
||
payload.write_u32::<BigEndian>(sender_channel)?;
|
||
|
||
// Initial window size
|
||
payload.write_u32::<BigEndian>(window_size)?;
|
||
|
||
// Maximum packet size
|
||
payload.write_u32::<BigEndian>(packet_size)?;
|
||
|
||
Ok(SshPacket::new(payload))
|
||
}
|
||
|
||
/// 构建SSH_MSG_CHANNEL_OPEN_FAILURE(参考OpenSSH channel.c)
|
||
fn build_channel_open_failure(
|
||
&self,
|
||
sender_channel: u32,
|
||
reason_code: u32,
|
||
description: &str,
|
||
language: &str,
|
||
) -> Result<SshPacket> {
|
||
let mut payload = Vec::new();
|
||
|
||
// Packet type
|
||
payload.write_u8(PacketType::SSH_MSG_CHANNEL_OPEN_FAILURE as u8)?;
|
||
|
||
// Sender channel number
|
||
payload.write_u32::<BigEndian>(sender_channel)?;
|
||
|
||
// Reason code
|
||
payload.write_u32::<BigEndian>(reason_code)?;
|
||
|
||
// Description(SSH string)
|
||
payload.write_u32::<BigEndian>(description.len() as u32)?;
|
||
payload.write_all(description.as_bytes())?;
|
||
|
||
// Language(SSH string)
|
||
payload.write_u32::<BigEndian>(language.len() as u32)?;
|
||
payload.write_all(language.as_bytes())?;
|
||
|
||
Ok(SshPacket::new(payload))
|
||
}
|
||
|
||
/// 构建SSH_MSG_CHANNEL_SUCCESS(参考OpenSSH channel.c)
|
||
fn build_channel_success(&self, channel: u32) -> Result<SshPacket> {
|
||
let mut payload = Vec::new();
|
||
|
||
payload.write_u8(PacketType::SSH_MSG_CHANNEL_SUCCESS as u8)?;
|
||
payload.write_u32::<BigEndian>(channel)?;
|
||
|
||
Ok(SshPacket::new(payload))
|
||
}
|
||
|
||
/// 构建SSH_MSG_CHANNEL_FAILURE(参考OpenSSH channel.c)
|
||
fn build_channel_failure(&self, channel: u32) -> Result<SshPacket> {
|
||
let mut payload = Vec::new();
|
||
|
||
payload.write_u8(PacketType::SSH_MSG_CHANNEL_FAILURE as u8)?;
|
||
payload.write_u32::<BigEndian>(channel)?;
|
||
|
||
Ok(SshPacket::new(payload))
|
||
}
|
||
|
||
/// 构建SSH_MSG_CHANNEL_CLOSE(参考OpenSSH channel.c)
|
||
pub fn build_channel_close(&self, channel: u32) -> Result<SshPacket> {
|
||
let mut payload = Vec::new();
|
||
|
||
payload.write_u8(PacketType::SSH_MSG_CHANNEL_CLOSE as u8)?;
|
||
payload.write_u32::<BigEndian>(channel)?;
|
||
|
||
Ok(SshPacket::new(payload))
|
||
}
|
||
|
||
/// 构建SSH_MSG_CHANNEL_DATA(Phase 6新增)
|
||
pub fn build_channel_data(&self, channel: u32, data: &[u8]) -> Result<SshPacket> {
|
||
let mut payload = Vec::new();
|
||
|
||
payload.write_u8(PacketType::SSH_MSG_CHANNEL_DATA as u8)?;
|
||
payload.write_u32::<BigEndian>(channel)?;
|
||
payload.write_u32::<BigEndian>(data.len() as u32)?;
|
||
payload.write_all(data)?;
|
||
|
||
Ok(SshPacket::new(payload))
|
||
}
|
||
|
||
/// 构建SSH_MSG_CHANNEL_EOF(Phase 6新增)
|
||
pub fn build_channel_eof(&self, channel: u32) -> Result<SshPacket> {
|
||
let mut payload = Vec::new();
|
||
|
||
payload.write_u8(PacketType::SSH_MSG_CHANNEL_EOF as u8)?;
|
||
payload.write_u32::<BigEndian>(channel)?;
|
||
|
||
Ok(SshPacket::new(payload))
|
||
}
|
||
|
||
/// 获取有输出待发送的channel ID(Phase 6新增)
|
||
pub fn get_channel_with_output(&self) -> Option<u32> {
|
||
for (&id, channel) in &self.channels {
|
||
if channel.output_buffer.is_some() {
|
||
return Some(id);
|
||
}
|
||
}
|
||
None
|
||
}
|
||
|
||
/// 获取channel输出(Phase 6新增)
|
||
pub fn get_channel_output(&mut self, channel_id: u32) -> Option<Vec<u8>> {
|
||
if let Some(channel) = self.channels.get_mut(&channel_id) {
|
||
channel.output_buffer.take()
|
||
} else {
|
||
None
|
||
}
|
||
}
|
||
|
||
/// 移除channel(Phase 6新增)
|
||
pub fn remove_channel(&mut self, channel_id: u32) {
|
||
self.channels.remove(&channel_id);
|
||
}
|
||
}
|
||
|
||
/// SSH Channel结构(参考OpenSSH channel.c: struct channel)
|
||
struct Channel {
|
||
server_channel: u32,
|
||
sender_channel: u32,
|
||
channel_type: String,
|
||
window_size: u32,
|
||
maximum_packet_size: u32,
|
||
state: ChannelState,
|
||
output_buffer: Option<Vec<u8>>, // Phase 6: 命令输出缓冲
|
||
sftp_handler: Option<SftpHandler>, // Phase 7: SFTP处理器
|
||
scp_handler: Option<ScpHandler>, // Phase 8: SCP处理器
|
||
rsync_handler: Option<RsyncHandler>, // Phase 8: rsync处理器
|
||
// Phase 13.3: 端口转发相关字段
|
||
direct_tcpip: Option<DirectTcpipChannel>, // direct-tcpip channel(Remote forwarding)
|
||
forwarded_tcpip: Option<ForwardedTcpipChannel>, // forwarded-tcpip channel(Local forwarding)
|
||
}
|
||
|
||
/// SSH Channel状态(参考OpenSSH channel.c)
|
||
enum ChannelState {
|
||
Open,
|
||
Closing,
|
||
Closed,
|
||
}
|
||
|
||
/// SSH string读取辅助函数
|
||
fn read_ssh_string<R: std::io::Read>(reader: &mut R) -> Result<String> {
|
||
let length = reader.read_u32::<BigEndian>()?;
|
||
let mut buffer = vec![0u8; length as usize];
|
||
reader.read_exact(&mut buffer)?;
|
||
Ok(String::from_utf8(buffer)?)
|
||
}
|
||
|
||
#[cfg(test)]
|
||
mod tests {
|
||
use super::*;
|
||
|
||
#[test]
|
||
fn test_channel_manager_creation() {
|
||
let manager = ChannelManager::new();
|
||
assert_eq!(manager.next_channel_id, 0);
|
||
}
|
||
|
||
#[test]
|
||
fn test_channel_open_confirmation() {
|
||
let manager = ChannelManager::new();
|
||
let packet = manager.build_channel_open_confirmation(0, 100, 2097152, 32768).unwrap();
|
||
|
||
assert_eq!(packet.payload[0], PacketType::SSH_MSG_CHANNEL_OPEN_CONFIRMATION as u8);
|
||
}
|
||
|
||
#[test]
|
||
fn test_channel_success() {
|
||
let manager = ChannelManager::new();
|
||
let packet = manager.build_channel_success(0).unwrap();
|
||
|
||
assert_eq!(packet.payload[0], PacketType::SSH_MSG_CHANNEL_SUCCESS as u8);
|
||
}
|
||
}
|