Comments (8)
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.
this is ~(the response) in Firefox
���
from tokio-rustls.
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.
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.
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.
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.
@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.
@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)
- README and examples use unavailable API HOT 7
- Version tags HOT 6
- tokio-rustls write only first IoSlice when use write_vectored HOT 1
- Override `poll_write_vectored`? HOT 5
- Allow non-static lifetime for ServerName? HOT 3
- I can't find OwnedTrustAnchor??????
- Error: tls handshake eof HOT 1
- How to get peer certificates as server? HOT 2
- Error `NotConnected` when serving a `TlsStream<TcpStream>` when using `hyper` HOT 4
- Error: badRecordMac HOT 2
- Large percentage of cpu time in memset when reading with a larger buffer HOT 9
- Proposal: Share code between tokio-rustls and futures-rustls HOT 1
- Use Unbuffered API
- 0.5-RTT support
- Remove TCP shutdown
- Secure WebSocket Implementation with tokio-tungstenite | tokio-rustls | rustls-platform-verifier HOT 2
- Detailed Error Messages HOT 1
- Test failure in common::test_stream::stream_handshake_regression_issues_77 HOT 2
- does TLSAcceptor read early data? HOT 5
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from tokio-rustls.