From ae5db1642c94cbfe9072767064d8af1d6368f3ca Mon Sep 17 00:00:00 2001 From: Noratrieb <48135649+Noratrieb@users.noreply.github.com> Date: Sun, 11 Aug 2024 22:10:34 +0200 Subject: [PATCH] stuff --- src/main.rs | 2 + ssh-transport/src/channel.rs | 103 +++++++++++++----------------- ssh-transport/src/lib.rs | 55 ++++++++-------- ssh-transport/src/packet.rs | 2 + ssh-transport/src/packet/ctors.rs | 93 +++++++++++++++++++++++++++ 5 files changed, 166 insertions(+), 89 deletions(-) create mode 100644 ssh-transport/src/packet/ctors.rs diff --git a/src/main.rs b/src/main.rs index ad36772..88af154 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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() { conn.write_all(&msg.to_bytes()) .await diff --git a/ssh-transport/src/channel.rs b/ssh-transport/src/channel.rs index 1e2472e..c40c33c 100644 --- a/ssh-transport/src/channel.rs +++ b/ssh-transport/src/channel.rs @@ -9,6 +9,8 @@ use crate::Result; pub(crate) struct ServerChannelsState { packets_to_send: VecDeque, channels: Vec, + + channel_updates: VecDeque, } struct SessionChannel { @@ -20,11 +22,21 @@ struct SessionChannel { sent_bytes: Vec, } +pub struct ChannelUpdate { + pub channel: u32, + pub kind: ChannelUpdateKind, +} + +pub enum ChannelUpdateKind { + ChannelData(Vec), +} + impl ServerChannelsState { pub(crate) fn new() -> Self { ServerChannelsState { packets_to_send: VecDeque::new(), channels: Vec::new(), + channel_updates: VecDeque::new(), } } @@ -43,12 +55,13 @@ impl ServerChannelsState { "session" => { let our_number = self.channels.len() as u32; - let mut confirm = Writer::new(); - confirm.u8(Packet::SSH_MSG_CHANNEL_OPEN_CONFIRMATION); - confirm.u32(our_number); - confirm.u32(sender_channel); - confirm.u32(initial_window_size); - confirm.u32(max_packet_size); + self.packets_to_send + .push_back(Packet::new_msg_channel_open_confirmation( + our_number, + sender_channel, + initial_window_size, + max_packet_size, + )); self.channels.push(SessionChannel { we_closed: false, @@ -58,23 +71,16 @@ impl ServerChannelsState { sent_bytes: Vec::new(), }); - self.packets_to_send.push_back(Packet { - payload: confirm.finish(), - }); - debug!(?channel_type, ?our_number, "Successfully opened channel"); } _ => { - let mut failure = Writer::new(); - failure.u8(Packet::SSH_MSG_CHANNEL_OPEN_FAILURE); - failure.u32(sender_channel); - failure.u32(3); // SSH_OPEN_UNKNOWN_CHANNEL_TYPE - failure.string(b"unknown channel type"); - failure.string(b""); - - self.packets_to_send.push_back(Packet { - payload: failure.finish(), - }); + self.packets_to_send + .push_back(Packet::new_msg_channel_open_failure( + sender_channel, + 3, // SSH_OPEN_UNKNOWN_CHANNEL_TYPE + b"unknown channel type", + b"", + )); } } } @@ -83,33 +89,18 @@ 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); // echo :3 - self.packets_to_send.push_back(Packet { - payload: reply.finish(), - }); + let peer = channel.peer_channel; + // echo :3 + self.packets_to_send + .push_back(Packet::new_msg_channel_data(peer, data)); if data.contains(&0x03 /*EOF, Ctrl-C*/) { debug!(?our_channel, "Received EOF, closing channel"); // - 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(), - }); + self.packets_to_send + .push_back(Packet::new_msg_channel_close(peer)); let channel = self.channel(our_channel)?; channel.we_closed = true; @@ -120,14 +111,10 @@ impl ServerChannelsState { 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(), - }); + let close = Packet::new_msg_channel_close(channel.peer_channel); + self.packets_to_send.push_back(close); } - + self.channels.remove(our_channel as usize); debug!("Channel has been closed"); @@ -203,22 +190,18 @@ impl ServerChannelsState { self.packets_to_send.drain(..) } + pub(crate) fn channel_updates(&mut self) -> impl Iterator + '_ { + self.channel_updates.drain(..) + } + fn send_channel_success(&mut self, recipient_channel: u32) { - let mut failure = Writer::new(); - failure.u8(Packet::SSH_MSG_CHANNEL_SUCCESS); - failure.u32(recipient_channel); - self.packets_to_send.push_back(Packet { - payload: failure.finish(), - }); + self.packets_to_send + .push_back(Packet::new_msg_channel_success(recipient_channel)); } fn send_channel_failure(&mut self, recipient_channel: u32) { - let mut failure = Writer::new(); - failure.u8(Packet::SSH_MSG_CHANNEL_FAILURE); - failure.u32(recipient_channel); - self.packets_to_send.push_back(Packet { - payload: failure.finish(), - }); + self.packets_to_send + .push_back(Packet::new_msg_channel_failure(recipient_channel)); } fn channel(&mut self, number: u32) -> Result<&mut SessionChannel> { diff --git a/ssh-transport/src/lib.rs b/ssh-transport/src/lib.rs index c147adf..1be2b3c 100644 --- a/ssh-transport/src/lib.rs +++ b/ssh-transport/src/lib.rs @@ -18,6 +18,7 @@ use sha2::Digest; use tracing::{debug, info, trace}; use x25519_dalek::{EphemeralSecret, PublicKey}; +pub use channel::ChannelUpdate; pub use packet::Msg; #[derive(Debug)] @@ -50,6 +51,8 @@ pub struct ServerConnection { state: ServerState, packet_transport: PacketTransport, rng: Box, + + channel_updates: VecDeque, } enum ServerState { @@ -118,6 +121,7 @@ impl ServerConnection { }, packet_transport: PacketTransport::new(), rng: Box::new(rng), + channel_updates: VecDeque::new(), } } } @@ -399,21 +403,16 @@ impl ServerConnection { info!(?password, "Got password"); // Don't worry queen, your password is correct! - let mut success = Writer::new(); - success.u8(Packet::SSH_MSG_USERAUTH_SUCCESS); - self.packet_transport.queue_packet(Packet { - payload: success.finish(), - }); + self.packet_transport + .queue_packet(Packet::new_msg_userauth_success()); + self.state = ServerState::ConnectionOpen(ServerChannelsState::new()); } "publickey" => { info!("Got public key"); // Don't worry queen, your key is correct! - let mut success = Writer::new(); - success.u8(Packet::SSH_MSG_USERAUTH_SUCCESS); - self.packet_transport.queue_packet(Packet { - payload: success.finish(), - }); + self.packet_transport + .queue_packet(Packet::new_msg_userauth_success()); self.state = ServerState::ConnectionOpen(ServerChannelsState::new()); } _ if *has_failed => { @@ -424,21 +423,17 @@ impl ServerConnection { _ => { // Initial. - 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""); - self.packet_transport.queue_packet(Packet { - payload: banner.finish(), - }); + self.packet_transport.queue_packet(Packet::new_msg_userauth_banner( + 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", + b"", + )); - let mut rejection = Writer::new(); - rejection.u8(Packet::SSH_MSG_USERAUTH_FAILURE); - rejection.name_list(NameList::one("publickey")); - rejection.bool(false); - self.packet_transport.queue_packet(Packet { - payload: rejection.finish(), - }); + self.packet_transport + .queue_packet(Packet::new_msg_userauth_failure( + NameList::one("publickey"), + false, + )); // Stay in the same state } } @@ -454,17 +449,15 @@ impl ServerConnection { for packet in con.packets_to_send() { self.packet_transport.queue_packet(packet); } + self.channel_updates.extend(con.channel_updates()); } Packet::SSH_MSG_GLOBAL_REQUEST => { let request_name = payload.utf8_string()?; let want_reply = payload.bool()?; debug!(?request_name, ?want_reply, "Received global request"); - 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::new_msg_request_failure()); } _ => { todo!("packet: {packet_type}"); @@ -479,6 +472,10 @@ impl ServerConnection { pub fn next_msg_to_send(&mut self) -> Option { self.packet_transport.next_msg_to_send() } + + pub fn next_channel_update(&mut self) -> Option { + self.channel_updates.pop_front() + } } // hardcoded test keys. lol. diff --git a/ssh-transport/src/packet.rs b/ssh-transport/src/packet.rs index 80f8598..ddec272 100644 --- a/ssh-transport/src/packet.rs +++ b/ssh-transport/src/packet.rs @@ -1,3 +1,5 @@ +mod ctors; + use std::collections::VecDeque; use crate::client_error; diff --git a/ssh-transport/src/packet/ctors.rs b/ssh-transport/src/packet/ctors.rs new file mode 100644 index 0000000..b443037 --- /dev/null +++ b/ssh-transport/src/packet/ctors.rs @@ -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); +}