mirror of
https://github.com/Noratrieb/cluelessh.git
synced 2026-01-14 08:25:05 +01:00
disconnect after ctrl c
This commit is contained in:
parent
bc7e12e50b
commit
b75db7c21f
3 changed files with 78 additions and 13 deletions
|
|
@ -7,7 +7,7 @@ use tokio::{
|
|||
};
|
||||
use tracing::{error, info};
|
||||
|
||||
use ssh_transport::{ServerConnection, SshError, ThreadRngRand};
|
||||
use ssh_transport::{ServerConnection, SshStatus, ThreadRngRand};
|
||||
use tracing_subscriber::EnvFilter;
|
||||
|
||||
#[tokio::main]
|
||||
|
|
@ -67,13 +67,16 @@ async fn handle_connection(next: (TcpStream, SocketAddr)) -> Result<()> {
|
|||
|
||||
if let Err(err) = state.recv_bytes(&buf[..read]) {
|
||||
match err {
|
||||
SshError::ClientError(err) => {
|
||||
SshStatus::ClientError(err) => {
|
||||
info!(?err, "disconnecting client after invalid operation");
|
||||
return Ok(());
|
||||
}
|
||||
SshError::ServerError(err) => {
|
||||
SshStatus::ServerError(err) => {
|
||||
return Err(err);
|
||||
}
|
||||
SshStatus::Disconnect => {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@ pub(crate) struct ServerChannelsState {
|
|||
}
|
||||
|
||||
struct SessionChannel {
|
||||
/// Whether our side has closed this channel.
|
||||
we_closed: bool,
|
||||
peer_channel: u32,
|
||||
has_pty: bool,
|
||||
has_shell: bool,
|
||||
|
|
@ -49,6 +51,7 @@ impl ServerChannelsState {
|
|||
confirm.u32(max_packet_size);
|
||||
|
||||
self.channels.push(SessionChannel {
|
||||
we_closed: false,
|
||||
peer_channel: sender_channel,
|
||||
has_pty: false,
|
||||
has_shell: false,
|
||||
|
|
@ -67,7 +70,7 @@ impl ServerChannelsState {
|
|||
failure.u32(sender_channel);
|
||||
failure.u32(3); // SSH_OPEN_UNKNOWN_CHANNEL_TYPE
|
||||
failure.string(b"unknown channel type");
|
||||
failure.string(b"en_US");
|
||||
failure.string(b"");
|
||||
|
||||
self.packets_to_send.push_back(Packet {
|
||||
payload: failure.finish(),
|
||||
|
|
@ -80,15 +83,54 @@ impl ServerChannelsState {
|
|||
let data = payload.string()?;
|
||||
|
||||
let channel = self.channel(our_channel)?;
|
||||
let peer = channel.peer_channel;
|
||||
channel.recv_bytes(data);
|
||||
|
||||
let mut reply = Writer::new();
|
||||
reply.u8(Packet::SSH_MSG_CHANNEL_DATA);
|
||||
reply.u32(channel.peer_channel);
|
||||
reply.string(data);
|
||||
reply.string(data); // echo :3
|
||||
self.packets_to_send.push_back(Packet {
|
||||
payload: reply.finish(),
|
||||
});
|
||||
|
||||
if data.contains(&0x03 /*EOF, Ctrl-C*/) {
|
||||
debug!(?our_channel, "Received EOF, closing channel");
|
||||
// <https://datatracker.ietf.org/doc/html/rfc4254#section-5.3>
|
||||
let mut eof = Writer::new();
|
||||
eof.u8(Packet::SSH_MSG_CHANNEL_EOF);
|
||||
eof.u32(peer);
|
||||
self.packets_to_send.push_back(Packet {
|
||||
payload: eof.finish(),
|
||||
});
|
||||
|
||||
let mut close = Writer::new();
|
||||
close.u8(Packet::SSH_MSG_CHANNEL_CLOSE);
|
||||
close.u32(peer);
|
||||
self.packets_to_send.push_back(Packet {
|
||||
payload: close.finish(),
|
||||
});
|
||||
|
||||
let channel = self.channel(our_channel)?;
|
||||
channel.we_closed = true;
|
||||
}
|
||||
}
|
||||
Packet::SSH_MSG_CHANNEL_CLOSE => {
|
||||
// <https://datatracker.ietf.org/doc/html/rfc4254#section-5.3>
|
||||
let our_channel = payload.u32()?;
|
||||
let channel = self.channel(our_channel)?;
|
||||
if !channel.we_closed {
|
||||
let mut close = Writer::new();
|
||||
close.u8(Packet::SSH_MSG_CHANNEL_CLOSE);
|
||||
close.u32(channel.peer_channel);
|
||||
self.packets_to_send.push_back(Packet {
|
||||
payload: close.finish(),
|
||||
});
|
||||
}
|
||||
|
||||
self.channels.remove(our_channel as usize);
|
||||
|
||||
debug!("Channel has been closed");
|
||||
}
|
||||
Packet::SSH_MSG_CHANNEL_REQUEST => {
|
||||
let our_channel = payload.u32()?;
|
||||
|
|
|
|||
|
|
@ -21,7 +21,10 @@ use x25519_dalek::{EphemeralSecret, PublicKey};
|
|||
pub use packet::Msg;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum SshError {
|
||||
pub enum SshStatus {
|
||||
/// The client has sent a disconnect request, close the connection.
|
||||
/// This is not an error.
|
||||
Disconnect,
|
||||
/// The client did something wrong.
|
||||
/// The connection should be closed and a notice may be logged,
|
||||
/// but this does not require operator intervention.
|
||||
|
|
@ -32,9 +35,9 @@ pub enum SshError {
|
|||
ServerError(eyre::Report),
|
||||
}
|
||||
|
||||
pub type Result<T, E = SshError> = std::result::Result<T, E>;
|
||||
pub type Result<T, E = SshStatus> = std::result::Result<T, E>;
|
||||
|
||||
impl From<eyre::Report> for SshError {
|
||||
impl From<eyre::Report> for SshStatus {
|
||||
fn from(value: eyre::Report) -> Self {
|
||||
Self::ServerError(value)
|
||||
}
|
||||
|
|
@ -140,6 +143,23 @@ impl ServerConnection {
|
|||
|
||||
while let Some(packet) = self.packet_transport.recv_next_packet() {
|
||||
trace!(packet_type = ?packet.payload.get(0), packet_len = ?packet.payload.len(), "Received packet");
|
||||
|
||||
// Handle some packets ignoring the state.
|
||||
match packet.payload.get(0).copied() {
|
||||
Some(Packet::SSH_MSG_DISCONNECT) => {
|
||||
// <https://datatracker.ietf.org/doc/html/rfc4253#section-11.1>
|
||||
let mut disconnect = Parser::new(&packet.payload[1..]);
|
||||
let reason = disconnect.u32()?;
|
||||
let description = disconnect.utf8_string()?;
|
||||
let _language_tag = disconnect.utf8_string()?;
|
||||
|
||||
info!(?reason, ?description, "Client disconnecting");
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match &mut self.state {
|
||||
ServerState::ProtoExchange { .. } => unreachable!("handled above"),
|
||||
ServerState::KeyExchangeInit {
|
||||
|
|
@ -407,7 +427,7 @@ impl ServerConnection {
|
|||
let mut banner = Writer::new();
|
||||
banner.u8(Packet::SSH_MSG_USERAUTH_BANNER);
|
||||
banner.string(b"!! this system ONLY allows catgirls to enter !!\r\n!! all other attempts WILL be prosecuted to the full extent of the rawr !!\r\n");
|
||||
banner.string(b"en_US");
|
||||
banner.string(b"");
|
||||
self.packet_transport.queue_packet(Packet {
|
||||
payload: banner.finish(),
|
||||
});
|
||||
|
|
@ -442,9 +462,9 @@ impl ServerConnection {
|
|||
|
||||
let mut failure = Writer::new();
|
||||
failure.u8(Packet::SSH_MSG_REQUEST_FAILURE);
|
||||
//self.packet_transport.queue_packet(Packet {
|
||||
// payload: failure.finish(),
|
||||
//});
|
||||
self.packet_transport.queue_packet(Packet {
|
||||
payload: failure.finish(),
|
||||
});
|
||||
}
|
||||
_ => {
|
||||
todo!("packet: {packet_type}");
|
||||
|
|
@ -485,7 +505,7 @@ const PRIVKEY_BYTES: &[u8; 32] = &[
|
|||
|
||||
macro_rules! client_error {
|
||||
($($tt:tt)*) => {
|
||||
$crate::SshError::ClientError(::std::format!($($tt)*))
|
||||
$crate::SshStatus::ClientError(::std::format!($($tt)*))
|
||||
};
|
||||
}
|
||||
use client_error;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue