lnk_thrussh/
lib.rs

1// Copyright 2016 Pierre-Étienne Meunier
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14//
15
16//! Server and client SSH asynchronous library, based on tokio/futures.
17//!
18//! The normal way to use this library, both for clients and for
19//! servers, is by creating *handlers*, i.e. types that implement
20//! `client::Handler` for clients and `server::Handler` for
21//! servers.
22//!
23//! # Writing servers
24//!
25//! In the specific case of servers, a server must implement
26//! `server::Server`, a trait for creating new `server::Handler`.  The
27//! main type to look at in the `server` module is `Session` (and
28//! `Config`, of course).
29//!
30//! Here is an example server, which forwards input from each client
31//! to all other clients:
32//!
33//! ```
34//! extern crate lnk_thrussh;
35//! extern crate lnk_thrussh_keys;
36//! extern crate futures;
37//! extern crate tokio;
38//! use std::sync::{Mutex, Arc};
39//! use lnk_thrussh::*;
40//! use lnk_thrussh::server::{Auth, Session};
41//! use lnk_thrussh_keys::*;
42//! use std::collections::HashMap;
43//! use futures::Future;
44//!
45//! #[tokio::main]
46//! async fn main() {
47//!     let client_key = lnk_thrussh_keys::key::KeyPair::generate_ed25519().unwrap();
48//!     let client_pubkey = Arc::new(client_key.clone_public_key());
49//!     let mut config = lnk_thrussh::server::Config::default();
50//!     config.connection_timeout = Some(std::time::Duration::from_secs(3));
51//!     config.auth_rejection_time = std::time::Duration::from_secs(3);
52//!     config.keys.push(lnk_thrussh_keys::key::KeyPair::generate_ed25519().unwrap());
53//!     let config = Arc::new(config);
54//!     let sh = Server{
55//!         client_pubkey,
56//!         clients: Arc::new(Mutex::new(HashMap::new())),
57//!         id: 0
58//!     };
59//!     tokio::time::timeout(
60//!        std::time::Duration::from_secs(1),
61//!        lnk_thrussh::server::run(config, "0.0.0.0:2222", sh)
62//!     ).await.unwrap_or(Ok(()));
63//! }
64//!
65//! #[derive(Clone)]
66//! struct Server {
67//!     client_pubkey: Arc<lnk_thrussh_keys::key::PublicKey>,
68//!     clients: Arc<Mutex<HashMap<(usize, ChannelId), lnk_thrussh::server::Handle>>>,
69//!     id: usize,
70//! }
71//!
72//! impl server::Server for Server {
73//!     type Handler = Self;
74//!     fn new(&mut self, _: Option<std::net::SocketAddr>) -> Self {
75//!         let s = self.clone();
76//!         self.id += 1;
77//!         s
78//!     }
79//! }
80//!
81//! impl server::Handler for Server {
82//!     type Error = anyhow::Error;
83//!     type FutureAuth = futures::future::Ready<Result<(Self, server::Auth), anyhow::Error>>;
84//!     type FutureUnit = futures::future::Ready<Result<(Self, Session), anyhow::Error>>;
85//!     type FutureBool = futures::future::Ready<Result<(Self, Session, bool), anyhow::Error>>;
86//!
87//!     fn finished_auth(mut self, auth: Auth) -> Self::FutureAuth {
88//!         futures::future::ready(Ok((self, auth)))
89//!     }
90//!     fn finished_bool(self, b: bool, s: Session) -> Self::FutureBool {
91//!         futures::future::ready(Ok((self, s, b)))
92//!     }
93//!     fn finished(self, s: Session) -> Self::FutureUnit {
94//!         futures::future::ready(Ok((self, s)))
95//!     }
96//!     fn channel_open_session(self, channel: ChannelId, session: Session) -> Self::FutureUnit {
97//!         {
98//!             let mut clients = self.clients.lock().unwrap();
99//!             clients.insert((self.id, channel), session.handle());
100//!         }
101//!         self.finished(session)
102//!     }
103//!     fn auth_publickey(self, _: &str, _: &key::PublicKey) -> Self::FutureAuth {
104//!         self.finished_auth(server::Auth::Accept)
105//!     }
106//!     fn data(self, channel: ChannelId, data: &[u8], mut session: Session) -> Self::FutureUnit {
107//!         {
108//!             let mut clients = self.clients.lock().unwrap();
109//!             for ((id, channel), ref mut s) in clients.iter_mut() {
110//!                 if *id != self.id {
111//!                     s.data(*channel, CryptoVec::from_slice(data));
112//!                 }
113//!             }
114//!         }
115//!         session.data(channel, CryptoVec::from_slice(data));
116//!         self.finished(session)
117//!     }
118//! }
119//! ```
120//!
121//! Note the call to `session.handle()`, which allows to keep a handle
122//! to a client outside the event loop. This feature is internally
123//! implemented using `futures::sync::mpsc` channels.
124//!
125//! Note that this is just a toy server. In particular:
126//!
127//! - It doesn't handle errors when `s.data` returns an error,
128//!   i.e. when the client has disappeared
129//!
130//! - Each new connection increments the `id` field. Even though we
131//! would need a lot of connections per second for a very long time to
132//! saturate it, there are probably better ways to handle this to
133//! avoid collisions.
134//!
135//!
136//! # Implementing clients
137//!
138//! Maybe surprisingly, the data types used by Thrussh to implement
139//! clients are relatively more complicated than for servers. This is
140//! mostly related to the fact that clients are generally used both in
141//! a synchronous way (in the case of SSH, we can think of sending a
142//! shell command), and asynchronously (because the server may send
143//! unsollicited messages), and hence need to handle multiple
144//! interfaces.
145//!
146//! The important types in the `client` module are `Session` and
147//! `Connection`. A `Connection` is typically used to send commands to
148//! the server and wait for responses, and contains a `Session`. The
149//! `Session` is passed to the `Handler` when the client receives
150//! data.
151//!
152//! ```no_run
153//!extern crate lnk_thrussh;
154//!extern crate lnk_thrussh_keys;
155//!extern crate futures;
156//!extern crate tokio;
157//!extern crate env_logger;
158//!use std::sync::Arc;
159//!use lnk_thrussh::*;
160//!use lnk_thrussh::server::{Auth, Session};
161//!use lnk_thrussh_keys::*;
162//!use futures::Future;
163//!use std::io::Read;
164//!
165//!
166//!struct Client {
167//!}
168//!
169//!impl client::Handler for Client {
170//!    type Error = anyhow::Error;
171//!    type FutureUnit = futures::future::Ready<Result<(Self, client::Session), anyhow::Error>>;
172//!    type FutureBool = futures::future::Ready<Result<(Self, bool), anyhow::Error>>;
173//!
174//!    fn finished_bool(self, b: bool) -> Self::FutureBool {
175//!        futures::future::ready(Ok((self, b)))
176//!    }
177//!    fn finished(self, session: client::Session) -> Self::FutureUnit {
178//!        futures::future::ready(Ok((self, session)))
179//!    }
180//!    fn check_server_key(self, server_public_key: &key::PublicKey) -> Self::FutureBool {
181//!        println!("check_server_key: {:?}", server_public_key);
182//!        self.finished_bool(true)
183//!    }
184//!    fn channel_open_confirmation(self, channel: ChannelId, max_packet_size: u32, window_size: u32, session: client::Session) -> Self::FutureUnit {
185//!        println!("channel_open_confirmation: {:?}", channel);
186//!        self.finished(session)
187//!    }
188//!    fn data(self, channel: ChannelId, data: &[u8], session: client::Session) -> Self::FutureUnit {
189//!        println!("data on channel {:?}: {:?}", channel, std::str::from_utf8(data));
190//!        self.finished(session)
191//!    }
192//!}
193//!
194//! #[tokio::main]
195//! async fn main() {
196//!   use lnk_thrussh_agent::client::ClientStream as _;
197//!
198//!   let config = lnk_thrussh::client::Config::default();
199//!   let config = Arc::new(config);
200//!   let sh = Client{};
201//!
202//!   let key = lnk_thrussh_keys::key::KeyPair::generate_ed25519().unwrap();
203//!   let mut agent = lnk_thrussh_agent::client::tokio::UnixStream::connect_env().await.unwrap();
204//!   agent.add_identity(&key, &[]).await.unwrap();
205//!   let mut session = lnk_thrussh::client::connect(config, "localhost:22", sh).await.unwrap();
206//!   if session.authenticate_future(std::env::var("USER").unwrap(), key.clone_public_key(), agent).await.1.unwrap() {
207//!     let mut channel = session.channel_open_session().await.unwrap();
208//!     channel.data(&b"Hello, world!"[..]).await.unwrap();
209//!     if let Some(msg) = channel.wait().await {
210//!         println!("{:?}", msg)
211//!     }
212//!   }
213//! }
214//! ```
215//! # Using non-socket IO / writing tunnels
216//!
217//! The easy way to implement SSH tunnels, like `ProxyCommand` for
218//! OpenSSH, is to use the `thrussh-config` crate, and use the
219//! `Stream::tcp_connect` or `Stream::proxy_command` methods of that
220//! crate. That crate is a very lightweight layer above Thrussh, only
221//! implementing for external commands the traits used for sockets.
222//!
223//! # The SSH protocol
224//!
225//! If we exclude the key exchange and authentication phases, handled
226//! by Thrussh behind the scenes, the rest of the SSH protocol is
227//! relatively simple: clients and servers open *channels*, which are
228//! just integers used to handle multiple requests in parallel in a
229//! single connection. Once a client has obtained a `ChannelId` by
230//! calling one the many `channel_open_…` methods of
231//! `client::Connection`, the client may send exec requests and data
232//! to the server.
233//!
234//! A simple client just asking the server to run one command will
235//! usually start by calling
236//! `client::Connection::channel_open_session`, then
237//! `client::Connection::exec`, then possibly
238//! `client::Connection::data` a number of times to send data to the
239//! command's standard input, and finally `Connection::channel_eof`
240//! and `Connection::channel_close`.
241//!
242//! # Design principles
243//!
244//! The main goal of this library is conciseness, and reduced size and
245//! readability of the library's code. Moreover, this library is split
246//! between Thrussh, which implements the main logic of SSH clients
247//! and servers, and Thrussh-keys, which implements calls to
248//! cryptographic primitives.
249//!
250//! One non-goal is to implement all possible cryptographic algorithms
251//! published since the initial release of SSH. Technical debt is
252//! easily acquired, and we would need a very strong reason to go
253//! against this principle. If you are designing a system from
254//! scratch, we urge you to consider recent cryptographic primitives
255//! such as Ed25519 for public key cryptography, and Chacha20-Poly1305
256//! for symmetric cryptography and MAC.
257//!
258//! # Internal details of the event loop
259//!
260//! It might seem a little odd that the read/write methods for server
261//! or client sessions often return neither `Result` nor
262//! `Future`. This is because the data sent to the remote side is
263//! buffered, because it needs to be encrypted first, and encryption
264//! works on buffers, and for many algorithms, not in place.
265//!
266//! Hence, the event loop keeps waiting for incoming packets, reacts
267//! to them by calling the provided `Handler`, which fills some
268//! buffers. If the buffers are non-empty, the event loop then sends
269//! them to the socket, flushes the socket, empties the buffers and
270//! starts again. In the special case of the server, unsollicited
271//! messages sent through a `server::Handle` are processed when there
272//! is no incoming packet to read.
273//!
274#[macro_use]
275extern crate bitflags;
276#[macro_use]
277extern crate log;
278extern crate lnk_thrussh_libsodium as sodium;
279#[macro_use]
280extern crate thiserror;
281
282pub use lnk_cryptovec::CryptoVec;
283mod auth;
284mod cipher;
285mod compression;
286mod kex;
287mod key;
288mod msg;
289mod negotiation;
290mod ssh_read;
291mod sshbuffer;
292
293pub use negotiation::{Named, Preferred};
294mod pty;
295pub use pty::Pty;
296
297macro_rules! push_packet {
298    ( $buffer:expr, $x:expr ) => {{
299        use byteorder::{BigEndian, ByteOrder};
300        let i0 = $buffer.len();
301        $buffer.extend(b"\0\0\0\0");
302        let x = $x;
303        let i1 = $buffer.len();
304        use std::ops::DerefMut;
305        let buf = $buffer.deref_mut();
306        BigEndian::write_u32(&mut buf[i0..], (i1 - i0 - 4) as u32);
307        x
308    }};
309}
310
311type Sha256Hash =
312    generic_array::GenericArray<u8, <sha2::Sha256 as digest::FixedOutputDirty>::OutputSize>;
313
314mod session;
315
316/// Server side of this library.
317pub mod server;
318
319/// Client side of this library.
320pub mod client;
321
322#[derive(Debug, Error)]
323pub enum Error {
324    /// The key file could not be parsed.
325    #[error("Could not read key")]
326    CouldNotReadKey,
327
328    /// Unspecified problem with the beginning of key exchange.
329    #[error("Key exchange init failed")]
330    KexInit,
331
332    /// No common key exchange algorithm.
333    #[error("No common key exchange algorithm")]
334    NoCommonKexAlgo,
335
336    /// No common signature algorithm.
337    #[error("No common key algorithm")]
338    NoCommonKeyAlgo,
339
340    /// No common cipher.
341    #[error("No common key cipher")]
342    NoCommonCipher,
343
344    /// No common compression algorithm.
345    #[error("No common compression algorithm")]
346    NoCommonCompression,
347
348    /// Invalid SSH version string.
349    #[error("invalid SSH version string")]
350    Version,
351
352    /// Error during key exchange.
353    #[error("Key exchange failed")]
354    Kex,
355
356    /// Invalid packet authentication code.
357    #[error("Wrong packet authentication code")]
358    PacketAuth,
359
360    /// The protocol is in an inconsistent state.
361    #[error("Inconsistent state of the protocol")]
362    Inconsistent,
363
364    /// The client is not yet authenticated.
365    #[error("Not yet authenticated")]
366    NotAuthenticated,
367
368    /// Index out of bounds.
369    #[error("Index out of bounds")]
370    IndexOutOfBounds,
371
372    /// Unknown server key.
373    #[error("Unknown server key")]
374    UnknownKey,
375
376    /// The server provided a wrong signature.
377    #[error("Wrong server signature")]
378    WrongServerSig,
379
380    /// Message received/sent on unopened channel.
381    #[error("Channel not open")]
382    WrongChannel,
383
384    /// Disconnected
385    #[error("Disconnected")]
386    Disconnect,
387
388    /// No home directory found when trying to learn new host key.
389    #[error("No home directory when saving host key")]
390    NoHomeDir,
391
392    /// Remote key changed, this could mean a man-in-the-middle attack
393    /// is being performed on the connection.
394    #[error("Key changed, line {}", line)]
395    KeyChanged { line: usize },
396
397    /// Connection closed by the remote side.
398    #[error("Connection closed by the remote side")]
399    HUP,
400
401    /// Connection timeout.
402    #[error("Connection timeout")]
403    ConnectionTimeout,
404
405    /// Missing authentication method.
406    #[error("No authentication method")]
407    NoAuthMethod,
408
409    #[error("Channel send error")]
410    SendError,
411
412    #[error("Pending buffer limit reached")]
413    Pending,
414
415    #[error(transparent)]
416    Keys(#[from] lnk_thrussh_keys::Error),
417
418    #[error(transparent)]
419    Encoding(#[from] lnk_thrussh_encoding::Error),
420
421    #[error(transparent)]
422    IO(#[from] std::io::Error),
423
424    #[error(transparent)]
425    Utf8(#[from] std::str::Utf8Error),
426
427    #[error(transparent)]
428    Compress(#[from] flate2::CompressError),
429
430    #[error(transparent)]
431    Decompress(#[from] flate2::DecompressError),
432
433    #[error(transparent)]
434    Join(#[from] tokio::task::JoinError),
435
436    #[error(transparent)]
437    #[cfg(feature = "openssl")]
438    Openssl(#[from] openssl::error::ErrorStack),
439
440    #[error(transparent)]
441    Elapsed(#[from] tokio::time::error::Elapsed),
442}
443
444#[derive(Debug, Error)]
445#[error("Could not reach the event loop")]
446pub struct SendError {}
447
448/// Since handlers are large, their associated future types must implement this trait to provide reasonable default implementations (basically, rejecting all requests).
449pub trait FromFinished<T>: futures::Future<Output = Result<T, Error>> {
450    /// Turns type `T` into `Self`, a future yielding `T`.
451    fn finished(t: T) -> Self;
452}
453
454impl<T> FromFinished<T> for futures::future::Ready<Result<T, Error>> {
455    fn finished(t: T) -> Self {
456        futures::future::ready(Ok(t))
457    }
458}
459
460impl<T: 'static> FromFinished<T> for Box<dyn futures::Future<Output = Result<T, Error>> + Unpin> {
461    fn finished(t: T) -> Self {
462        Box::new(futures::future::ready(Ok(t)))
463    }
464}
465
466// mod mac;
467// use mac::*;
468// mod compression;
469
470/// The number of bytes read/written, and the number of seconds before a key re-exchange is requested.
471#[derive(Debug, Clone)]
472pub struct Limits {
473    pub rekey_write_limit: usize,
474    pub rekey_read_limit: usize,
475    pub rekey_time_limit: std::time::Duration,
476}
477
478impl Limits {
479    /// Create a new `Limits`, checking that the given bounds cannot lead to nonce reuse.
480    pub fn new(write_limit: usize, read_limit: usize, time_limit: std::time::Duration) -> Limits {
481        assert!(write_limit <= 1 << 30 && read_limit <= 1 << 30);
482        Limits {
483            rekey_write_limit: write_limit,
484            rekey_read_limit: read_limit,
485            rekey_time_limit: time_limit,
486        }
487    }
488}
489
490impl Default for Limits {
491    fn default() -> Self {
492        // Following the recommendations of
493        // https://tools.ietf.org/html/rfc4253#section-9
494        Limits {
495            rekey_write_limit: 1 << 30, // 1 Gb
496            rekey_read_limit: 1 << 30,  // 1 Gb
497            rekey_time_limit: std::time::Duration::from_secs(3600),
498        }
499    }
500}
501
502pub use auth::{AgentAuthError, MethodSet, Signer};
503
504/// A reason for disconnection.
505#[allow(missing_docs)] // This should be relatively self-explanatory.
506#[derive(Debug)]
507pub enum Disconnect {
508    HostNotAllowedToConnect = 1,
509    ProtocolError = 2,
510    KeyExchangeFailed = 3,
511    #[doc(hidden)]
512    Reserved = 4,
513    MACError = 5,
514    CompressionError = 6,
515    ServiceNotAvailable = 7,
516    ProtocolVersionNotSupported = 8,
517    HostKeyNotVerifiable = 9,
518    ConnectionLost = 10,
519    ByApplication = 11,
520    TooManyConnections = 12,
521    AuthCancelledByUser = 13,
522    NoMoreAuthMethodsAvailable = 14,
523    IllegalUserName = 15,
524}
525
526/// The type of signals that can be sent to a remote process. If you
527/// plan to use custom signals, read [the
528/// RFC](https://tools.ietf.org/html/rfc4254#section-6.10) to
529/// understand the encoding.
530#[allow(missing_docs)]
531// This should be relatively self-explanatory.
532#[derive(Debug, Clone)]
533pub enum Sig {
534    ABRT,
535    ALRM,
536    FPE,
537    HUP,
538    ILL,
539    INT,
540    KILL,
541    PIPE,
542    QUIT,
543    SEGV,
544    TERM,
545    USR1,
546    Custom(String),
547}
548
549impl Sig {
550    fn name(&self) -> &str {
551        match *self {
552            Sig::ABRT => "ABRT",
553            Sig::ALRM => "ALRM",
554            Sig::FPE => "FPE",
555            Sig::HUP => "HUP",
556            Sig::ILL => "ILL",
557            Sig::INT => "INT",
558            Sig::KILL => "KILL",
559            Sig::PIPE => "PIPE",
560            Sig::QUIT => "QUIT",
561            Sig::SEGV => "SEGV",
562            Sig::TERM => "TERM",
563            Sig::USR1 => "USR1",
564            Sig::Custom(ref c) => c,
565        }
566    }
567    fn from_name(name: &[u8]) -> Result<Sig, Error> {
568        match name {
569            b"ABRT" => Ok(Sig::ABRT),
570            b"ALRM" => Ok(Sig::ALRM),
571            b"FPE" => Ok(Sig::FPE),
572            b"HUP" => Ok(Sig::HUP),
573            b"ILL" => Ok(Sig::ILL),
574            b"INT" => Ok(Sig::INT),
575            b"KILL" => Ok(Sig::KILL),
576            b"PIPE" => Ok(Sig::PIPE),
577            b"QUIT" => Ok(Sig::QUIT),
578            b"SEGV" => Ok(Sig::SEGV),
579            b"TERM" => Ok(Sig::TERM),
580            b"USR1" => Ok(Sig::USR1),
581            x => Ok(Sig::Custom(std::str::from_utf8(x)?.to_string())),
582        }
583    }
584}
585
586/// Reason for not being able to open a channel.
587#[derive(Debug, Copy, Clone, PartialEq)]
588#[allow(missing_docs)]
589pub enum ChannelOpenFailure {
590    AdministrativelyProhibited = 1,
591    ConnectFailed = 2,
592    UnknownChannelType = 3,
593    ResourceShortage = 4,
594}
595
596impl ChannelOpenFailure {
597    fn from_u32(x: u32) -> Option<ChannelOpenFailure> {
598        match x {
599            1 => Some(ChannelOpenFailure::AdministrativelyProhibited),
600            2 => Some(ChannelOpenFailure::ConnectFailed),
601            3 => Some(ChannelOpenFailure::UnknownChannelType),
602            4 => Some(ChannelOpenFailure::ResourceShortage),
603            _ => None,
604        }
605    }
606}
607
608#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
609/// The identifier of a channel.
610pub struct ChannelId(u32);
611
612/// The parameters of a channel.
613#[derive(Debug)]
614pub(crate) struct Channel {
615    recipient_channel: u32,
616    sender_channel: ChannelId,
617    recipient_window_size: u32,
618    sender_window_size: u32,
619    recipient_maximum_packet_size: u32,
620    sender_maximum_packet_size: u32,
621    /// Has the other side confirmed the channel?
622    pub confirmed: bool,
623    wants_reply: bool,
624    pending_data: std::collections::VecDeque<(CryptoVec, Option<u32>, usize)>,
625}
626
627#[derive(Debug)]
628pub enum ChannelMsg {
629    Data {
630        data: CryptoVec,
631    },
632    ExtendedData {
633        data: CryptoVec,
634        ext: u32,
635    },
636    Eof,
637    Close,
638    XonXoff {
639        client_can_do: bool,
640    },
641    ExitStatus {
642        exit_status: u32,
643    },
644    ExitSignal {
645        signal_name: Sig,
646        core_dumped: bool,
647        error_message: String,
648        lang_tag: String,
649    },
650    WindowAdjusted {
651        new_size: u32,
652    },
653    Success,
654}
655
656#[cfg(test)]
657mod test_compress {
658    use super::server::{Auth, Server as _, Session};
659    use super::*;
660    use std::collections::HashMap;
661    use std::sync::{Arc, Mutex};
662
663    #[tokio::test]
664    async fn compress_local_test() {
665        let _ = env_logger::try_init();
666
667        let client_key = lnk_thrussh_keys::key::KeyPair::generate_ed25519().unwrap();
668        let client_pubkey = Arc::new(client_key.clone_public_key());
669        let mut config = server::Config::default();
670        config.preferred = Preferred::COMPRESSED;
671        config.connection_timeout = None; // Some(std::time::Duration::from_secs(3));
672        config.auth_rejection_time = std::time::Duration::from_secs(3);
673        config
674            .keys
675            .push(lnk_thrussh_keys::key::KeyPair::generate_ed25519().unwrap());
676        let config = Arc::new(config);
677        let mut sh = Server {
678            client_pubkey,
679            clients: Arc::new(Mutex::new(HashMap::new())),
680            id: 0,
681        };
682
683        let socket = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap();
684        let addr = socket.local_addr().unwrap();
685
686        tokio::spawn(async move {
687            let (socket, _) = socket.accept().await.unwrap();
688            let server = sh.new(socket.peer_addr().ok());
689            server::run_stream(config, socket, server).await.unwrap();
690        });
691
692        let mut config = client::Config::default();
693        config.preferred = Preferred::COMPRESSED;
694        let config = Arc::new(config);
695
696        dbg!(&addr);
697        let mut session = client::connect(config, addr, Client {}).await.unwrap();
698        let authenticated = session
699            .authenticate_publickey(std::env::var("USER").unwrap(), Arc::new(client_key))
700            .await
701            .unwrap();
702        assert!(authenticated);
703        let mut channel = session.channel_open_session().await.unwrap();
704
705        let data = &b"Hello, world!"[..];
706        channel.data(data).await.unwrap();
707        let msg = channel.wait().await.unwrap();
708        match msg {
709            ChannelMsg::Data { data: msg_data } => {
710                assert_eq!(*data, *msg_data)
711            }
712            msg => panic!("Unexpected message {:?}", msg),
713        }
714    }
715
716    #[derive(Clone)]
717    struct Server {
718        client_pubkey: Arc<lnk_thrussh_keys::key::PublicKey>,
719        clients: Arc<Mutex<HashMap<(usize, ChannelId), super::server::Handle>>>,
720        id: usize,
721    }
722
723    impl server::Server for Server {
724        type Handler = Self;
725        fn new(&mut self, _: Option<std::net::SocketAddr>) -> Self {
726            let s = self.clone();
727            self.id += 1;
728            s
729        }
730    }
731
732    impl server::Handler for Server {
733        type Error = super::Error;
734        type FutureAuth = futures::future::Ready<Result<(Self, server::Auth), Self::Error>>;
735        type FutureUnit = futures::future::Ready<Result<(Self, Session), Self::Error>>;
736        type FutureBool = futures::future::Ready<Result<(Self, Session, bool), Self::Error>>;
737
738        fn finished_auth(self, auth: Auth) -> Self::FutureAuth {
739            futures::future::ready(Ok((self, auth)))
740        }
741        fn finished_bool(self, b: bool, s: Session) -> Self::FutureBool {
742            futures::future::ready(Ok((self, s, b)))
743        }
744        fn finished(self, s: Session) -> Self::FutureUnit {
745            futures::future::ready(Ok((self, s)))
746        }
747        fn channel_open_session(self, channel: ChannelId, session: Session) -> Self::FutureUnit {
748            {
749                let mut clients = self.clients.lock().unwrap();
750                clients.insert((self.id, channel), session.handle());
751            }
752            self.finished(session)
753        }
754        fn auth_publickey(self, _: &str, _: &lnk_thrussh_keys::key::PublicKey) -> Self::FutureAuth {
755            debug!("auth_publickey");
756            self.finished_auth(server::Auth::Accept)
757        }
758        fn data(self, channel: ChannelId, data: &[u8], mut session: Session) -> Self::FutureUnit {
759            debug!("server data = {:?}", std::str::from_utf8(data));
760            session.data(channel, CryptoVec::from_slice(data));
761            self.finished(session)
762        }
763    }
764
765    struct Client {}
766
767    impl client::Handler for Client {
768        type Error = super::Error;
769        type FutureUnit = futures::future::Ready<Result<(Self, client::Session), Self::Error>>;
770        type FutureBool = futures::future::Ready<Result<(Self, bool), Self::Error>>;
771
772        fn finished_bool(self, b: bool) -> Self::FutureBool {
773            futures::future::ready(Ok((self, b)))
774        }
775        fn finished(self, session: client::Session) -> Self::FutureUnit {
776            futures::future::ready(Ok((self, session)))
777        }
778        fn check_server_key(
779            self,
780            server_public_key: &lnk_thrussh_keys::key::PublicKey,
781        ) -> Self::FutureBool {
782            println!("check_server_key: {:?}", server_public_key);
783            self.finished_bool(true)
784        }
785    }
786}