Server and client SSH library, based on ring for its crypto, and tokio/futures for its network management. More information at pijul.org/thrussh.
Here is an example client and server:
xtern crate thrussh;
xtern crate futures;
xtern crate tokio_core;
xtern crate env_logger;
se std::sync::Arc;
se thrussh::*;
[derive(Clone)]
truct H{}
mpl server::Handler for H {
type Error = ();
type FutureAuth = futures::Finished<(Self, server::Auth), Self::Error>;
type FutureUnit = futures::Finished<(Self, server::Session), Self::Error>;
type FutureBool = futures::Finished<(Self, server::Session, bool), Self::Error>;
fn auth_publickey(mut self, _: &str, _: &key::PublicKey) -> Self::FutureAuth {
futures::finished((self, server::Auth::Accept))
}
fn data(mut self, channel: ChannelId, data: &[u8], mut session: server::Session) -> Self::FutureUnit {
println!("data on channel {:?}: {:?}", channel, std::str::from_utf8(data));
session.data(channel, None, data).unwrap();
futures::finished((self, session))
}
se std::net::ToSocketAddrs;
se futures::Future;
se tokio_core::net::TcpStream;
se tokio_core::reactor::Core;
truct Client { }
mpl client::Handler for Client {
type Error = ();
type FutureBool = futures::Finished<(Self, bool), Self::Error>;
type FutureUnit = futures::Finished<Self, Self::Error>;
type SessionUnit = futures::Finished<(Self, client::Session), Self::Error>;
fn check_server_key(mut self, server_public_key: &key::PublicKey) -> Self::FutureBool {
println!("check_server_key: {:?}", server_public_key);
futures::finished((self, true))
}
fn channel_open_confirmation(mut self, channel: ChannelId, session: client::Session) -> Self::SessionUnit {
println!("channel_open_confirmation: {:?}", channel);
futures::finished((self, session))
}
fn data(mut self, channel: ChannelId, ext: Option<u32>, data: &[u8], session: client::Session) -> Self::SessionUnit {
println!("data on channel {:?} {:?}: {:?}", ext, channel, std::str::from_utf8(data));
futures::finished((self, session))
}
mpl Client {
fn run(self, config: Arc<client::Config>, addr: &str) {
let addr = addr.to_socket_addrs().unwrap().next().unwrap();
let mut l = Core::new().unwrap();
let handle = l.handle();
let done =
TcpStream::connect(&addr, &handle).map_err(|err| HandlerError::Error(thrussh::Error::IO(err))).and_then(|socket| {
println!("connected");
let mut connection = client::Connection::new(
config.clone(),
socket,
self,
None
).unwrap();
let key = thrussh::load_secret_key("/home/pe/.ssh/id_ed25519").unwrap();
connection.authenticate_key("pe", key).and_then(|connection| {
connection.channel_open_session().and_then(move |(mut connection, chan)| {
connection.data(chan, None, b"First test").and_then(move |(connection, _)| {
connection.data(chan, None, b"Second test").and_then(move |(mut connection, _)| {
connection.disconnect(Disconnect::ByApplication, "Ciao", "");
connection
})
})
})
})
});
l.run(done).unwrap();
}
n main() {
env_logger::init().unwrap();
// Starting the server thread.
let t = std::thread::spawn(|| {
let mut config = thrussh::server::Config::default();
config.connection_timeout = Some(std::time::Duration::from_secs(600));
config.auth_rejection_time = std::time::Duration::from_secs(3);
config.keys.push(thrussh::key::Algorithm::generate_keypair(thrussh::key::ED25519).unwrap());
let config = Arc::new(config);
let sh = H{};
thrussh::server::run(config, "0.0.0.0:2222", sh);
});
std::thread::sleep(std::time::Duration::from_secs(1));
let mut config = thrussh::client::Config::default();
config.connection_timeout = Some(std::time::Duration::from_secs(600));
let config = Arc::new(config);
let sh = Client {};
sh.run(config, "127.0.0.1:2222");
// Kill the server thread after the client has ended.
std::mem::forget(t)