diff --git a/src/client.rs b/src/client.rs index fbe85dc..d46296d 100644 --- a/src/client.rs +++ b/src/client.rs @@ -9,6 +9,7 @@ use error_stack::{report, Report, ResultExt}; use std::fmt::Display; use std::str::FromStr; use thiserror::Error; +use tracing::Instrument; pub async fn hush(base_config: ClientConfiguration) -> error_stack::Result<(), OperationalError> { match base_config.command() { @@ -99,34 +100,43 @@ async fn connect( .connect(resolver, 22) .await .change_context(OperationalError::Connection)?; + let stream_span = tracing::debug_span!( + "client connection", + server = %stream.peer_addr().map(|x| x.to_string()).unwrap_or_else(|_| "".to_string()), + client = %stream.local_addr().map(|x| x.to_string()).unwrap_or_else(|_| "".to_string()), + ); - let _preamble = ssh::Preamble::read(&mut stream) + let their_preamble = ssh::Preamble::read(&mut stream) + .instrument(stream_span.clone()) .await .change_context(OperationalError::Connection)?; - // if !commentary.is_empty() { - // tracing::debug!(?commentary, "Server sent commentary."); - // } - // if !pre_message.is_empty() { - // for line in pre_message.lines() { - // tracing::debug!(?line, "Server sent prefix line."); - // } - // } - // - // let my_info = format!( - // "SSH-2.0-{}_{}\r\n", - // env!("CARGO_PKG_NAME"), - // env!("CARGO_PKG_VERSION") - // ); - // connection - // .write_all(my_info.as_bytes()) - // .await - // .map_err(OperationalError::WriteBanner)?; - // - // assert_eq!(4096, read_buffer.len()); - // read_buffer.fill(0); - // - // let mut stream = SshChannel::new(connection); + let our_preamble = ssh::Preamble::default() + .write(&mut stream) + .instrument(stream_span) + .await + .change_context(OperationalError::Connection)?; + + if !their_preamble.preamble.is_empty() { + for line in their_preamble.preamble.lines() { + tracing::info!("server: {}", line); + } + } + + tracing::info!( + software = ?their_preamble.software_name, + version = ?their_preamble.software_version, + commentary = ?their_preamble.commentary, + "received server preamble" + ); + + let mut stream = ssh::SshChannel::new(stream); + let their_initial = stream + .read() + .await + .attach_printable_lazy(stream_error_info) + .change_context(OperationalError::KeyExchange)? + .ok_or_else(); // let mut rng = rand::thread_rng(); // // let packet = stream diff --git a/src/operational_error.rs b/src/operational_error.rs index f0df143..557810a 100644 --- a/src/operational_error.rs +++ b/src/operational_error.rs @@ -7,6 +7,8 @@ pub enum OperationalError { ConfigurationError, #[error("Failed to connect to target address")] Connection, + #[error("Failure during key exchange / agreement protocol")] + KeyExchange, #[error("Failed to complete initial read: {0}")] InitialRead(std::io::Error), #[error("SSH banner was not formatted in UTF-8: {0}")] diff --git a/src/ssh.rs b/src/ssh.rs index 946d957..7f09015 100644 --- a/src/ssh.rs +++ b/src/ssh.rs @@ -3,6 +3,7 @@ mod message_ids; mod packets; mod preamble; +pub use channel::SshChannel; pub use message_ids::SshMessageID; pub use packets::SshKeyExchangeProcessingError; pub use preamble::Preamble; diff --git a/src/ssh/preamble.rs b/src/ssh/preamble.rs index ad830bf..3baf51e 100644 --- a/src/ssh/preamble.rs +++ b/src/ssh/preamble.rs @@ -6,10 +6,10 @@ use tokio::io::{AsyncReadExt, AsyncWriteExt}; #[derive(Debug, PartialEq)] pub struct Preamble { - preamble: String, - software_name: String, - software_version: String, - commentary: String, + pub preamble: String, + pub software_name: String, + pub software_version: String, + pub commentary: String, } impl Arbitrary for Preamble {