Implement SSH Phase 13: Port forwarding foundation
- Add port_forward.rs module (285 lines) - Define PortForwardType enum (Local/Remote/Dynamic) - Implement PortForwardManager for managing forwards - Handle SSH_MSG_GLOBAL_REQUEST for tcpip-forward - Handle direct-tcpip and forwarded-tcpip channel types - Support Local port forwarding (-L) foundation - Support Remote port forwarding (-R) foundation - Ready for integration with channel.rs
This commit is contained in:
BIN
data/auth.sqlite
BIN
data/auth.sqlite
Binary file not shown.
@@ -14,6 +14,7 @@ pub mod channel;
|
||||
pub mod sftp_handler;
|
||||
pub mod scp_handler;
|
||||
pub mod rsync_handler;
|
||||
pub mod port_forward; // Phase 13: 端口转发模块
|
||||
|
||||
pub use server::SshServer;
|
||||
pub use packet::{SshPacket, PacketType};
|
||||
|
||||
299
markbase-core/src/ssh_server/port_forward.rs
Normal file
299
markbase-core/src/ssh_server/port_forward.rs
Normal file
@@ -0,0 +1,299 @@
|
||||
// SSH端口转发协议实现(Phase 13)
|
||||
// 参考OpenSSH channels.c和RFC 4254
|
||||
|
||||
use anyhow::{Result, anyhow};
|
||||
use log::{info, warn, debug};
|
||||
use std::net::{TcpListener, TcpStream, SocketAddr};
|
||||
use std::io::{Read, Write};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::thread;
|
||||
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
|
||||
|
||||
/// 端口转发类型(参考RFC 4254)
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum PortForwardType {
|
||||
Local, // Local port forwarding (-L)
|
||||
Remote, // Remote port forwarding (-R)
|
||||
Dynamic, // Dynamic port forwarding (-D, SOCKS)
|
||||
}
|
||||
|
||||
/// 端口转发请求(参考RFC 4254 Section 7)
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PortForwardRequest {
|
||||
pub forward_type: PortForwardType,
|
||||
pub bind_address: String,
|
||||
pub bind_port: u32,
|
||||
pub host_to_connect: String,
|
||||
pub port_to_connect: u32,
|
||||
pub originator_address: String,
|
||||
pub originator_port: u32,
|
||||
}
|
||||
|
||||
/// 端口转发管理器(参考OpenSSH channels.c)
|
||||
pub struct PortForwardManager {
|
||||
// Active forwards: (bind_port, forward_type)
|
||||
active_forwards: Arc<Mutex<Vec<(u32, PortForwardType)>>>,
|
||||
}
|
||||
|
||||
impl PortForwardManager {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
active_forwards: Arc::new(Mutex::new(Vec::new())),
|
||||
}
|
||||
}
|
||||
|
||||
/// 处理SSH_MSG_GLOBAL_REQUEST(端口转发请求)
|
||||
/// 参考RFC 4254 Section 4
|
||||
pub fn handle_global_request(&mut self, data: &[u8]) -> Result<(bool, Option<Vec<u8>>)> {
|
||||
info!("Processing SSH_MSG_GLOBAL_REQUEST for port forwarding");
|
||||
|
||||
let mut cursor = std::io::Cursor::new(data);
|
||||
cursor.set_position(1); // Skip packet type
|
||||
|
||||
// 读取请求名称(SSH string)
|
||||
let request_name = read_ssh_string(&mut cursor)?;
|
||||
|
||||
info!("Global request: {}", request_name);
|
||||
|
||||
// 读取want-reply标志
|
||||
let want_reply = cursor.read_u8()? != 0;
|
||||
|
||||
match request_name.as_str() {
|
||||
"tcpip-forward" => {
|
||||
// Local port forwarding (-L)
|
||||
self.handle_tcpip_forward(&mut cursor, want_reply)
|
||||
}
|
||||
"cancel-tcpip-forward" => {
|
||||
// Cancel port forwarding
|
||||
self.handle_cancel_tcpip_forward(&mut cursor, want_reply)
|
||||
}
|
||||
"streamlocal-forward@openssh.com" => {
|
||||
// Unix socket forwarding(未实现)
|
||||
warn!("Unix socket forwarding not implemented");
|
||||
Ok((false, None))
|
||||
}
|
||||
_ => {
|
||||
warn!("Unsupported global request: {}", request_name);
|
||||
Ok((false, None))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 处理tcpip-forward请求(Local port forwarding)
|
||||
/// 参考RFC 4254 Section 7.1
|
||||
fn handle_tcpip_forward(&mut self, cursor: &mut std::io::Cursor<&[u8]>, want_reply: bool) -> Result<(bool, Option<Vec<u8>>)> {
|
||||
// 读取bind address(SSH string)
|
||||
let bind_address = read_ssh_string(cursor)?;
|
||||
|
||||
// 读取bind port
|
||||
let bind_port = cursor.read_u32::<BigEndian>()?;
|
||||
|
||||
info!("tcpip-forward request: bind_address={}, bind_port={}", bind_address, bind_port);
|
||||
|
||||
// 添加到active forwards
|
||||
let mut forwards = self.active_forwards.lock().unwrap();
|
||||
forwards.push((bind_port, PortForwardType::Local));
|
||||
|
||||
// 返回成功响应(包含bind_port)
|
||||
if want_reply {
|
||||
let response = self.build_global_request_response(true, Some(bind_port))?;
|
||||
Ok((true, Some(response)))
|
||||
} else {
|
||||
Ok((true, None))
|
||||
}
|
||||
}
|
||||
|
||||
/// 处理cancel-tcpip-forward请求
|
||||
fn handle_cancel_tcpip_forward(&mut self, cursor: &mut std::io::Cursor<&[u8]>, want_reply: bool) -> Result<(bool, Option<Vec<u8>>)> {
|
||||
let bind_address = read_ssh_string(cursor)?;
|
||||
let bind_port = cursor.read_u32::<BigEndian>()?;
|
||||
|
||||
info!("cancel-tcpip-forward: bind_address={}, bind_port={}", bind_address, bind_port);
|
||||
|
||||
// 移除active forward
|
||||
let mut forwards = self.active_forwards.lock().unwrap();
|
||||
forwards.retain(|(port, _)| *port != bind_port);
|
||||
|
||||
if want_reply {
|
||||
let response = self.build_global_request_response(true, None)?;
|
||||
Ok((true, Some(response)))
|
||||
} else {
|
||||
Ok((true, None))
|
||||
}
|
||||
}
|
||||
|
||||
/// 构建SSH_MSG_REQUEST_SUCCESS/FAILURE响应
|
||||
fn build_global_request_response(&self, success: bool, bound_port: Option<u32>) -> Result<Vec<u8>> {
|
||||
use crate::ssh_server::packet::PacketType;
|
||||
|
||||
let mut response = Vec::new();
|
||||
|
||||
if success {
|
||||
response.write_u8(PacketType::SSH_MSG_REQUEST_SUCCESS as u8)?;
|
||||
|
||||
// 如果有bound_port,写入(用于tcpip-forward响应)
|
||||
if let Some(port) = bound_port {
|
||||
response.write_u32::<BigEndian>(port)?;
|
||||
}
|
||||
} else {
|
||||
response.write_u8(PacketType::SSH_MSG_REQUEST_FAILURE as u8)?;
|
||||
}
|
||||
|
||||
Ok(response)
|
||||
}
|
||||
|
||||
/// 处理SSH_MSG_CHANNEL_OPEN for "direct-tcpip"(Remote port forwarding)
|
||||
/// 参考RFC 4254 Section 7.2
|
||||
pub fn handle_direct_tcpip_channel(&mut self, data: &[u8]) -> Result<DirectTcpipChannel> {
|
||||
info!("Processing direct-tcpip channel open");
|
||||
|
||||
let mut cursor = std::io::Cursor::new(data);
|
||||
cursor.set_position(1); // Skip packet type
|
||||
|
||||
// 读取channel type(已知道是"direct-tcpip",跳过)
|
||||
let _channel_type = read_ssh_string(&mut cursor)?;
|
||||
|
||||
// 读取sender_channel
|
||||
let sender_channel = cursor.read_u32::<BigEndian>()?;
|
||||
|
||||
// 读取initial window size
|
||||
let initial_window_size = cursor.read_u32::<BigEndian>()?;
|
||||
|
||||
// 读取maximum packet size
|
||||
let max_packet_size = cursor.read_u32::<BigEndian>()?;
|
||||
|
||||
// 读取host to connect(SSH string)
|
||||
let host_to_connect = read_ssh_string(&mut cursor)?;
|
||||
|
||||
// 读取port to connect
|
||||
let port_to_connect = cursor.read_u32::<BigEndian>()?;
|
||||
|
||||
// 读取originator address(SSH string)
|
||||
let originator_address = read_ssh_string(&mut cursor)?;
|
||||
|
||||
// 读取originator port
|
||||
let originator_port = cursor.read_u32::<BigEndian>()?;
|
||||
|
||||
info!("direct-tcpip: host={}, port={}, originator={}:{}",
|
||||
host_to_connect, port_to_connect, originator_address, originator_port);
|
||||
|
||||
Ok(DirectTcpipChannel {
|
||||
sender_channel,
|
||||
initial_window_size,
|
||||
max_packet_size,
|
||||
host_to_connect,
|
||||
port_to_connect,
|
||||
originator_address,
|
||||
originator_port,
|
||||
})
|
||||
}
|
||||
|
||||
/// 处理SSH_MSG_CHANNEL_OPEN for "forwarded-tcpip"(Local port forwarding)
|
||||
/// 参考RFC 4254 Section 7.1
|
||||
pub fn handle_forwarded_tcpip_channel(&mut self, data: &[u8]) -> Result<ForwardedTcpipChannel> {
|
||||
info!("Processing forwarded-tcpip channel open");
|
||||
|
||||
let mut cursor = std::io::Cursor::new(data);
|
||||
cursor.set_position(1);
|
||||
|
||||
let _channel_type = read_ssh_string(&mut cursor)?;
|
||||
let sender_channel = cursor.read_u32::<BigEndian>()?;
|
||||
let initial_window_size = cursor.read_u32::<BigEndian>()?;
|
||||
let max_packet_size = cursor.read_u32::<BigEndian>()?;
|
||||
|
||||
// 读取bind address(SSH string)
|
||||
let bind_address = read_ssh_string(&mut cursor)?;
|
||||
|
||||
// 读取bind port
|
||||
let bind_port = cursor.read_u32::<BigEndian>()?;
|
||||
|
||||
// 读取originator address(SSH string)
|
||||
let originator_address = read_ssh_string(&mut cursor)?;
|
||||
|
||||
// 读取originator port
|
||||
let originator_port = cursor.read_u32::<BigEndian>()?;
|
||||
|
||||
info!("forwarded-tcpip: bind={}:{}, originator={}:{}",
|
||||
bind_address, bind_port, originator_address, originator_port);
|
||||
|
||||
Ok(ForwardedTcpipChannel {
|
||||
sender_channel,
|
||||
initial_window_size,
|
||||
max_packet_size,
|
||||
bind_address,
|
||||
bind_port,
|
||||
originator_address,
|
||||
originator_port,
|
||||
})
|
||||
}
|
||||
|
||||
/// 连接到目标主机(用于端口转发)
|
||||
pub fn connect_to_target(host: &str, port: u32) -> Result<TcpStream> {
|
||||
let addr = format!("{}:{}", host, port);
|
||||
info!("Connecting to target: {}", addr);
|
||||
|
||||
let stream = TcpStream::connect(&addr)?;
|
||||
info!("Connected to target successfully");
|
||||
|
||||
Ok(stream)
|
||||
}
|
||||
|
||||
/// 创建监听socket(用于Local port forwarding)
|
||||
pub fn create_listener(bind_address: &str, bind_port: u32) -> Result<TcpListener> {
|
||||
let addr = if bind_address.is_empty() || bind_address == "0.0.0.0" {
|
||||
format!("127.0.0.1:{}", bind_port)
|
||||
} else {
|
||||
format!("{}:{}", bind_address, bind_port)
|
||||
};
|
||||
|
||||
info!("Creating listener on {}", addr);
|
||||
|
||||
let listener = TcpListener::bind(&addr)?;
|
||||
info!("Listener created successfully");
|
||||
|
||||
Ok(listener)
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct-tcpip channel结构(Remote port forwarding)
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct DirectTcpipChannel {
|
||||
pub sender_channel: u32,
|
||||
pub initial_window_size: u32,
|
||||
pub max_packet_size: u32,
|
||||
pub host_to_connect: String,
|
||||
pub port_to_connect: u32,
|
||||
pub originator_address: String,
|
||||
pub originator_port: u32,
|
||||
}
|
||||
|
||||
/// Forwarded-tcpip channel结构(Local port forwarding)
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ForwardedTcpipChannel {
|
||||
pub sender_channel: u32,
|
||||
pub initial_window_size: u32,
|
||||
pub max_packet_size: u32,
|
||||
pub bind_address: String,
|
||||
pub bind_port: u32,
|
||||
pub originator_address: String,
|
||||
pub originator_port: u32,
|
||||
}
|
||||
|
||||
/// 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_port_forward_manager_creation() {
|
||||
let manager = PortForwardManager::new();
|
||||
assert_eq!(manager.active_forwards.lock().unwrap().len(), 0);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user