Bump dependencies

This commit is contained in:
Σrebe - Romain GERARD 2024-05-09 13:33:23 +02:00
parent 1eccb70aab
commit bf9459b3fc
No known key found for this signature in database
GPG key ID: 7A42B4B97E0332F4
6 changed files with 971 additions and 291 deletions

1091
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -7,9 +7,10 @@ repository = "https://github.com/erebe/wstunnel.git"
[dependencies] [dependencies]
ahash = { version = "0.8.11", features = [] } ahash = { version = "0.8.11", features = [] }
anyhow = "1.0.81" anyhow = "1.0.83"
async-trait = "0.1.79" async-trait = "0.1.80"
base64 = "0.22.0" base64 = "0.22.1"
scopeguard = "1.2.0"
bb8 = { version = "0.8", features = [] } bb8 = { version = "0.8", features = [] }
bytes = { version = "1.6.0", features = [] } bytes = { version = "1.6.0", features = [] }
@ -17,7 +18,7 @@ clap = { version = "4.5.4", features = ["derive", "env"] }
fast-socks5 = { version = "0.9.6", features = [] } fast-socks5 = { version = "0.9.6", features = [] }
fastwebsockets = { version = "0.7.1", features = ["upgrade", "simd", "unstable-split"] } fastwebsockets = { version = "0.7.1", features = ["upgrade", "simd", "unstable-split"] }
futures-util = { version = "0.3.30" } futures-util = { version = "0.3.30" }
hickory-resolver = { version = "0.24.0", features = ["tokio", "dns-over-https-rustls", "dns-over-rustls"] } hickory-resolver = { version = "0.24.1", features = ["tokio", "dns-over-https-rustls", "dns-over-rustls"] }
ppp = { version = "2.2.0", features = [] } ppp = { version = "2.2.0", features = [] }
# For config file parsing # For config file parsing
@ -26,27 +27,30 @@ serde_regex = "1.1.0"
serde_yaml = { version = "0.9.34", features = [] } serde_yaml = { version = "0.9.34", features = [] }
ipnet = { version = "2.9.0", features = ["serde"] } ipnet = { version = "2.9.0", features = ["serde"] }
hyper = { version = "1.2.0", features = ["client", "http1", "http2"] } hyper = { version = "1.3.1", features = ["client", "http1", "http2"] }
hyper-util = { version = "0.1.3", features = ["tokio", "server", "server-auto"] } hyper-util = { version = "0.1.3", features = ["tokio", "server", "server-auto"] }
http-body-util = { version = "0.1.1" } http-body-util = { version = "0.1.1" }
jsonwebtoken = { version = "9.3.0", default-features = false } jsonwebtoken = { version = "9.3.0", default-features = false }
log = "0.4.21" log = "0.4.21"
nix = { version = "0.28.0", features = ["socket", "net", "uio"] } nix = { version = "0.28.0", features = ["socket", "net", "uio"] }
once_cell = { version = "1.19.0", features = [] } once_cell = { version = "1.19.0", features = [] }
parking_lot = "0.12.1" parking_lot = "0.12.2"
pin-project = "1" pin-project = "1"
notify = { version = "6.1.1", features = [] } notify = { version = "6.1.1", features = [] }
rustls-native-certs = { version = "0.7.0", features = [] } rustls-native-certs = { version = "0.7.0", features = [] }
rustls-pemfile = { version = "2.1.1", features = [] } rustls-pemfile = { version = "2.1.2", features = [] }
x509-parser = "0.16.0" x509-parser = "0.16.0"
scopeguard = "1.2.0" serde = { version = "1.0.201", features = ["derive"] }
serde = { version = "1.0.197", features = ["derive"] } socket2 = { version = "0.5.7", features = [] }
socket2 = { version = "0.5.6", features = [] } tokio = { version = "1.37.0", features = ["full"] }
tokio = { version = "1.36.0", features = ["full"] }
tokio-rustls = { version = "0.24.1", features = ["tls12", "dangerous_configuration", "early-data"] }
tokio-stream = { version = "0.1.15", features = ["net"] } tokio-stream = { version = "0.1.15", features = ["net"] }
[target.'cfg(os = "linux")'.dependencies]
tokio-rustls = { version = "0.26.0", features = ["tls12"] }
[target.'cfg(not(os = "linux"))'.dependencies]
tokio-rustls = { version = "0.26.0", default-features = false, features = ["logging", "tls12", "ring"] }
tracing = { version = "0.1.40", features = ["log"] } tracing = { version = "0.1.40", features = ["log"] }
tracing-subscriber = { version = "0.3.18", features = ["env-filter", "fmt", "local-time"] } tracing-subscriber = { version = "0.3.18", features = ["env-filter", "fmt", "local-time"] }
url = "2.5.0" url = "2.5.0"
@ -55,13 +59,13 @@ uuid = { version = "1.8.0", features = ["v7", "serde"] }
[target.'cfg(not(target_family = "unix"))'.dependencies] [target.'cfg(not(target_family = "unix"))'.dependencies]
crossterm = { version = "0.27.0" } crossterm = { version = "0.27.0" }
tokio-util = { version = "0.7.10", features = ["io"] } tokio-util = { version = "0.7.11", features = ["io"] }
[target.'cfg(target_family = "unix")'.dependencies] [target.'cfg(target_family = "unix")'.dependencies]
tokio-fd = "0.3.0" tokio-fd = "0.3.0"
[dev-dependencies] [dev-dependencies]
testcontainers = "0.15.0" testcontainers = "0.16.7"
[profile.release] [profile.release]
lto = "fat" lto = "fat"

