Help implement ssh client Russh/Thrussh with jumphost

please i need help using Thrussh or Russh ssh create

i am trying to implement a small program that ssh into a server using another server as a jump host.
I was successfully able to ssh directly, request pty and shell etc directly but when trying to implement jump host i get disconnect error when trying to connect to the target using the jumphost stream

mod actor;

use russh::client as client_lib;
use std::sync::Arc;
use async_trait::async_trait;
use russh::{client, ChannelId};
use russh_keys::key::PublicKey;


#[actix_rt::main]
async fn main() {
    let config = client_lib::Config::default();

    let jumphost = "172.17.181.25";
    let jumphost_port = 22;
    let jumphost_username = "username";
    let jumphost_password = "password";

    let client = SshClient {
        host: "172.17.181.27",
        port: 22,
        username: "username",
        password: "password",
    };

    let custom_config = Arc::new(config);
    let mut jumphost_session = client_lib::connect(
        custom_config.clone(),
        (jumphost, jumphost_port),
        client.clone(),
    )
    .await
    .unwrap();

    if jumphost_session
        .authenticate_password(jumphost_username, jumphost_password)
        .await
        .unwrap()
    {
        let channel_stream = jumphost_session
            .channel_open_direct_tcpip(client.host, client.port as u32, "127.0.0.1", 0)
            .await
            .unwrap()
            .into_stream();

        let mut ts =
            client_lib::connect_stream(custom_config.clone(), channel_stream, client.clone())
                .await;

        let mut target_session = ts.unwrap();    // <= Disconnect Error occurred hear

        let is_authenticated = target_session
            .authenticate_password(client.username, client.password)
            .await
            .unwrap();

        if is_authenticated {
            let mut channel = target_session.channel_open_session().await.unwrap();
            channel
                .request_pty(true, "xterm", 200, 200, 200, 200, &[])
                .await
                .unwrap();
            channel.request_shell(true).await.unwrap();
            channel.data(&b"ls -ls\n"[..]).await.unwrap();
        }

        // loop {
        //     if let Some(msg) = channel.wait().await {
        //     match msg {
        //         ChannelMsg::Eof => {
        //             println!("Server closed connection");
        //             std::process::exit(0);
        //         }
        //         ChannelMsg::Success => println!("Something was successfull"),
        //         ChannelMsg::Data { data } => println!("{:?}", data),
        //         ChannelMsg::Open {
        //             id,
        //             max_packet_size,
        //             window_size,
        //         } => {
        //             println!("ID: {id}, PACKET_SIZE: {max_packet_size}, WINDOW_SIZE: {window_size}")
        //         }
        //         ChannelMsg::Exec {
        //             want_reply,
        //             command,
        //         } => println!("{:?}:::{:?}", want_reply, command),
        //         ChannelMsg::ExtendedData { data, ext } => println!("{:?} {:?}", data, ext),
        //         ChannelMsg::Failure => println!("Failure"),
        //         ChannelMsg::ExitStatus { exit_status } => println!("{:?}", exit_status),
        //         ChannelMsg::Close => println!("close returned"),
        //
        //         _ => println!("Something Else"),
        //     }
        //         dbg!(msg);
        //     }
        // }
    }
}




#[derive(Debug, Clone)]
pub struct SshClient<'client> {
    pub host: &'client str,
    pub port: u16,
    pub username: &'client str,
    pub password: &'client str,
}

#[async_trait]
impl<'client> client::Handler for SshClient<'client> {
    type Error = anyhow::Error;

    async fn check_server_key(
        self,
        server_public_key: &PublicKey,
    ) -> Result<(Self, bool), Self::Error> {
        println!("check server public key {:?}", server_public_key);
        Ok((self, true))
    }

    async fn data(
        self,
        channel: ChannelId,
        data: &[u8],
        session: client::Session,
    ) -> Result<(Self, client::Session), Self::Error> {
        println!(
            "data on channel {:?}: {:?}",
            channel,
            String::from_utf8_lossy(data)
        );
        Ok((self, session))
    }
}

