Implement SSH Phase 6: Channel protocol with command execution

Phase 6 completed:
- SSH_MSG_CHANNEL_OPEN handling
- SSH_MSG_CHANNEL_OPEN_CONFIRMATION/FAILURE responses
- SSH_MSG_CHANNEL_REQUEST handling (exec, env, shell, subsystem)
- SSH_MSG_CHANNEL_DATA transmission (command output)
- SSH_MSG_CHANNEL_EOF/CLOSE handling
- Command execution via shell (sh -c)
- Encrypted packet handling in service loop

Test results:
- SSH connection successful with channel creation
- Command execution working: 'echo', 'whoami', 'pwd', 'ls'
- Output correctly transmitted via CHANNEL_DATA
- EOF and CLOSE properly sent after execution
- Multiple commands working correctly

Files modified:
- channel.rs: Channel management, command execution, output buffering
- server.rs: Encrypted service loop, channel output handling

Progress: SSH implementation 95% complete (Phase 1-6)
This commit is contained in:
Warren
2026-06-15 10:36:53 +08:00
parent 2187e78398
commit e5af2537b4
2 changed files with 116 additions and 7 deletions

View File

@@ -95,7 +95,7 @@ fn handle_connection_complete(stream: TcpStream) -> Result<()> {
let mut channel_manager = ChannelManager::new();
// Phase 6-7: SSH服务循环处理channel请求
handle_ssh_service_loop(&mut stream, &mut channel_manager)?;
handle_ssh_service_loop(&mut stream, &mut channel_manager, &mut encryption_ctx)?;
info!("SSH session completed successfully");
Ok(())
@@ -278,23 +278,54 @@ AuthResult::Failure(message) => {
fn handle_ssh_service_loop(
stream: &mut TcpStream,
channel_manager: &mut ChannelManager,
encryption_ctx: &mut EncryptionContext,
) -> Result<()> {
info!("Starting SSH service loop (channel management)");
loop {
let packet = SshPacket::read(stream)?;
// 使用EncryptedPacket读取加密packetPhase 6
let encrypted_packet = EncryptedPacket::read(stream, encryption_ctx, true)?;
let packet = SshPacket::new(encrypted_packet.payload().to_vec());
match packet.payload.first() {
Some(&pt) if pt == PacketType::SSH_MSG_CHANNEL_OPEN as u8 => {
info!("Received SSH_MSG_CHANNEL_OPEN");
let response = channel_manager.handle_channel_open(&packet)?;
response.write(stream)?;
let encrypted_response = EncryptedPacket::new(&response.payload, encryption_ctx, true)?;
encrypted_response.write(stream)?;
info!("Sent SSH_MSG_CHANNEL_OPEN_CONFIRMATION");
}
Some(&pt) if pt == PacketType::SSH_MSG_CHANNEL_REQUEST as u8 => {
info!("Received SSH_MSG_CHANNEL_REQUEST");
if let Some(response) = channel_manager.handle_channel_request(&packet)? {
response.write(stream)?;
let encrypted_response = EncryptedPacket::new(&response.payload, encryption_ctx, true)?;
encrypted_response.write(stream)?;
// Phase 6: 检查是否有命令输出需要发送
if let Some(channel_id) = channel_manager.get_channel_with_output() {
if let Some(output) = channel_manager.get_channel_output(channel_id) {
// 发送命令输出SSH_MSG_CHANNEL_DATA
let data_packet = channel_manager.build_channel_data(channel_id, &output)?;
let encrypted_data = EncryptedPacket::new(&data_packet.payload, encryption_ctx, true)?;
encrypted_data.write(stream)?;
info!("Sent command output ({} bytes)", output.len());
// 发送SSH_MSG_CHANNEL_EOF
let eof_packet = channel_manager.build_channel_eof(channel_id)?;
let encrypted_eof = EncryptedPacket::new(&eof_packet.payload, encryption_ctx, true)?;
encrypted_eof.write(stream)?;
info!("Sent SSH_MSG_CHANNEL_EOF");
// 发送SSH_MSG_CHANNEL_CLOSE
let close_packet = channel_manager.build_channel_close(channel_id)?;
let encrypted_close = EncryptedPacket::new(&close_packet.payload, encryption_ctx, true)?;
encrypted_close.write(stream)?;
info!("Sent SSH_MSG_CHANNEL_CLOSE");
// 移除channel
channel_manager.remove_channel(channel_id);
}
}
}
}
Some(&pt) if pt == PacketType::SSH_MSG_CHANNEL_DATA as u8 => {
@@ -303,7 +334,10 @@ fn handle_ssh_service_loop(
}
Some(&pt) if pt == PacketType::SSH_MSG_CHANNEL_CLOSE as u8 => {
info!("Received SSH_MSG_CHANNEL_CLOSE");
channel_manager.handle_channel_close(&packet)?;
if let Some(response) = channel_manager.handle_channel_close(&packet)? {
let encrypted_response = EncryptedPacket::new(&response.payload, encryption_ctx, true)?;
encrypted_response.write(stream)?;
}
break;
}
Some(&pt) if pt == PacketType::SSH_MSG_DISCONNECT as u8 => {