View file

@ -1,17 +1,17 @@
use log::info; use log::info;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use tokio_rustls::rustls::{Certificate, PrivateKey}; use tokio_rustls::rustls::pki_types::{CertificateDer, PrivateKeyDer};
pub static TLS_PRIVATE_KEY: Lazy<PrivateKey> = Lazy::new(|| { pub static TLS_PRIVATE_KEY: Lazy<PrivateKeyDer<'static>> = Lazy::new(|| {
info!("Loading embedded tls private key"); info!("Loading embedded tls private key");
let key = include_bytes!("../certs/key.pem"); let key = include_bytes!("../certs/key.pem");
let key = rustls_pemfile::private_key(&mut key.as_slice()) let key = rustls_pemfile::private_key(&mut key.as_slice())
.expect("failed to load embedded tls private key") .expect("failed to load embedded tls private key")
.expect("failed to load embedded tls private key"); .expect("failed to load embedded tls private key");
PrivateKey(key.secret_der().to_vec()) key
}); });
pub static TLS_CERTIFICATE: Lazy<Vec<Certificate>> = Lazy::new(|| { pub static TLS_CERTIFICATE: Lazy<Vec<CertificateDer<'static>>> = Lazy::new(|| {
info!("Loading embedded tls certificate"); info!("Loading embedded tls certificate");
let cert = include_bytes!("../certs/cert.pem"); let cert = include_bytes!("../certs/cert.pem");
@ -19,8 +19,5 @@ pub static TLS_CERTIFICATE: Lazy<Vec<Certificate>> = Lazy::new(|| {
.next() .next()
.expect("failed to load embedded tls certificate"); .expect("failed to load embedded tls certificate");
certs certs.into_iter().collect()
.into_iter()
.map(|cert| Certificate(cert.as_ref().to_vec()))
.collect()
}); });

View file