here is the complete outoput

/home/blackdante/Development/learning/rust/learn_ssh/target/debug/learn_ssh
check server public key Ed25519(PublicKey(CompressedEdwardsY: [35, 56, 108, 175, 224, 8, 99, 157, 102, 61, 119, 255, 169, 228, 68, 113, 138, 84, 167, 146, 179, 137, 106, 184, 142, 22, 151, 15, 178, 211, 54, 25]), EdwardsPoint{
        X: FieldElement51([1630537806071078, 648316631189368, 793242739809564, 1818755964497301, 2232763494220464]),
        Y: FieldElement51([854186038933539, 1477670205182892, 735926167081874, 922886286399945, 443572329445745]),
        Z: FieldElement51([1, 0, 0, 0, 0]),
        T: FieldElement51([1505040704566283, 1894851419557823, 1376022236302954, 2064758804968182, 1505568779901593])
}))
data on channel ChannelId(2): "SSH-2.0-OpenSSH_8.0\r\n"
data on channel ChannelId(2): "\0\0\u{4}\u{14}\u{5}\u{14}V(#\u{e}\u{1a}k\u{2}\u{4}\u{1a}��倿��\0\0\u{1}%curve25519-sha256,curve25519-sha256@libssh.org,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nist521,diffie-hellman-group-exchange-sha256,diffie-hellman-group14-sha256,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha1,diffie-hellman-group14-sha1\0\0\0Arsa-sha2-512,rsa-sha2-256,ssh-rsa,ecdsa-sha2-nistp256,ssh-ed25519\0\0\0waes256-gcm@openssh.com,chacha20-poly1305@openssh.com,aes256-ctr,aes256-cbc,aes128-gcm@openssh.com,aes128-ctr,aes128-cbc\0\0\0waes256-gcm@openssh.com,chacha20-poly1305@openssh.com,aes256-ctr,aes256-cbc,aes128-gcm@openssh.com,aes128-ctr,aes128-cbc\0\0\0�hmac-sha2-256-etm@openssh.com,hmac-sha1-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha2-256,hmac-sha1,umac-128@openssh.com,hmac-sha2-512\0\0\0�hmac-sha2-256-etm@openssh.com,hmac-sha1-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha2-256,hmac-sha1,umac-128@openssh.com,hmac-sha2-512\0\0\0\u{15}none,zlib@openssh.com\0\0\0\u{15}none,zlib@openssh.com\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Disconnected', src/main.rs:52:37
stack backtrace:
   0: rust_begin_unwind
             at /rustc/8ede3aae28fe6e4d52b38157d7bfe0d3bceef225/library/std/src/panicking.rs:593:5
   1: core::panicking::panic_fmt
             at /rustc/8ede3aae28fe6e4d52b38157d7bfe0d3bceef225/library/core/src/panicking.rs:67:14
   2: core::result::unwrap_failed
             at /rustc/8ede3aae28fe6e4d52b38157d7bfe0d3bceef225/library/core/src/result.rs:1651:5
   3: core::result::Result<T,E>::unwrap
             at /rustc/8ede3aae28fe6e4d52b38157d7bfe0d3bceef225/library/core/src/result.rs:1076:23
   4: learn_ssh::main::{{closure}}
             at ./src/main.rs:52:34
   5: <tokio::task::local::RunUntil<T> as core::future::future::Future>::poll::{{closure}}
             at /home/blackdante/.local/share/cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.26.0/src/task/local.rs:923:42
   6: tokio::task::local::LocalSet::with::{{closure}}
             at /home/blackdante/.local/share/cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.26.0/src/task/local.rs:684:13
   7: std::thread::local::LocalKey<T>::try_with
             at /rustc/8ede3aae28fe6e4d52b38157d7bfe0d3bceef225/library/std/src/thread/local.rs:270:16
   8: std::thread::local::LocalKey<T>::with
             at /rustc/8ede3aae28fe6e4d52b38157d7bfe0d3bceef225/library/std/src/thread/local.rs:246:9
   9: tokio::task::local::LocalSet::with
             at /home/blackdante/.local/share/cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.26.0/src/task/local.rs:667:9
  10: <tokio::task::local::RunUntil<T> as core::future::future::Future>::poll
             at /home/blackdante/.local/share/cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.26.0/src/task/local.rs:913:9
  11: tokio::task::local::LocalSet::run_until::{{closure}}
             at /home/blackdante/.local/share/cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.26.0/src/task/local.rs:573:19
  12: <core::pin::Pin<P> as core::future::future::Future>::poll
             at /rustc/8ede3aae28fe6e4d52b38157d7bfe0d3bceef225/library/core/src/future/future.rs:125:9
  13: tokio::runtime::scheduler::current_thread::CoreGuard::block_on::{{closure}}::{{closure}}::{{closure}}
             at /home/blackdante/.local/share/cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.26.0/src/runtime/scheduler/current_thread.rs:541:57
  14: tokio::runtime::coop::with_budget
             at /home/blackdante/.local/share/cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.26.0/src/runtime/coop.rs:107:5
  15: tokio::runtime::coop::budget
             at /home/blackdante/.local/share/cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.26.0/src/runtime/coop.rs:73:5
  16: tokio::runtime::scheduler::current_thread::CoreGuard::block_on::{{closure}}::{{closure}}
             at /home/blackdante/.local/share/cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.26.0/src/runtime/scheduler/current_thread.rs:541:25
  17: tokio::runtime::scheduler::current_thread::Context::enter
             at /home/blackdante/.local/share/cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.26.0/src/runtime/scheduler/current_thread.rs:350:19
  18: tokio::runtime::scheduler::current_thread::CoreGuard::block_on::{{closure}}
             at /home/blackdante/.local/share/cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.26.0/src/runtime/scheduler/current_thread.rs:540:36
  19: tokio::runtime::scheduler::current_thread::CoreGuard::enter::{{closure}}
             at /home/blackdante/.local/share/cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.26.0/src/runtime/scheduler/current_thread.rs:615:57
  20: tokio::macros::scoped_tls::ScopedKey<T>::set
             at /home/blackdante/.local/share/cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.26.0/src/macros/scoped_tls.rs:61:9
  21: tokio::runtime::scheduler::current_thread::CoreGuard::enter
             at /home/blackdante/.local/share/cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.26.0/src/runtime/scheduler/current_thread.rs:615:27
  22: tokio::runtime::scheduler::current_thread::CoreGuard::block_on
             at /home/blackdante/.local/share/cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.26.0/src/runtime/scheduler/current_thread.rs:530:19
  23: tokio::runtime::scheduler::current_thread::CurrentThread::block_on
             at /home/blackdante/.local/share/cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.26.0/src/runtime/scheduler/current_thread.rs:154:24
  24: tokio::runtime::runtime::Runtime::block_on
             at /home/blackdante/.local/share/cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.26.0/src/runtime/runtime.rs:302:47
  25: tokio::task::local::LocalSet::block_on
             at /home/blackdante/.local/share/cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.26.0/src/task/local.rs:534:9
  26: actix_rt::runtime::Runtime::block_on
             at /home/blackdante/.local/share/cargo/registry/src/index.crates.io-6f17d22bba15001f/actix-rt-2.8.0/src/runtime.rs:82:9
  27: actix_rt::system::SystemRunner::block_on
             at /home/blackdante/.local/share/cargo/registry/src/index.crates.io-6f17d22bba15001f/actix-rt-2.8.0/src/system.rs:210:9
  28: learn_ssh::main
             at ./src/main.rs:12:1
  29: core::ops::function::FnOnce::call_once
             at /rustc/8ede3aae28fe6e4d52b38157d7bfe0d3bceef225/library/core/src/ops/function.rs:250:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.