mirror of
https://github.com/Noratrieb/cluelessh.git
synced 2026-01-16 09:25:04 +01:00
stuff
This commit is contained in:
parent
9c320c8b4c
commit
ae5db1642c
5 changed files with 166 additions and 89 deletions
|
|
@ -80,6 +80,8 @@ async fn handle_connection(next: (TcpStream, SocketAddr)) -> Result<()> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
while let Some(channel_update) = state.next_channel_update() {}
|
||||||
|
|
||||||
while let Some(msg) = state.next_msg_to_send() {
|
while let Some(msg) = state.next_msg_to_send() {
|
||||||
conn.write_all(&msg.to_bytes())
|
conn.write_all(&msg.to_bytes())
|
||||||
.await
|
.await
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,8 @@ use crate::Result;
|
||||||
pub(crate) struct ServerChannelsState {
|
pub(crate) struct ServerChannelsState {
|
||||||
packets_to_send: VecDeque<Packet>,
|
packets_to_send: VecDeque<Packet>,
|
||||||
channels: Vec<SessionChannel>,
|
channels: Vec<SessionChannel>,
|
||||||
|
|
||||||
|
channel_updates: VecDeque<ChannelUpdate>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SessionChannel {
|
struct SessionChannel {
|
||||||
|
|
@ -20,11 +22,21 @@ struct SessionChannel {
|
||||||
sent_bytes: Vec<u8>,
|
sent_bytes: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct ChannelUpdate {
|
||||||
|
pub channel: u32,
|
||||||
|
pub kind: ChannelUpdateKind,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum ChannelUpdateKind {
|
||||||
|
ChannelData(Vec<u8>),
|
||||||
|
}
|
||||||
|
|
||||||
impl ServerChannelsState {
|
impl ServerChannelsState {
|
||||||
pub(crate) fn new() -> Self {
|
pub(crate) fn new() -> Self {
|
||||||
ServerChannelsState {
|
ServerChannelsState {
|
||||||
packets_to_send: VecDeque::new(),
|
packets_to_send: VecDeque::new(),
|
||||||
channels: Vec::new(),
|
channels: Vec::new(),
|
||||||
|
channel_updates: VecDeque::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -43,12 +55,13 @@ impl ServerChannelsState {
|
||||||
"session" => {
|
"session" => {
|
||||||
let our_number = self.channels.len() as u32;
|
let our_number = self.channels.len() as u32;
|
||||||
|
|
||||||
let mut confirm = Writer::new();
|
self.packets_to_send
|
||||||
confirm.u8(Packet::SSH_MSG_CHANNEL_OPEN_CONFIRMATION);
|
.push_back(Packet::new_msg_channel_open_confirmation(
|
||||||
confirm.u32(our_number);
|
our_number,
|
||||||
confirm.u32(sender_channel);
|
sender_channel,
|
||||||
confirm.u32(initial_window_size);
|
initial_window_size,
|
||||||
confirm.u32(max_packet_size);
|
max_packet_size,
|
||||||
|
));
|
||||||
|
|
||||||
self.channels.push(SessionChannel {
|
self.channels.push(SessionChannel {
|
||||||
we_closed: false,
|
we_closed: false,
|
||||||
|
|
@ -58,23 +71,16 @@ impl ServerChannelsState {
|
||||||
sent_bytes: Vec::new(),
|
sent_bytes: Vec::new(),
|
||||||
});
|
});
|
||||||
|
|
||||||
self.packets_to_send.push_back(Packet {
|
|
||||||
payload: confirm.finish(),
|
|
||||||
});
|
|
||||||
|
|
||||||
debug!(?channel_type, ?our_number, "Successfully opened channel");
|
debug!(?channel_type, ?our_number, "Successfully opened channel");
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let mut failure = Writer::new();
|
self.packets_to_send
|
||||||
failure.u8(Packet::SSH_MSG_CHANNEL_OPEN_FAILURE);
|
.push_back(Packet::new_msg_channel_open_failure(
|
||||||
failure.u32(sender_channel);
|
sender_channel,
|
||||||
failure.u32(3); // SSH_OPEN_UNKNOWN_CHANNEL_TYPE
|
3, // SSH_OPEN_UNKNOWN_CHANNEL_TYPE
|
||||||
failure.string(b"unknown channel type");
|
b"unknown channel type",
|
||||||
failure.string(b"");
|
b"",
|
||||||
|
));
|
||||||
self.packets_to_send.push_back(Packet {
|
|
||||||
payload: failure.finish(),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -83,33 +89,18 @@ impl ServerChannelsState {
|
||||||
let data = payload.string()?;
|
let data = payload.string()?;
|
||||||
|
|
||||||
let channel = self.channel(our_channel)?;
|
let channel = self.channel(our_channel)?;
|
||||||
let peer = channel.peer_channel;
|
|
||||||
channel.recv_bytes(data);
|
channel.recv_bytes(data);
|
||||||
|
|
||||||
let mut reply = Writer::new();
|
let peer = channel.peer_channel;
|
||||||
reply.u8(Packet::SSH_MSG_CHANNEL_DATA);
|
// echo :3
|
||||||
reply.u32(channel.peer_channel);
|
self.packets_to_send
|
||||||
reply.string(data); // echo :3
|
.push_back(Packet::new_msg_channel_data(peer, data));
|
||||||
self.packets_to_send.push_back(Packet {
|
|
||||||
payload: reply.finish(),
|
|
||||||
});
|
|
||||||
|
|
||||||
if data.contains(&0x03 /*EOF, Ctrl-C*/) {
|
if data.contains(&0x03 /*EOF, Ctrl-C*/) {
|
||||||
debug!(?our_channel, "Received EOF, closing channel");
|
debug!(?our_channel, "Received EOF, closing channel");
|
||||||
// <https://datatracker.ietf.org/doc/html/rfc4254#section-5.3>
|
// <https://datatracker.ietf.org/doc/html/rfc4254#section-5.3>
|
||||||
let mut eof = Writer::new();
|
self.packets_to_send
|
||||||
eof.u8(Packet::SSH_MSG_CHANNEL_EOF);
|
.push_back(Packet::new_msg_channel_close(peer));
|
||||||
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)?;
|
let channel = self.channel(our_channel)?;
|
||||||
channel.we_closed = true;
|
channel.we_closed = true;
|
||||||
|
|
@ -120,12 +111,8 @@ impl ServerChannelsState {
|
||||||
let our_channel = payload.u32()?;
|
let our_channel = payload.u32()?;
|
||||||
let channel = self.channel(our_channel)?;
|
let channel = self.channel(our_channel)?;
|
||||||
if !channel.we_closed {
|
if !channel.we_closed {
|
||||||
let mut close = Writer::new();
|
let close = Packet::new_msg_channel_close(channel.peer_channel);
|
||||||
close.u8(Packet::SSH_MSG_CHANNEL_CLOSE);
|
self.packets_to_send.push_back(close);
|
||||||
close.u32(channel.peer_channel);
|
|
||||||
self.packets_to_send.push_back(Packet {
|
|
||||||
payload: close.finish(),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.channels.remove(our_channel as usize);
|
self.channels.remove(our_channel as usize);
|
||||||
|
|
@ -203,22 +190,18 @@ impl ServerChannelsState {
|
||||||
self.packets_to_send.drain(..)
|
self.packets_to_send.drain(..)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn channel_updates(&mut self) -> impl Iterator<Item = ChannelUpdate> + '_ {
|
||||||
|
self.channel_updates.drain(..)
|
||||||
|
}
|
||||||
|
|
||||||
fn send_channel_success(&mut self, recipient_channel: u32) {
|
fn send_channel_success(&mut self, recipient_channel: u32) {
|
||||||
let mut failure = Writer::new();
|
self.packets_to_send
|
||||||
failure.u8(Packet::SSH_MSG_CHANNEL_SUCCESS);
|
.push_back(Packet::new_msg_channel_success(recipient_channel));
|
||||||
failure.u32(recipient_channel);
|
|
||||||
self.packets_to_send.push_back(Packet {
|
|
||||||
payload: failure.finish(),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_channel_failure(&mut self, recipient_channel: u32) {
|
fn send_channel_failure(&mut self, recipient_channel: u32) {
|
||||||
let mut failure = Writer::new();
|
self.packets_to_send
|
||||||
failure.u8(Packet::SSH_MSG_CHANNEL_FAILURE);
|
.push_back(Packet::new_msg_channel_failure(recipient_channel));
|
||||||
failure.u32(recipient_channel);
|
|
||||||
self.packets_to_send.push_back(Packet {
|
|
||||||
payload: failure.finish(),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn channel(&mut self, number: u32) -> Result<&mut SessionChannel> {
|
fn channel(&mut self, number: u32) -> Result<&mut SessionChannel> {
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ use sha2::Digest;
|
||||||
use tracing::{debug, info, trace};
|
use tracing::{debug, info, trace};
|
||||||
use x25519_dalek::{EphemeralSecret, PublicKey};
|
use x25519_dalek::{EphemeralSecret, PublicKey};
|
||||||
|
|
||||||
|
pub use channel::ChannelUpdate;
|
||||||
pub use packet::Msg;
|
pub use packet::Msg;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
@ -50,6 +51,8 @@ pub struct ServerConnection {
|
||||||
state: ServerState,
|
state: ServerState,
|
||||||
packet_transport: PacketTransport,
|
packet_transport: PacketTransport,
|
||||||
rng: Box<dyn SshRng + Send + Sync>,
|
rng: Box<dyn SshRng + Send + Sync>,
|
||||||
|
|
||||||
|
channel_updates: VecDeque<ChannelUpdate>,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ServerState {
|
enum ServerState {
|
||||||
|
|
@ -118,6 +121,7 @@ impl ServerConnection {
|
||||||
},
|
},
|
||||||
packet_transport: PacketTransport::new(),
|
packet_transport: PacketTransport::new(),
|
||||||
rng: Box::new(rng),
|
rng: Box::new(rng),
|
||||||
|
channel_updates: VecDeque::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -399,21 +403,16 @@ impl ServerConnection {
|
||||||
|
|
||||||
info!(?password, "Got password");
|
info!(?password, "Got password");
|
||||||
// Don't worry queen, your password is correct!
|
// Don't worry queen, your password is correct!
|
||||||
let mut success = Writer::new();
|
self.packet_transport
|
||||||
success.u8(Packet::SSH_MSG_USERAUTH_SUCCESS);
|
.queue_packet(Packet::new_msg_userauth_success());
|
||||||
self.packet_transport.queue_packet(Packet {
|
|
||||||
payload: success.finish(),
|
|
||||||
});
|
|
||||||
self.state = ServerState::ConnectionOpen(ServerChannelsState::new());
|
self.state = ServerState::ConnectionOpen(ServerChannelsState::new());
|
||||||
}
|
}
|
||||||
"publickey" => {
|
"publickey" => {
|
||||||
info!("Got public key");
|
info!("Got public key");
|
||||||
// Don't worry queen, your key is correct!
|
// Don't worry queen, your key is correct!
|
||||||
let mut success = Writer::new();
|
self.packet_transport
|
||||||
success.u8(Packet::SSH_MSG_USERAUTH_SUCCESS);
|
.queue_packet(Packet::new_msg_userauth_success());
|
||||||
self.packet_transport.queue_packet(Packet {
|
|
||||||
payload: success.finish(),
|
|
||||||
});
|
|
||||||
self.state = ServerState::ConnectionOpen(ServerChannelsState::new());
|
self.state = ServerState::ConnectionOpen(ServerChannelsState::new());
|
||||||
}
|
}
|
||||||
_ if *has_failed => {
|
_ if *has_failed => {
|
||||||
|
|
@ -424,21 +423,17 @@ impl ServerConnection {
|
||||||
_ => {
|
_ => {
|
||||||
// Initial.
|
// Initial.
|
||||||
|
|
||||||
let mut banner = Writer::new();
|
self.packet_transport.queue_packet(Packet::new_msg_userauth_banner(
|
||||||
banner.u8(Packet::SSH_MSG_USERAUTH_BANNER);
|
b"!! this system ONLY allows catgirls to enter !!\r\n\
|
||||||
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");
|
!! all other attempts WILL be prosecuted to the full extent of the rawr !!\r\n",
|
||||||
banner.string(b"");
|
b"",
|
||||||
self.packet_transport.queue_packet(Packet {
|
));
|
||||||
payload: banner.finish(),
|
|
||||||
});
|
|
||||||
|
|
||||||
let mut rejection = Writer::new();
|
self.packet_transport
|
||||||
rejection.u8(Packet::SSH_MSG_USERAUTH_FAILURE);
|
.queue_packet(Packet::new_msg_userauth_failure(
|
||||||
rejection.name_list(NameList::one("publickey"));
|
NameList::one("publickey"),
|
||||||
rejection.bool(false);
|
false,
|
||||||
self.packet_transport.queue_packet(Packet {
|
));
|
||||||
payload: rejection.finish(),
|
|
||||||
});
|
|
||||||
// Stay in the same state
|
// Stay in the same state
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -454,17 +449,15 @@ impl ServerConnection {
|
||||||
for packet in con.packets_to_send() {
|
for packet in con.packets_to_send() {
|
||||||
self.packet_transport.queue_packet(packet);
|
self.packet_transport.queue_packet(packet);
|
||||||
}
|
}
|
||||||
|
self.channel_updates.extend(con.channel_updates());
|
||||||
}
|
}
|
||||||
Packet::SSH_MSG_GLOBAL_REQUEST => {
|
Packet::SSH_MSG_GLOBAL_REQUEST => {
|
||||||
let request_name = payload.utf8_string()?;
|
let request_name = payload.utf8_string()?;
|
||||||
let want_reply = payload.bool()?;
|
let want_reply = payload.bool()?;
|
||||||
debug!(?request_name, ?want_reply, "Received global request");
|
debug!(?request_name, ?want_reply, "Received global request");
|
||||||
|
|
||||||
let mut failure = Writer::new();
|
self.packet_transport
|
||||||
failure.u8(Packet::SSH_MSG_REQUEST_FAILURE);
|
.queue_packet(Packet::new_msg_request_failure());
|
||||||
self.packet_transport.queue_packet(Packet {
|
|
||||||
payload: failure.finish(),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
todo!("packet: {packet_type}");
|
todo!("packet: {packet_type}");
|
||||||
|
|
@ -479,6 +472,10 @@ impl ServerConnection {
|
||||||
pub fn next_msg_to_send(&mut self) -> Option<Msg> {
|
pub fn next_msg_to_send(&mut self) -> Option<Msg> {
|
||||||
self.packet_transport.next_msg_to_send()
|
self.packet_transport.next_msg_to_send()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn next_channel_update(&mut self) -> Option<ChannelUpdate> {
|
||||||
|
self.channel_updates.pop_front()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// hardcoded test keys. lol.
|
// hardcoded test keys. lol.
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
mod ctors;
|
||||||
|
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
use crate::client_error;
|
use crate::client_error;
|
||||||
|
|
|
||||||
93
ssh-transport/src/packet/ctors.rs
Normal file
93
ssh-transport/src/packet/ctors.rs
Normal file
|
|
@ -0,0 +1,93 @@
|
||||||
|
use crate::packet::Packet;
|
||||||
|
use crate::parse::Writer;
|
||||||
|
|
||||||
|
#[allow(non_camel_case_types)]
|
||||||
|
mod ssh_type_to_rust {
|
||||||
|
pub(super) use {bool, u32, u8};
|
||||||
|
pub(super) type string<'a> = &'a [u8];
|
||||||
|
pub(super) type name_list<'a> = crate::parse::NameList<'a>;
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! ctors {
|
||||||
|
(
|
||||||
|
$(
|
||||||
|
fn $fn_name:ident(
|
||||||
|
$msg_type:ident;
|
||||||
|
$(
|
||||||
|
$name:ident: $ssh_type:ident
|
||||||
|
),*
|
||||||
|
$(,)?
|
||||||
|
);
|
||||||
|
)*
|
||||||
|
) => {
|
||||||
|
impl Packet {
|
||||||
|
$(
|
||||||
|
pub fn $fn_name(
|
||||||
|
$(
|
||||||
|
$name: ssh_type_to_rust::$ssh_type
|
||||||
|
),*
|
||||||
|
) -> Packet {
|
||||||
|
let mut w = Writer::new();
|
||||||
|
|
||||||
|
w.u8(Packet::$msg_type);
|
||||||
|
|
||||||
|
$(
|
||||||
|
w.$ssh_type($name);
|
||||||
|
)*
|
||||||
|
|
||||||
|
Packet {
|
||||||
|
payload: w.finish(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
ctors! {
|
||||||
|
// -----
|
||||||
|
// Transport layer protocol:
|
||||||
|
|
||||||
|
// 1 to 19 Transport layer generic (e.g., disconnect, ignore, debug, etc.)
|
||||||
|
// 20 to 29 Algorithm negotiation
|
||||||
|
// 30 to 49 Key exchange method specific (numbers can be reused for different authentication methods)
|
||||||
|
|
||||||
|
// -----
|
||||||
|
// User authentication protocol:
|
||||||
|
|
||||||
|
// 50 to 59 User authentication generic
|
||||||
|
fn new_msg_userauth_failure(SSH_MSG_USERAUTH_FAILURE;
|
||||||
|
auth_options: name_list,
|
||||||
|
partial_success: bool,
|
||||||
|
);
|
||||||
|
fn new_msg_userauth_success(SSH_MSG_USERAUTH_SUCCESS;);
|
||||||
|
fn new_msg_userauth_banner(SSH_MSG_USERAUTH_BANNER; msg: string, language_tag: string);
|
||||||
|
|
||||||
|
// 60 to 79 User authentication method specific (numbers can be reused for different authentication methods)
|
||||||
|
|
||||||
|
// -----
|
||||||
|
// Connection protocol:
|
||||||
|
|
||||||
|
// 80 to 89 Connection protocol generic
|
||||||
|
fn new_msg_request_failure(SSH_MSG_REQUEST_FAILURE;);
|
||||||
|
|
||||||
|
// 90 to 127 Channel related messages
|
||||||
|
fn new_msg_channel_open_confirmation(SSH_MSG_CHANNEL_OPEN_CONFIRMATION;
|
||||||
|
peer_channel: u32,
|
||||||
|
sender_channel: u32,
|
||||||
|
initial_window_size: u32,
|
||||||
|
max_packet_size: u32,
|
||||||
|
);
|
||||||
|
fn new_msg_channel_open_failure(SSH_MSG_CHANNEL_OPEN_FAILURE;
|
||||||
|
sender_channe: u32,
|
||||||
|
reason_code: u32,
|
||||||
|
description: string,
|
||||||
|
language_tag: string,
|
||||||
|
);
|
||||||
|
fn new_msg_channel_data(SSH_MSG_CHANNEL_DATA; recipient_channel: 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);
|
||||||
|
fn new_msg_channel_success(SSH_MSG_CHANNEL_SUCCESS; recipient_channel: u32);
|
||||||
|
fn new_msg_channel_failure(SSH_MSG_CHANNEL_FAILURE; recipient_channel: u32);
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue