From 16c57380d7a539677524b62f2ddcbb6169bf1297 Mon Sep 17 00:00:00 2001 From: Thomas Gatzweiler Date: Sat, 15 Jul 2017 19:59:55 +0200 Subject: [PATCH] Rename Session to Connection --- src/{session.rs => connection.rs} | 89 ++++++++++++++++++++++++------- src/key_exchange/mod.rs | 1 - src/lib.rs | 3 +- src/protocol.rs | 21 -------- src/server.rs | 42 ++++++++------- 5 files changed, 93 insertions(+), 63 deletions(-) rename src/{session.rs => connection.rs} (61%) delete mode 100644 src/protocol.rs diff --git a/src/session.rs b/src/connection.rs similarity index 61% rename from src/session.rs rename to src/connection.rs index 941e030..3e5e98f 100644 --- a/src/session.rs +++ b/src/connection.rs @@ -1,55 +1,102 @@ +use std::io::{self, BufRead, BufReader, Read, Write}; + use key_exchange::{self, KeyExchange, KeyExchangeResult}; use message::MessageType; use packet::{Packet, ReadPacketExt, WritePacketExt}; -use std::io::Write; +use public_key::KeyPair; #[derive(PartialEq)] -enum SessionState { +enum ConnectionState { Initial, KeyExchange, Established, } #[derive(PartialEq)] -pub enum SessionType { +pub enum ConnectionType { Server, Client, } -pub struct Session { - stype: SessionType, - state: SessionState, +pub struct Connection { + ctype: ConnectionType, + state: ConnectionState, key_exchange: Option>, stream: W, + my_id: String, + peer_id: Option, } -impl Session { - pub fn new(stype: SessionType, stream: W) -> Session { - Session { - stype: stype, - state: SessionState::Initial, +impl Connection { + pub fn new(ctype: ConnectionType, stream: W) -> Connection { + Connection { + ctype: ctype, + state: ConnectionState::Initial, key_exchange: None, stream: stream, + my_id: format!( + "SSH-2.0-RedoxSSH_{}\r\n", + env!("CARGO_PKG_VERSION") + ), + peer_id: None, } } + pub fn run(&mut self, mut stream: &mut Read) -> io::Result<()> { + self.stream.write(self.my_id.as_bytes())?; + self.peer_id = Some(self.read_id(stream)?); + + if let Some(ref peer_id) = self.peer_id { + println!("Identifies as {:?}", peer_id); + } + + loop { + let packet = Packet::read_from(&mut stream).unwrap(); + println!("packet: {:?}", packet); + self.process(&packet); + } + } + + fn read_id(&mut self, stream: &mut Read) -> io::Result { + // The identification string has a maximum length of 255 bytes + // TODO: Make sure to stop reading if the client sends too much + + let mut reader = BufReader::new(stream); + let mut id = String::new(); + + while !id.starts_with("SSH-") { + reader.read_line(&mut id)?; + } + + Ok(id.trim_right().to_owned()) + } + pub fn process(&mut self, packet: &Packet) { - match packet.msg_type() { + match packet.msg_type() + { MessageType::KexInit => { println!("Starting Key Exchange!"); self.kex_init(packet); } MessageType::KeyExchange(_) => { if let Some(ref mut kex) = self.key_exchange { - match kex.process(packet) { - KeyExchangeResult::Ok(Some(packet)) => { packet.write_to(&mut self.stream); }, - KeyExchangeResult::Error(Some(packet)) => { packet.write_to(&mut self.stream); }, - KeyExchangeResult::Done(Some(packet)) => { packet.write_to(&mut self.stream); }, + match kex.process(packet) + { + KeyExchangeResult::Ok(Some(packet)) => { + packet.write_to(&mut self.stream); + } + KeyExchangeResult::Error(Some(packet)) => { + packet.write_to(&mut self.stream); + } + KeyExchangeResult::Done(Some(packet)) => { + packet.write_to(&mut self.stream); + } KeyExchangeResult::Ok(None) | KeyExchangeResult::Error(None) | KeyExchangeResult::Done(None) => {} }; - } else { + } + else { warn!("Received KeyExchange packet without KexInit"); } } @@ -74,10 +121,12 @@ impl Session { let comp_algos_s2c = reader.read_enum_list::(); let kex_algo = negotiate(KEY_EXCHANGE, kex_algos.unwrap().as_slice()); - let srv_host_key_algo = negotiate(HOST_KEY, srv_host_key_algos.unwrap().as_slice()); + let srv_host_key_algo = + negotiate(HOST_KEY, srv_host_key_algos.unwrap().as_slice()); let enc_algo = negotiate(ENCRYPTION, enc_algos_s2c.unwrap().as_slice()); let mac_algo = negotiate(MAC, mac_algos_s2c.unwrap().as_slice()); - let comp_algo = negotiate(COMPRESSION, comp_algos_s2c.unwrap().as_slice()); + let comp_algo = + negotiate(COMPRESSION, comp_algos_s2c.unwrap().as_slice()); println!("Negotiated Kex Algorithm: {:?}", kex_algo); println!("Negotiated Host Key Algorithm: {:?}", srv_host_key_algo); @@ -107,7 +156,7 @@ impl Session { Ok(()) }); - self.state = SessionState::KeyExchange; + self.state = ConnectionState::KeyExchange; self.key_exchange = Some(Box::new(key_exchange::Curve25519::new())); packet.write_to(&mut self.stream); } diff --git a/src/key_exchange/mod.rs b/src/key_exchange/mod.rs index c49f62c..15061cc 100644 --- a/src/key_exchange/mod.rs +++ b/src/key_exchange/mod.rs @@ -4,7 +4,6 @@ mod dh_group_sha1; pub use self::curve25519::Curve25519; pub use self::dh_group_sha1::DhGroupSha1; -use session::Session; use packet::Packet; pub enum KeyExchangeResult { diff --git a/src/lib.rs b/src/lib.rs index fda7cbe..7573ca8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,10 +6,9 @@ extern crate num_bigint; extern crate log; mod algorithm; -mod protocol; mod packet; mod message; -mod session; +mod connection; mod key_exchange; pub mod public_key; diff --git a/src/protocol.rs b/src/protocol.rs deleted file mode 100644 index d79d872..0000000 --- a/src/protocol.rs +++ /dev/null @@ -1,21 +0,0 @@ -use std::io::{Read, Write, BufReader, BufRead}; -use std::io; - -pub fn send_identification(stream: &mut W) -> io::Result { - let id = format!("SSH-2.0-RedoxSSH_{}\r\n", env!("CARGO_PKG_VERSION")); - stream.write(id.as_bytes()) -} - -pub fn read_identification(stream: &mut R) -> io::Result { - // The identification string has a maximum length of 255 bytes - // TODO: Make sure that we stop reading when the client sends more than that - - let mut reader = BufReader::new(stream); - let mut id = String::new(); - - while !id.starts_with("SSH-") { - reader.read_line(&mut id)?; - } - - Ok(id.trim_right().to_owned()) -} diff --git a/src/server.rs b/src/server.rs index 4467d29..baf020f 100644 --- a/src/server.rs +++ b/src/server.rs @@ -1,15 +1,15 @@ -use std::net::TcpListener; use std::io::{self, Write}; +use std::net::TcpListener; +use std::thread; -use session::{Session, SessionType}; +use connection::{Connection, ConnectionType}; use packet::Packet; use public_key::KeyPair; -use protocol; pub struct ServerConfig { pub host: String, pub port: u16, - pub key: Box + pub key: Box, } pub struct Server { @@ -22,28 +22,32 @@ impl Server { } pub fn run(&self) -> io::Result<()> { - let listener = TcpListener::bind((&*self.config.host, self.config.port)).expect(&*format!( + let listener = TcpListener::bind( + (&*self.config.host, self.config.port), + ).expect(&*format!( "sshd: failed to bind to {}:{}", self.config.host, self.config.port )); - let (mut stream, addr) = listener.accept().expect(&*format!( - "sshd: failed to establish incoming connection" - )); - - println!("Incoming connection from {}", addr); - protocol::send_identification(&mut stream)?; - - let id = protocol::read_identification(&mut stream)?; - println!("{} identifies as {}", addr, id); - - let mut session = Session::new(SessionType::Server, stream.try_clone().unwrap()); loop { - let packet = Packet::read_from(&mut stream).unwrap(); - println!("packet: {:?}", packet); - session.process(&packet); + let (mut stream, addr) = listener.accept().expect(&*format!( + "sshd: failed to establish incoming connection" + )); + + println!("Incoming connection from {}", addr); + + thread::spawn(move || { + let mut connection = Connection::new( + ConnectionType::Server, + stream.try_clone().unwrap(), + ); + + connection.run(&mut stream); + }); + } + Ok(()) } }