ineteractive "tty"

This commit is contained in:
nora 2024-08-26 03:14:27 +02:00
parent 6486bb4c81
commit c7965e404a
3 changed files with 113 additions and 13 deletions

View file

@ -1,3 +1,5 @@
mod readline;
use std::{net::SocketAddr, sync::Arc}; use std::{net::SocketAddr, sync::Arc};
use cluelessh_tokio::{server::ServerAuthVerify, Channel}; use cluelessh_tokio::{server::ServerAuthVerify, Channel};
@ -134,6 +136,8 @@ async fn handle_session_channel(
mut channel: Channel, mut channel: Channel,
total_sent_data: Arc<Mutex<Vec<u8>>>, total_sent_data: Arc<Mutex<Vec<u8>>>,
) -> Result<()> { ) -> Result<()> {
let mut readline = None;
loop { loop {
match channel.next_update().await { match channel.next_update().await {
Ok(update) => match update { Ok(update) => match update {
@ -141,6 +145,13 @@ async fn handle_session_channel(
let success = ChannelOperationKind::Success; let success = ChannelOperationKind::Success;
match req { match req {
ChannelRequest::PtyReq { want_reply, .. } => { ChannelRequest::PtyReq { want_reply, .. } => {
let mut new_readline = readline::InteractiveShell::new();
let to_write = new_readline.bytes_to_write();
if !to_write.is_empty() {
channel.send(ChannelOperationKind::Data(to_write)).await?;
}
readline = Some(new_readline);
if want_reply { if want_reply {
channel.send(success).await?; channel.send(success).await?;
} }
@ -176,13 +187,7 @@ async fn handle_session_channel(
} }
ChannelUpdateKind::OpenFailed { .. } => todo!(), ChannelUpdateKind::OpenFailed { .. } => todo!(),
ChannelUpdateKind::Data { data } => { ChannelUpdateKind::Data { data } => {
let is_eof = data.contains(&0x04 /*EOF, Ctrl-D*/); // Store sent data
// echo :3
channel
.send(ChannelOperationKind::Data(data.clone()))
.await?;
let mut total_sent_data = total_sent_data.lock().await; let mut total_sent_data = total_sent_data.lock().await;
// arbitrary limit // arbitrary limit
if total_sent_data.len() < 50_000 { if total_sent_data.len() < 50_000 {
@ -195,6 +200,28 @@ async fn handle_session_channel(
channel.send(ChannelOperationKind::Close).await?; channel.send(ChannelOperationKind::Close).await?;
} }
if let Some(readline) = &mut readline {
readline.recv_bytes(&data);
let to_write = readline.bytes_to_write();
if !to_write.is_empty() {
channel.send(ChannelOperationKind::Data(to_write)).await?;
}
if readline.should_exit() {
debug!("Received Ctrl-D, closing channel");
channel.send(ChannelOperationKind::Eof).await?;
channel.send(ChannelOperationKind::Close).await?;
}
} else {
// bad fallback behavior
let is_eof = data.contains(&0x04 /*EOF, Ctrl-D*/);
// echo :3
channel
.send(ChannelOperationKind::Data(data.clone()))
.await?;
if is_eof { if is_eof {
debug!("Received Ctrl-D, closing channel"); debug!("Received Ctrl-D, closing channel");
@ -202,6 +229,7 @@ async fn handle_session_channel(
channel.send(ChannelOperationKind::Close).await?; channel.send(ChannelOperationKind::Close).await?;
} }
} }
}
ChannelUpdateKind::Open(_) ChannelUpdateKind::Open(_)
| ChannelUpdateKind::Closed | ChannelUpdateKind::Closed
| ChannelUpdateKind::ExtendedData { .. } | ChannelUpdateKind::ExtendedData { .. }
@ -233,7 +261,7 @@ fn execute_command(command: &[u8]) -> ProcessOutput {
stdout: b"what the hell".to_vec(), stdout: b"what the hell".to_vec(),
}; };
}; };
match command { match command.trim() {
"uname -s -v -n -r -m" => ProcessOutput { "uname -s -v -n -r -m" => ProcessOutput {
status: 0, status: 0,
stdout: UNAME_SVNRM.to_vec(), stdout: UNAME_SVNRM.to_vec(),

View file

@ -0,0 +1,72 @@
pub struct InteractiveShell {
line_buf: Vec<u8>,
out_buf: Vec<u8>,
should_exit: bool,
}
impl InteractiveShell {
pub fn new() -> Self {
let mut this = Self {
line_buf: Vec::new(),
out_buf: Vec::new(),
should_exit: false,
};
this.prompt();
this
}
pub fn recv_bytes(&mut self, data: &[u8]) {
// we're doing a little bit of tty-drivering
for &byte in data {
match byte {
// EOF
0x04 => {
self.should_exit = true;
return;
}
b'\r' => {
let output = super::execute_command(&self.line_buf);
self.line_buf.clear();
self.write(b"\r\n");
self.write(&output.stdout);
self.prompt();
}
// ESC
27 => {
// We don't handle any of the fancy escape characters, so just drop it to avoid weird behavior.
}
// DEL
127 => {
// Backspace, space, backspace.
// We literally erase it.
if self.line_buf.len() > 0 {
self.write(&[8, 32, 8]);
self.line_buf.truncate(self.line_buf.len() - 1);
}
}
_ => {
if self.line_buf.len() < 1_000 {
self.line_buf.extend_from_slice(&[byte]);
}
self.write(&[byte]);
}
}
}
}
fn prompt(&mut self) {
self.write(b"# ");
}
fn write(&mut self, data: &[u8]) {
self.out_buf.extend_from_slice(data);
}
pub fn should_exit(&self) -> bool {
self.should_exit
}
pub fn bytes_to_write(&mut self) -> Vec<u8> {
std::mem::take(&mut self.out_buf)
}
}