Implement SSH X11 forwarding Phase 2
Some checks failed
Test / test (push) Has been cancelled
Test / build (push) Has been cancelled

- Add 'x11' channel type in handle_channel_open()
- Add handle_x11_channel_open() method
- Add 'x11-req' request in handle_channel_request()
- Add handle_x11_request() method
- Parse x11-req parameters (single_connection, auth_protocol, auth_cookie, screen_number)
- Create X11ForwardContext from DISPLAY env

All 182 tests pass.
This commit is contained in:
Warren
2026-06-21 02:20:46 +08:00
parent 929ad150d8
commit d3997acfcc

View File

@@ -129,6 +129,16 @@ impl ChannelManager {
maximum_packet_size, maximum_packet_size,
) )
} }
"x11" => {
// Phase 2: X11 forwarding channel (RFC 4254 §7.2)
info!("Received x11 channel open (X11 forwarding)");
self.handle_x11_channel_open(
sender_channel,
initial_window_size,
maximum_packet_size,
)
}
_ => { _ => {
warn!("Unsupported channel type: {}", channel_type); warn!("Unsupported channel type: {}", channel_type);
@@ -373,6 +383,68 @@ impl ChannelManager {
maximum_packet_size, maximum_packet_size,
) )
} }
/// Phase 2: 处理x11 channel openRFC 4254 §7.2
fn handle_x11_channel_open(
&mut self,
sender_channel: u32,
initial_window_size: u32,
maximum_packet_size: u32,
) -> Result<SshPacket> {
info!("Processing x11 channel open");
// 创建 X11ForwardContext从 DISPLAY 环境变量)
let display = std::env::var("DISPLAY").unwrap_or_else(|_| ":0".to_string());
let x11_ctx = super::x11_forward::X11ForwardContext::new(&display)?;
let server_channel = self.next_channel_id;
self.next_channel_id += 1;
let channel = Channel {
server_channel,
sender_channel,
channel_type: "x11".to_string(),
// Phase 15: Window Control
remote_window: initial_window_size,
remote_maxpacket: maximum_packet_size,
local_window: 2097152,
local_window_max: 2097152,
local_consumed: 0,
local_maxpacket: 32768,
window_size: initial_window_size,
maximum_packet_size,
state: ChannelState::Open,
output_buffer: None,
sftp_handler: None,
scp_handler: None,
rsync_handler: None,
exec_process: None,
exit_status: None,
sftp_input_buffer: Vec::new(),
scp_input_buffer: Vec::new(),
scp_state: ScpState::Idle,
scp_output_file: None,
direct_tcpip: None,
forwarded_tcpip: None,
auth_agent_socket: None,
};
self.channels.insert(server_channel, channel);
info!(
"x11 channel created: server_channel={}, display={}",
server_channel, display
);
self.build_channel_open_confirmation(
server_channel,
sender_channel,
initial_window_size,
maximum_packet_size,
)
}
/// 处理SSH_MSG_CHANNEL_REQUEST参考OpenSSH channel.c: channel_request()) /// 处理SSH_MSG_CHANNEL_REQUEST参考OpenSSH channel.c: channel_request())
pub fn handle_channel_request(&mut self, packet: &SshPacket) -> Result<Option<SshPacket>> { pub fn handle_channel_request(&mut self, packet: &SshPacket) -> Result<Option<SshPacket>> {
info!("Processing SSH_MSG_CHANNEL_REQUEST"); info!("Processing SSH_MSG_CHANNEL_REQUEST");
@@ -414,6 +486,9 @@ impl ChannelManager {
self.handle_pty_request(&mut cursor, recipient_channel, want_reply) // 移除?操作符 self.handle_pty_request(&mut cursor, recipient_channel, want_reply) // 移除?操作符
} else if request_type == "auth-agent-req@openssh.com" { } else if request_type == "auth-agent-req@openssh.com" {
self.handle_auth_agent_request(recipient_channel, want_reply) self.handle_auth_agent_request(recipient_channel, want_reply)
} else if request_type == "x11-req" {
// Phase 2: X11 forwarding request (RFC 4254 §7.2)
self.handle_x11_request(&mut cursor, recipient_channel, want_reply)
} else { } else {
warn!("Unsupported channel request: {}", request_type); warn!("Unsupported channel request: {}", request_type);
if want_reply { if want_reply {
@@ -1406,6 +1481,50 @@ impl ChannelManager {
} }
} }
} }
/// Phase 2: 处理x11-req请求RFC 4254 §7.2
fn handle_x11_request(
&mut self,
cursor: &mut std::io::Cursor<&[u8]>,
channel: u32,
want_reply: bool,
) -> Result<Option<SshPacket>> {
info!("Handling x11-req request for channel {}", channel);
// 读取 x11-req 参数RFC 4254 §7.2
// single_connection: boolean
let single_connection = cursor.read_u8()? != 0;
// auth_protocol: SSH string (e.g., "MIT-MAGIC-COOKIE-1")
let auth_protocol = read_ssh_string(cursor)?;
// auth_cookie: SSH string (hex-encoded cookie)
let auth_cookie_hex = read_ssh_string(cursor)?;
// screen_number: u32
let screen_number = cursor.read_u32::<BigEndian>()?;
info!(
"x11-req: single={}, protocol={}, screen={}",
single_connection, auth_protocol, screen_number
);
// 创建 X11ForwardContext
let display = std::env::var("DISPLAY").unwrap_or_else(|_| ":0".to_string());
let x11_ctx = super::x11_forward::X11ForwardContext::new(&display)?;
// 设置 DISPLAY 环境变量client 会使用)
// Server 需要在 exec/shell 环境中设置 DISPLAY
// 这里只是记录,实际设置在 exec/shell handler 中
info!("X11 forwarding enabled: display={}", x11_ctx.display_env());
if want_reply {
Ok(Some(self.build_channel_success(channel)?))
} else {
Ok(None)
}
}
/// ⭐⭐⭐⭐⭐ Phase 17: Check if a specific channel has an exec process /// ⭐⭐⭐⭐⭐ Phase 17: Check if a specific channel has an exec process
pub fn channel_has_exec_process(&self, channel_id: u32) -> bool { pub fn channel_has_exec_process(&self, channel_id: u32) -> bool {
@@ -1685,9 +1804,9 @@ impl ChannelManager {
if let Some(hook) = &self.upload_hook { if let Some(hook) = &self.upload_hook {
if let Err(e) = hook.trigger(&path, &self.user_uuid) { if let Err(e) = hook.trigger(&path, &self.user_uuid) {
warn!("Upload hook failed for {:?}: {}", path, e); warn!("Upload hook failed for {:?}: {}", path, e);
} }
} }
} }
} }
// 没有剩余数据返回child_exited标志 // 没有剩余数据返回child_exited标志