Fix SNI header parsing

When a listener is configured to deal with TLS upstreams, we use the SNI
field of the TLS ClientHello message to decide where to send the traffic.

Therefore, a buffer of 1024 bytes was used to temporarily store this
message. However, a TLS ClientHello message can be larger than that, up
to 16K bytes.

So now the first few bytes are read and manually parsed to find out how
long the message is. And then the entire ClientHello message is
retrieved.

So hopefully that will fix the issue causing the ClientHello
determination to fail.

Closes #10

Signed-off-by: Jacob Kiers <code@kiers.eu>
This commit is contained in:
2025-01-09 20:23:02 +01:00
parent aff46b6bfb
commit 8fe1f7f57b
2 changed files with 567 additions and 28 deletions

View File

@@ -1,6 +1,6 @@
use crate::servers::protocol::tls::get_sni;
use crate::servers::protocol::tls::determine_upstream_name;
use crate::servers::Proxy;
use log::{debug, error, info, warn};
use log::{debug, error, info, trace, warn};
use std::error::Error;
use std::sync::Arc;
use tokio::net::{TcpListener, TcpStream};
@@ -35,29 +35,7 @@ async fn accept(inbound: TcpStream, proxy: Arc<Proxy>) -> Result<(), Box<dyn Err
let upstream_name = match proxy.tls {
false => proxy.default_action.clone(),
true => {
let mut hello_buf = [0u8; 1024];
inbound.peek(&mut hello_buf).await?;
let snis = get_sni(&hello_buf);
if snis.is_empty() {
proxy.default_action.clone()
} else {
match proxy.sni.clone() {
Some(sni_map) => {
let mut upstream = proxy.default_action.clone();
for sni in snis {
let m = sni_map.get(&sni);
if m.is_some() {
upstream = m.unwrap().clone();
break;
}
}
upstream
}
None => proxy.default_action.clone(),
}
}
}
true => determine_upstream_name(&inbound, &proxy).await?,
};
debug!("Upstream: {}", upstream_name);