diff --git a/bin/cluelesshd/src/main.rs b/bin/cluelesshd/src/main.rs index 988415f..2b770bc 100644 --- a/bin/cluelesshd/src/main.rs +++ b/bin/cluelesshd/src/main.rs @@ -300,13 +300,23 @@ async fn handle_session_channel(user: String, channel: Channel) -> Result<()> { let Ok(read) = read else { bail!("failed to read"); }; - let _ = state.channel.send(ChannelOperationKind::Data(read_buf[..read].to_vec())).await; + if read == 0 { + // EOF, close the stream. + state.reader = None; + } else { + let _ = state.channel.send(ChannelOperationKind::Data(read_buf[..read].to_vec())).await; + } } read = read_ext => { let Ok(read) = read else { bail!("failed to read"); }; - let _ = state.channel.send(ChannelOperationKind::ExtendedData(1, read_ext_buf[..read].to_vec())).await; + if read == 0 { + // EOF, close the stream. + state.reader_ext = None; + } else { + let _ = state.channel.send(ChannelOperationKind::ExtendedData(1, read_ext_buf[..read].to_vec())).await; + } } } } diff --git a/bin/cluelesshd/tests/openssh-client/command.sh b/bin/cluelesshd/tests/openssh-client/command.sh index 9c32cd5..a5702c0 100644 --- a/bin/cluelesshd/tests/openssh-client/command.sh +++ b/bin/cluelesshd/tests/openssh-client/command.sh @@ -1,3 +1,6 @@ #!/usr/bin/env bash ssh -p "$PORT" "$HOST" echo jdklfsjdöklfd | grep "jdklfsjdöklfd" + +# Important: redirect 2>&1 first before clobbering 1 +ssh -p "$PORT" "$HOST" "echo jdklfsjdöklfd 1>&2" 2>&1 1>/dev/null | grep "jdklfsjdöklfd" diff --git a/lib/cluelessh-connection/src/lib.rs b/lib/cluelessh-connection/src/lib.rs index 2ad76c0..2a82241 100644 --- a/lib/cluelessh-connection/src/lib.rs +++ b/lib/cluelessh-connection/src/lib.rs @@ -331,7 +331,9 @@ impl ChannelsState { let limit = cmp::min(queued_data_extended.len(), peer_window_size as usize); let data_to_send = queued_data_extended.splice(..limit, []).collect::>(); - self.send_data(our_channel, &data_to_send, Some(number)); + if !data_to_send.is_empty() { + self.send_data(our_channel, &data_to_send, Some(number)); + } } } } @@ -663,6 +665,8 @@ impl ChannelsState { data: &[u8], extended_code: Option, ) { + assert!(!data.is_empty()); + let channel = self.channel(channel_number).unwrap(); let mut chunks = data.chunks(channel.peer_max_packet_size as usize); @@ -680,7 +684,7 @@ impl ChannelsState { // Send everything we can, which empties the window. channel.peer_window_size -= rest; assert_eq!(channel.peer_window_size, 0); - self.send_data_packet(channel_number, to_send); + self.send_data_packet(channel_number, to_send, extended_code); } // It's over, we have exhausted all window space. @@ -710,21 +714,34 @@ impl ChannelsState { } trace!(channel = %channel_number, window = %channel.peer_window_size, "Remaining window on their side"); - self.send_data_packet(channel_number, data); + self.send_data_packet(channel_number, data, extended_code); } } /// Send a single data packet. /// The caller needs to ensure the windowing and packet size requirements are upheld. - fn send_data_packet(&mut self, channel_number: ChannelNumber, data: &[u8]) { + fn send_data_packet( + &mut self, + channel_number: ChannelNumber, + data: &[u8], + extended_code: Option, + ) { assert!(!data.is_empty(), "Trying to send empty data packet"); - trace!(%channel_number, amount = %data.len(), "Sending channel data"); + if let Some(extended_code) = extended_code { + trace!(%channel_number, amount = %data.len(), %extended_code, "Sending extended channel data"); + } else { + trace!(%channel_number, amount = %data.len(), "Sending channel data"); + } let channel = self.channel(channel_number).unwrap(); let peer = channel.peer_channel; assert!(channel.peer_max_packet_size >= data.len() as u32); - self.packets_to_send - .push_back(Packet::new_msg_channel_data(peer, data)); + let packet = if let Some(extended_code) = extended_code { + Packet::new_msg_channel_extended_data(peer, extended_code, data) + } else { + Packet::new_msg_channel_data(peer, data) + }; + self.packets_to_send.push_back(packet); } fn send_channel_success(&mut self, recipient_channel: u32) { diff --git a/lib/cluelessh-transport/src/packet/ctors.rs b/lib/cluelessh-transport/src/packet/ctors.rs index 3b4ce90..7e79d50 100644 --- a/lib/cluelessh-transport/src/packet/ctors.rs +++ b/lib/cluelessh-transport/src/packet/ctors.rs @@ -124,6 +124,7 @@ ctors! { ); fn new_msg_channel_window_adjust(SSH_MSG_CHANNEL_WINDOW_ADJUST; recipient_channel: u32, bytes_to_add: u32); fn new_msg_channel_data(SSH_MSG_CHANNEL_DATA; recipient_channel: u32, data: string); + fn new_msg_channel_extended_data(SSH_MSG_CHANNEL_EXTENDED_DATA; recipient_channel: u32, data_type_code: u32, data: string); fn new_msg_channel_eof(SSH_MSG_CHANNEL_EOF; recipient_channel: u32); fn new_msg_channel_close(SSH_MSG_CHANNEL_CLOSE; recipient_channel: u32);