use std::collections::HashMap; use std::sync::Arc; use async_trait::async_trait; use rand_core::OsRng; use russh::keys::*; use russh::server::{Msg, Server as _, Session}; use russh::*; use russh_keys::Certificate; use tokio::sync::Mutex; #[tokio::main] async fn main() { env_logger::builder() .filter_level(log::LevelFilter::Debug) .init(); let config = russh::server::Config { inactivity_timeout: Some(std::time::Duration::from_secs(3600)), auth_rejection_time: std::time::Duration::from_secs(3), auth_rejection_time_initial: Some(std::time::Duration::from_secs(0)), keys: vec![ russh_keys::PrivateKey::random(&mut OsRng, russh_keys::Algorithm::Ed25519).unwrap(), ], preferred: Preferred { // key: Cow::Borrowed(&[CERT_ECDSA_SHA2_P256]), ..Preferred::default() }, ..Default::default() }; let config = Arc::new(config); let mut sh = Server { clients: Arc::new(Mutex::new(HashMap::new())), id: 0, }; sh.run_on_address(config, ("0.0.0.0", 2222)).await.unwrap(); } #[derive(Clone)] struct Server { clients: Arc>>, id: usize, } impl Server { async fn post(&mut self, data: CryptoVec) { let mut clients = self.clients.lock().await; for ((id, channel), ref mut s) in clients.iter_mut() { if *id != self.id { let _ = s.data(*channel, data.clone()).await; } } } } impl server::Server for Server { type Handler = Self; fn new_client(&mut self, _: Option) -> Self { let s = self.clone(); self.id += 1; s } fn handle_session_error(&mut self, _error: ::Error) { eprintln!("Session error: {:#?}", _error); } } #[async_trait] impl server::Handler for Server { type Error = russh::Error; async fn channel_open_session( &mut self, channel: Channel, session: &mut Session, ) -> Result { { let mut clients = self.clients.lock().await; clients.insert((self.id, channel.id()), session.handle()); } Ok(true) } async fn auth_publickey( &mut self, _: &str, _key: &ssh_key::PublicKey, ) -> Result { Ok(server::Auth::Accept) } async fn auth_openssh_certificate( &mut self, _user: &str, certificate: &Certificate, ) -> Result { dbg!(certificate); Ok(server::Auth::Accept) } async fn data( &mut self, channel: ChannelId, data: &[u8], session: &mut Session, ) -> Result<(), Self::Error> { // Sending Ctrl+C ends the session and disconnects the client if data == [3] { return Err(russh::Error::Disconnect); } let data = CryptoVec::from(format!("Got data: {}\r\n", String::from_utf8_lossy(data))); self.post(data.clone()).await; session.data(channel, data)?; Ok(()) } async fn tcpip_forward( &mut self, address: &str, port: &mut u32, session: &mut Session, ) -> Result { let handle = session.handle(); let address = address.to_string(); let port = *port; tokio::spawn(async move { let channel = handle .channel_open_forwarded_tcpip(address, port, "1.2.3.4", 1234) .await .unwrap(); let _ = channel.data(&b"Hello from a forwarded port"[..]).await; let _ = channel.eof().await; }); Ok(true) } }