This commit is contained in:
nora 2024-08-11 22:10:34 +02:00
parent 9c320c8b4c
commit ae5db1642c
5 changed files with 166 additions and 89 deletions

View file

@ -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

View file

@ -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,14 +111,10 @@ 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);
debug!("Channel has been closed"); debug!("Channel has been closed");
@ -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> {

View file

@ -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.

View file

@ -1,3 +1,5 @@
mod ctors;
use std::collections::VecDeque; use std::collections::VecDeque;
use crate::client_error; use crate::client_error;

View 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);
}