Giter VIP home page Giter VIP logo

Comments (8)

BrandonLeeDotDev avatar BrandonLeeDotDev commented on June 15, 2024 1

Imo, this is just default behavior... that said this is my final solution

    pub async fn accept<F, Fut>(&self, fun: F) -> io::Result<()>
    where
        F: FnOnce(TlsStream<TcpStream>, SocketAddr) -> Fut,
        Fut: Future<Output = ()> + Send + 'static,
        F: Send + 'static,
    {
        let acceptor = self.2.clone();
        let (mut stream, peer_addr) = self.3.accept().await?;

        tokio::spawn(async move {
            let mut buf = [0; 1]; // Buffer to read the first byte
            match timeout(Duration::from_secs(10), stream.peek(&mut buf)).await {
                Ok(Ok(_)) => {}
                _ => {
                    let _ = Self::redirect(&mut stream).await;
                }
            }

            if buf[0] == 0x16 {
                // 0x16 is the first byte of a TLS handshake
                if let Ok(tls_stream) = acceptor.accept(stream).await {
                    fun(tls_stream, peer_addr).await;
                }
            } else {
                let _ = Self::redirect(&mut stream).await;
            }
        });

        Ok(())
    }

from tokio-rustls.

BrandonLeeDotDev avatar BrandonLeeDotDev commented on June 15, 2024

this is ~(the response) in Firefox

���

from tokio-rustls.

BrandonLeeDotDev avatar BrandonLeeDotDev commented on June 15, 2024

I see why the above failed. By calling accept I was attempting to accept the next incoming connection. Which is why I tried the following, non preferred, Fd path...

Even if I create a stream from an OwnedFd I get the following:

������2HTTP/1.1 301 Moved Permanently Location: https://localhost:4010/

What are the leading bytes? How do I prevent them from being sent? How do I access the underlying stream should TLS fail?

    pub async fn accept(&self) -> io::Result<(TlsStream<TcpStream>, SocketAddr)> {
        let listener = &self.3;
        let (mut stream, peer_addr) = listener.accept().await?;

        let owned_fd: OwnedFd = stream.as_fd().try_clone_to_owned().unwrap();
        let std_stream = unsafe { std::net::TcpStream::from_raw_fd(owned_fd.into_raw_fd()) };
        std_stream.set_nonblocking(true)?;
        let tokio_stream = TcpStream::from_std(std_stream)?;

        match self.2.accept(tokio_stream).await {
            Err(_error) => {
                let redirect =
                    b"HTTP/1.1 301 Moved Permanently\r\nLocation: https://localhost:4010/\r\n\r\n";
                stream.write(redirect).await?;
                stream.flush().await?;
                stream.shutdown().await?;
                Err(io::Error::new(io::ErrorKind::Other, "Redirected"))
            },
            Ok(tls_stream) => Ok((tls_stream, peer_addr))
            
        }
    }

from tokio-rustls.

djc avatar djc commented on June 15, 2024

So you want to achieve that plaintext (HTTP) clients connecting to your TLS server socket get a HTTP redirect? I don't think tokio-rustls will facilitate that use case, because it will ~always send a TLS alert when it fails to parse the client's stream as TLS.

If you drop down directly to the rustls API you can probably make it work, but I'm not sure you can easily wrap a tokio-rustls connection around that after the fact. I suppose we could maybe support this use case in the LazyConfigAcceptor, optionally postponing the sending of the alert until the caller has okayed it?

from tokio-rustls.

BrandonLeeDotDev avatar BrandonLeeDotDev commented on June 15, 2024

@djc

I suppose we could maybe support this use case in the LazyConfigAcceptor, optionally postponing the sending of the alert until the caller has okayed it? - here

Yeah, should be supported somewhere... as arg or something... something like .force_tls(bool)

from tokio-rustls.

c92s avatar c92s commented on June 15, 2024

Can you elaborate on how the peeking trick should work? For me, in both cases (connecting via HTTP & HTTPS), the timer does not run in a timeout, as the peek was successful.

Using the following:

tokio::spawn(async move {
    mut buf = [0u8; 1];
    tcp_stream.peek(&mut buf).await.unwrap();
    println!("peeked: {:?}", buf);
...

successfully peeks something with HTTP and HTTPS:

peeked: [22]             <-- HTTPS
peeked: [71]             <-- HTTP

from tokio-rustls.

BrandonLeeDotDev avatar BrandonLeeDotDev commented on June 15, 2024

@c92s I ended up doing this. The first byte is the type signature. 22 (peeked: [22] <-- HTTPS) or 0x16 == HTTPS. I also check the client hello byte. If not not both then 301. 'let _ = Self::redirect(&mut stream).await;'

    pub async fn accept<F, Fut>(&self, handle_client: F) -> io::Result<()>
    where
        F: FnOnce(TlsStream<TcpStream>, SocketAddr) -> Fut,
        Fut: Future<Output = ()> + Send + 'static,
        F: Send + 'static,
    {
        let (mut stream, peer_addr) = self.1.accept().await?;
        let acceptor = self.0.clone();

        tokio::spawn(async move {
            let mut buf = [0; 6];
            match timeout(Duration::from_secs(60), stream.peek(&mut buf)).await {
                Ok(Ok(_)) => {}
                _ => {
                    let _ = Self::redirect(&mut stream).await;
                }
            }

            // Check for the handshake message type (0x16) and the ClientHello byte (0x01)
            if buf[0] == 0x16 && buf[5] == 0x01 {
                crate::debug_with_time!({},"TLS connection from {peer_addr}",);
                if let Ok(tls_stream) = acceptor.accept(stream).await {
                    tokio::spawn(handle_client(tls_stream, peer_addr));
                }
            } else {
                let _ = Self::redirect(&mut stream).await;
            }
        });

        Ok(())
    }

from tokio-rustls.

c92s avatar c92s commented on June 15, 2024

@BrandonLeeDotDev thanks for the info!

FYI: we could further refine that, using the available rustls enums (rustls::ContentType::Handshake & rustls::HandshakeType::ClientHello), e.g.:

if buf[0] ==  rustls::ContentType::Handshake.get_u8() && buf[5] == rustls::HandshakeType::ClientHello.get_u8() {
    crate::debug_with_time!({},"TLS connection from {peer_addr}",);
    if let Ok(tls_stream) = acceptor.accept(stream).await {
        tokio::spawn(handle_client(tls_stream, peer_addr));
    }
} else {
    let _ = Self::redirect(&mut stream).await;
}

However, IMO this looks very "handcrafted", I am still not sure, if this is the proper way to handle such cases...

from tokio-rustls.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.