diff --git a/.gitignore b/.gitignore index ea8c4bf7f35f6f77f75d92ad8ce8349f6e81ddba..e2a3069b6ee98740d149140b881d6947483653c9 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /target +*~ diff --git a/async/examples/serv1.rs b/async/examples/serv1.rs new file mode 100644 index 0000000000000000000000000000000000000000..e8b2156aef999268bb596941e53aca02f24efa34 --- /dev/null +++ b/async/examples/serv1.rs @@ -0,0 +1,118 @@ +#[allow(unused_imports)] +use { + // crate::error::Error, + log::{debug, error, info, log, trace, warn}, +}; +use anyhow::{Context, Result, Error, bail}; +use pretty_hex::PrettyHex; + +use tokio::net::{TcpStream, TcpListener}; + +use std::{net::Ipv6Addr, io::Read}; + +use door_sshproto::*; +use door_async::{SSHServer, raw_pty}; + +use simplelog::*; +#[derive(argh::FromArgs)] +/** con1 + */ +struct Args { + #[argh(switch, short='v')] + /// verbose debug logging + debug: bool, + + #[argh(switch)] + /// more verbose + trace: bool, + + #[argh(option, short='p', default="22")] + /// port + port: u16, +} + +fn parse_args() -> Result<Args> { + let mut args: Args = argh::from_env(); + + Ok(args) +} + +fn main() -> Result<()> { + let args = parse_args()?; + + setup_log(&args)?; + + tokio::runtime::Builder::new_current_thread() + .enable_all() + .build() + .unwrap() + .block_on(async { + run(&args).await + }) + .map_err(|e| { + error!("Exit with error: {e:?}"); + e + }); + Ok(()) +} + +fn setup_log(args: &Args) -> Result<()> { + let mut conf = simplelog::ConfigBuilder::new(); + let conf = conf + .add_filter_allow_str("door") + .add_filter_allow_str("serv1") + // not debugging these bits of the stack at present + // .add_filter_ignore_str("door_sshproto::traffic") + // .add_filter_ignore_str("door_sshproto::runner") + // .add_filter_ignore_str("door_async::async_door") + .set_time_offset_to_local().expect("Couldn't get local timezone") + .build(); + + let level = if args.trace { + LevelFilter::Trace + } else if args.debug { + LevelFilter::Debug + } else { + LevelFilter::Warn + }; + + let mut logs: Vec<Box<dyn SharedLogger>> = vec![ + TermLogger::new(level, conf.clone(), TerminalMode::Mixed, ColorChoice::Auto), + ]; + + CombinedLogger::init(logs).unwrap(); + Ok(()) +} + +fn run_session<'a, R: Send>(scope: &'a moro::Scope<'a, '_, R>, stream: TcpStream) -> Result<()> { + let rxbuf = vec![0; 3000]; + // TODO: better lifetime rather than leaking + let rxbuf = Box::leak(Box::new(rxbuf)).as_mut_slice(); + let txbuf = vec![0; 3000]; + let txbuf = Box::leak(Box::new(txbuf)).as_mut_slice(); + + let mut serv = SSHServer::new(rxbuf, txbuf)?; + + scope.spawn(async { + + }); + Ok(()) + +} + +async fn run(args: &Args) -> Result<()> { + let listener = TcpListener::bind(("", args.port)).await?; + moro::async_scope!(|scope| { + scope.spawn(async { + loop { + let (stream, _) = listener.accept().await?; + + run_session(scope, stream)? + } + #[allow(unreachable_code)] + Ok::<_, anyhow::Error>(()) + }); + + }).await; + Ok(()) +} diff --git a/async/src/lib.rs b/async/src/lib.rs index 0bd2e20fb9794c352f4543262eb00b4f3b2def27..f802913b7b91609cf1aed93f89065a722ea51855 100644 --- a/async/src/lib.rs +++ b/async/src/lib.rs @@ -1,6 +1,7 @@ #![allow(unused_imports)] mod client; +mod server; mod async_door; mod async_channel; mod cmdline_client; @@ -8,6 +9,7 @@ mod pty; pub use async_door::AsyncDoor; pub use client::SSHClient; +pub use server::SSHServer; pub use cmdline_client::CmdlineClient; #[cfg(unix)] diff --git a/sshproto/src/behaviour.rs b/sshproto/src/behaviour.rs index f0ad10888a147f93a217be65602f4fe28ea3f809..de627f9a837f2f0c705df3cbe283fb4437d1e377 100644 --- a/sshproto/src/behaviour.rs +++ b/sshproto/src/behaviour.rs @@ -42,6 +42,10 @@ pub enum BhError { // Permit impl Trait in type aliases // https://github.com/rust-lang/rust/issues/63063 +// TODO: another interim option would to split the async trait methods +// into a separate trait (which impls the non-async trait) for a bit more +// DRY. + pub struct Behaviour<'a> { #[cfg(feature = "std")] inner: async_behaviour::AsyncCliServ<'a>, diff --git a/sshproto/src/conn.rs b/sshproto/src/conn.rs index de77fe7fc92c90d6133827f1bea14fcf926308e3..da464d5b8ccd934e83c2df40bf2683b63e71b80d 100644 --- a/sshproto/src/conn.rs +++ b/sshproto/src/conn.rs @@ -110,6 +110,10 @@ impl<'a> Conn<'a> { Self::new(ClientServer::Client(client::Client::new())) } + pub fn new_server() -> Result<Self> { + Self::new(ClientServer::Server(server::Server::new())) + } + fn new(cliserv: ClientServer) -> Result<Self, Error> { Ok(Conn { kex: kex::Kex::new()?, diff --git a/sshproto/src/runner.rs b/sshproto/src/runner.rs index ddae3a0e1a9b9477e16ac437659cf4841ce12713..19ade4a165282d83ad6fcd804a7c78ff5d852f35 100644 --- a/sshproto/src/runner.rs +++ b/sshproto/src/runner.rs @@ -46,6 +46,22 @@ impl<'a> Runner<'a> { Ok(runner) } + pub fn new_server( + inbuf: &'a mut [u8], + outbuf: &'a mut [u8], + ) -> Result<Runner<'a>, Error> { + let conn = Conn::new_server()?; + let runner = Runner { + conn, + traffic: traffic::Traffic::new(outbuf, inbuf), + keys: KeyState::new_cleartext(), + output_waker: None, + input_waker: None, + }; + + Ok(runner) + } + pub fn input(&mut self, buf: &[u8]) -> Result<usize, Error> { self.traffic.input( &mut self.keys, diff --git a/sshproto/src/servauth.rs b/sshproto/src/servauth.rs index 5919e4d9740091e3057856d4e0f2362f49c3c211..364658dbe636c4d746a75bb4b8957bba27cedd70 100644 --- a/sshproto/src/servauth.rs +++ b/sshproto/src/servauth.rs @@ -2,3 +2,10 @@ use crate::*; pub(crate) struct ServAuth { } + + +impl ServAuth { + pub fn new() -> Self { + Self {} + } +} diff --git a/sshproto/src/server.rs b/sshproto/src/server.rs index f16f2e3c2aac61fdaf994bcb9164d91604d97d03..a5077872ee1596b3975d812c8e752dbae71ebcde 100644 --- a/sshproto/src/server.rs +++ b/sshproto/src/server.rs @@ -4,3 +4,11 @@ use crate::servauth::ServAuth; pub(crate) struct Server { auth: ServAuth, } + +impl Server { + pub fn new() -> Self { + Server { + auth: ServAuth::new(), + } + } +}