@ -34,8 +34,7 @@ use std::{fmt, io};
use tokio::io::{AsyncRead, AsyncWrite}; use tokio::io::{AsyncRead, AsyncWrite};
use tokio::net::TcpStream; use tokio::net::TcpStream;
use tokio_rustls::rustls::server::DnsName; use tokio_rustls::rustls::pki_types::{CertificateDer, DnsName, PrivateKeyDer, ServerName};
use tokio_rustls::rustls::{Certificate, PrivateKey, ServerName};
use tokio_rustls::TlsConnector; use tokio_rustls::TlsConnector;
use tracing::{error, info}; use tracing::{error, info};
@ -143,7 +142,7 @@ struct Client {
/// Warning: If you are behind a CDN (i.e: Cloudflare) you must set this domain also in the http HOST header. /// Warning: If you are behind a CDN (i.e: Cloudflare) you must set this domain also in the http HOST header.
/// or it will be flagged as fishy and your request rejected /// or it will be flagged as fishy and your request rejected
#[arg(long, value_name = "DOMAIN_NAME", value_parser = parse_sni_override, verbatim_doc_comment)] #[arg(long, value_name = "DOMAIN_NAME", value_parser = parse_sni_override, verbatim_doc_comment)]
tls_sni_override: Option<DnsName>, tls_sni_override: Option<DnsName<'static>>,
/// Disable sending SNI during TLS handshake /// Disable sending SNI during TLS handshake
/// Warning: Most reverse proxies rely on it /// Warning: Most reverse proxies rely on it
@ -534,7 +533,7 @@ fn parse_tunnel_arg(arg: &str) -> Result<LocalToRemote, io::Error> {
} }
} }
fn parse_sni_override(arg: &str) -> Result<DnsName, io::Error> { fn parse_sni_override(arg: &str) -> Result<DnsName<'static>, io::Error> {
match DnsName::try_from(arg.to_string()) { match DnsName::try_from(arg.to_string()) {
Ok(val) => Ok(val), Ok(val) => Ok(val),
Err(err) => Err(io::Error::new( Err(err) => Err(io::Error::new(
@ -601,9 +600,9 @@ fn parse_server_url(arg: &str) -> Result<Url, io::Error> {
/// Find a leaf certificate in a vector of certificates. It is assumed only a single leaf certificate /// Find a leaf certificate in a vector of certificates. It is assumed only a single leaf certificate
/// is present in the vector. The other certificates should be (intermediate) CA certificates. /// is present in the vector. The other certificates should be (intermediate) CA certificates.
fn find_leaf_certificate(tls_certificates: &Vec<Certificate>) -> Option<X509Certificate> { fn find_leaf_certificate<'a>(tls_certificates: &'a Vec<CertificateDer<'static>>) -> Option<X509Certificate<'a>> {
for tls_certificate in tls_certificates { for tls_certificate in tls_certificates {
if let Ok((_, tls_certificate_x509)) = parse_x509_certificate(&tls_certificate.0) { if let Ok((_, tls_certificate_x509)) = parse_x509_certificate(tls_certificate) {
if !tls_certificate_x509.is_ca() { if !tls_certificate_x509.is_ca() {
return Some(tls_certificate_x509); return Some(tls_certificate_x509);
} }
@ -626,7 +625,7 @@ fn cn_from_certificate(tls_certificate_x509: &X509Certificate) -> Option<String>
#[derive(Clone)] #[derive(Clone)]
pub struct TlsClientConfig { pub struct TlsClientConfig {
pub tls_sni_disabled: bool, pub tls_sni_disabled: bool,
pub tls_sni_override: Option<DnsName>, pub tls_sni_override: Option<DnsName<'static>>,
pub tls_verify_certificate: bool, pub tls_verify_certificate: bool,
tls_connector: Arc<RwLock<TlsConnector>>, tls_connector: Arc<RwLock<TlsConnector>>,
pub tls_certificate_path: Option<PathBuf>, pub tls_certificate_path: Option<PathBuf>,
@ -641,9 +640,9 @@ impl TlsClientConfig {
#[derive(Debug)] #[derive(Debug)]
pub struct TlsServerConfig { pub struct TlsServerConfig {
pub tls_certificate: Mutex<Vec<Certificate>>, pub tls_certificate: Mutex<Vec<CertificateDer<'static>>>,
pub tls_key: Mutex<PrivateKey>, pub tls_key: Mutex<PrivateKeyDer<'static>>,
pub tls_client_ca_certificates: Option<Mutex<Vec<Certificate>>>, pub tls_client_ca_certificates: Option<Mutex<Vec<CertificateDer<'static>>>>,
pub tls_certificate_path: Option<PathBuf>, pub tls_certificate_path: Option<PathBuf>,
pub tls_key_path: Option<PathBuf>, pub tls_key_path: Option<PathBuf>,
pub tls_client_ca_certs_path: Option<PathBuf>, pub tls_client_ca_certs_path: Option<PathBuf>,
@ -716,17 +715,16 @@ impl WsClientConfig {
format!("{}:{}", self.remote_addr.host(), self.remote_addr.port()) format!("{}:{}", self.remote_addr.host(), self.remote_addr.port())
} }
pub fn tls_server_name(&self) -> ServerName { pub fn tls_server_name(&self) -> ServerName<'static> {
static INVALID_DNS_NAME: Lazy<DnsName> = static INVALID_DNS_NAME: Lazy<DnsName> = Lazy::new(|| DnsName::try_from("dns-name-invalid.com").unwrap());
Lazy::new(|| DnsName::try_from_ascii(b"dns-name-invalid.com").unwrap());
match self.remote_addr.tls().and_then(|tls| tls.tls_sni_override.as_ref()) { match self.remote_addr.tls().and_then(|tls| tls.tls_sni_override.as_ref()) {
None => match &self.remote_addr.host() { None => match &self.remote_addr.host() {
Host::Domain(domain) => { Host::Domain(domain) => {
ServerName::DnsName(DnsName::try_from(domain.clone()).unwrap_or_else(|_| INVALID_DNS_NAME.clone())) ServerName::DnsName(DnsName::try_from(domain.clone()).unwrap_or_else(|_| INVALID_DNS_NAME.clone()))
} }
Host::Ipv4(ip) => ServerName::IpAddress(IpAddr::V4(*ip)), Host::Ipv4(ip) => ServerName::IpAddress(IpAddr::V4(*ip).into()),
Host::Ipv6(ip) => ServerName::IpAddress(IpAddr::V6(*ip)), Host::Ipv6(ip) => ServerName::IpAddress(IpAddr::V6(*ip).into()),
}, },
Some(sni_override) => ServerName::DnsName(sni_override.clone()), Some(sni_override) => ServerName::DnsName(sni_override.clone()),
} }
@ -1237,7 +1235,7 @@ async fn main() {
let tls_key = if let Some(key_path) = &args.tls_private_key { let tls_key = if let Some(key_path) = &args.tls_private_key {
tls::load_private_key_from_file(key_path).expect("Cannot load tls private key") tls::load_private_key_from_file(key_path).expect("Cannot load tls private key")
} else { } else {
embedded_certificate::TLS_PRIVATE_KEY.clone() embedded_certificate::TLS_PRIVATE_KEY.clone_key()
}; };
let tls_client_ca_certificates = args.tls_client_ca_certs.as_ref().map(|tls_client_ca| { let tls_client_ca_certificates = args.tls_client_ca_certs.as_ref().map(|tls_client_ca| {

View file

@ -206,7 +206,8 @@ mod tests {
use futures_util::pin_mut; use futures_util::pin_mut;
use std::net::SocketAddr; use std::net::SocketAddr;
use testcontainers::core::WaitFor; use testcontainers::core::WaitFor;
use testcontainers::{Image, ImageArgs, RunnableImage}; use testcontainers::runners::AsyncRunner;
use testcontainers::{ContainerAsync, Image, ImageArgs, RunnableImage};
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone, Default)]
pub struct MitmProxy {} pub struct MitmProxy {}
@ -240,9 +241,10 @@ mod tests {
let server_addr: SocketAddr = "[::1]:1236".parse().unwrap(); let server_addr: SocketAddr = "[::1]:1236".parse().unwrap();
let server = TcpListener::bind(server_addr).await.unwrap(); let server = TcpListener::bind(server_addr).await.unwrap();
let docker = testcontainers::clients::Cli::default(); let _mitm_proxy: ContainerAsync<MitmProxy> = RunnableImage::from(MitmProxy {})
let mitm_proxy: RunnableImage<MitmProxy> = RunnableImage::from(MitmProxy {}).with_network("host".to_string()); .with_network("host".to_string())
let _node = docker.run(mitm_proxy); .start()
.await;
let mut client = connect_with_http_proxy( let mut client = connect_with_http_proxy(
&"http://localhost:8080".parse().unwrap(), &"http://localhost:8080".parse().unwrap(),

View file

@ -6,33 +6,70 @@ use log::warn;
use std::io::BufReader; use std::io::BufReader;
use std::path::Path; use std::path::Path;
use std::sync::Arc; use std::sync::Arc;
use std::time::SystemTime;
use tokio::net::TcpStream; use tokio::net::TcpStream;
use tokio_rustls::client::TlsStream; use tokio_rustls::client::TlsStream;
use tokio_rustls::rustls::client::{ServerCertVerified, ServerCertVerifier};
use crate::tunnel::TransportAddr; use crate::tunnel::TransportAddr;
use tokio_rustls::rustls::server::{AllowAnyAuthenticatedClient, NoClientAuth}; use tokio_rustls::rustls::client::danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier};
use tokio_rustls::rustls::{Certificate, ClientConfig, KeyLogFile, PrivateKey, ServerName}; use tokio_rustls::rustls::pki_types::{CertificateDer, PrivateKeyDer, ServerName, UnixTime};
use tokio_rustls::rustls::server::WebPkiClientVerifier;
use tokio_rustls::rustls::{ClientConfig, DigitallySignedStruct, Error, KeyLogFile, SignatureScheme};
use tokio_rustls::{rustls, TlsAcceptor, TlsConnector}; use tokio_rustls::{rustls, TlsAcceptor, TlsConnector};
use tracing::info; use tracing::info;
#[derive(Debug)]
struct NullVerifier; struct NullVerifier;
impl ServerCertVerifier for NullVerifier { impl ServerCertVerifier for NullVerifier {
fn verify_server_cert( fn verify_server_cert(
&self, &self,
_end_entity: &Certificate, _end_entity: &CertificateDer<'_>,
_intermediates: &[Certificate], _intermediates: &[CertificateDer<'_>],
_server_name: &ServerName, _server_name: &ServerName<'_>,
_scts: &mut dyn Iterator<Item = &[u8]>,
_ocsp_response: &[u8], _ocsp_response: &[u8],
_now: SystemTime, _now: UnixTime,
) -> Result<ServerCertVerified, rustls::Error> { ) -> Result<ServerCertVerified, Error> {
Ok(ServerCertVerified::assertion()) Ok(ServerCertVerified::assertion())
} }
fn verify_tls12_signature(
&self,
_message: &[u8],
_cert: &CertificateDer<'_>,
_dss: &DigitallySignedStruct,
) -> Result<HandshakeSignatureValid, Error> {
Ok(HandshakeSignatureValid::assertion())
}
fn verify_tls13_signature(
&self,
_message: &[u8],
_cert: &CertificateDer<'_>,
_dss: &DigitallySignedStruct,
) -> Result<HandshakeSignatureValid, Error> {
Ok(HandshakeSignatureValid::assertion())
}
fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
vec![
SignatureScheme::RSA_PKCS1_SHA1,
SignatureScheme::ECDSA_SHA1_Legacy,
SignatureScheme::RSA_PKCS1_SHA256,
SignatureScheme::ECDSA_NISTP256_SHA256,
SignatureScheme::RSA_PKCS1_SHA384,
SignatureScheme::ECDSA_NISTP384_SHA384,
SignatureScheme::RSA_PKCS1_SHA512,
SignatureScheme::ECDSA_NISTP521_SHA512,
SignatureScheme::RSA_PSS_SHA256,
SignatureScheme::RSA_PSS_SHA384,
SignatureScheme::RSA_PSS_SHA512,
SignatureScheme::ED25519,
SignatureScheme::ED448,
]
}
} }
pub fn load_certificates_from_pem(path: &Path) -> anyhow::Result<Vec<Certificate>> { pub fn load_certificates_from_pem(path: &Path) -> anyhow::Result<Vec<CertificateDer<'static>>> {
info!("Loading tls certificate from {:?}", path); info!("Loading tls certificate from {:?}", path);
let file = File::open(path)?; let file = File::open(path)?;
@ -42,7 +79,7 @@ pub fn load_certificates_from_pem(path: &Path) -> anyhow::Result<Vec<Certificate
Ok(certs Ok(certs
.into_iter() .into_iter()
.filter_map(|cert| match cert { .filter_map(|cert| match cert {
Ok(cert) => Some(Certificate(cert.to_vec())), Ok(cert) => Some(cert),
Err(err) => { Err(err) => {
warn!("Error while parsing tls certificate: {:?}", err); warn!("Error while parsing tls certificate: {:?}", err);
None None
@ -51,7 +88,7 @@ pub fn load_certificates_from_pem(path: &Path) -> anyhow::Result<Vec<Certificate
.collect()) .collect())
} }
pub fn load_private_key_from_file(path: &Path) -> anyhow::Result<PrivateKey> { pub fn load_private_key_from_file(path: &Path) -> anyhow::Result<PrivateKeyDer<'static>> {
info!("Loading tls private key from {:?}", path); info!("Loading tls private key from {:?}", path);
let file = File::open(path)?; let file = File::open(path)?;
@ -61,30 +98,28 @@ pub fn load_private_key_from_file(path: &Path) -> anyhow::Result<PrivateKey> {
return Err(anyhow!("No private key found in {path:?}")); return Err(anyhow!("No private key found in {path:?}"));
}; };
Ok(PrivateKey(private_key.secret_der().to_vec())) Ok(private_key)
} }
pub fn tls_connector( pub fn tls_connector(
tls_verify_certificate: bool, tls_verify_certificate: bool,
alpn_protocols: Vec<Vec<u8>>, alpn_protocols: Vec<Vec<u8>>,
enable_sni: bool, enable_sni: bool,
tls_client_certificate: Option<Vec<Certificate>>, tls_client_certificate: Option<Vec<CertificateDer<'static>>>,
tls_client_key: Option<PrivateKey>, tls_client_key: Option<PrivateKeyDer<'static>>,
) -> anyhow::Result<TlsConnector> { ) -> anyhow::Result<TlsConnector> {
let mut root_store = rustls::RootCertStore::empty(); let mut root_store = rustls::RootCertStore::empty();
// Load system certificates and add them to the root store // Load system certificates and add them to the root store
let certs = rustls_native_certs::load_native_certs().with_context(|| "Cannot load system certificates")?; let certs = rustls_native_certs::load_native_certs().with_context(|| "Cannot load system certificates")?;
for cert in certs { for cert in certs {
if let Err(err) = root_store.add(&Certificate(cert.as_ref().to_vec())) { if let Err(err) = root_store.add(cert) {
warn!("cannot load a system certificate: {:?}", err); warn!("cannot load a system certificate: {:?}", err);
continue; continue;
} }
} }
let config_builder = ClientConfig::builder() let config_builder = ClientConfig::builder().with_root_certificates(root_store);
.with_safe_defaults()
.with_root_certificates(root_store);
let mut config = match (tls_client_certificate, tls_client_key) { let mut config = match (tls_client_certificate, tls_client_key) {
(Some(tls_client_certificate), Some(tls_client_key)) => config_builder (Some(tls_client_certificate), Some(tls_client_key)) => config_builder
@ -111,19 +146,20 @@ pub fn tls_acceptor(tls_cfg: &TlsServerConfig, alpn_protocols: Option<Vec<Vec<u8
let mut root_store = rustls::RootCertStore::empty(); let mut root_store = rustls::RootCertStore::empty();
for tls_client_ca_certificate in tls_client_ca_certificates.lock().iter() { for tls_client_ca_certificate in tls_client_ca_certificates.lock().iter() {
root_store root_store
.add(tls_client_ca_certificate) .add(tls_client_ca_certificate.clone())
.with_context(|| "Failed to add mTLS client CA certificate")?; .with_context(|| "Failed to add mTLS client CA certificate")?;
} }
Arc::new(AllowAnyAuthenticatedClient::new(root_store)) WebPkiClientVerifier::builder(Arc::new(root_store))
.build()
.map_err(|err| anyhow!("Failed to build mTLS client verifier: {:?}", err))?
} else { } else {
NoClientAuth::boxed() WebPkiClientVerifier::no_client_auth()
}; };
let mut config = rustls::ServerConfig::builder() let mut config = rustls::ServerConfig::builder()
.with_safe_defaults()
.with_client_cert_verifier(client_cert_verifier) .with_client_cert_verifier(client_cert_verifier)
.with_single_cert(tls_cfg.tls_certificate.lock().clone(), tls_cfg.tls_key.lock().clone()) .with_single_cert(tls_cfg.tls_certificate.lock().clone(), tls_cfg.tls_key.lock().clone_key())
.with_context(|| "invalid tls certificate or private key")?; .with_context(|| "invalid tls certificate or private key")?;
config.key_log = Arc::new(KeyLogFile::new()); config.key_log = Arc::new(KeyLogFile::new());