#[path = "../src/config.rs"] mod config; #[path = "../src/datagram.rs"] mod datagram; #[path = "../src/protocol/mod.rs"] mod protocol; #[path = "../src/stats.rs"] mod stats; #[path = "../src/transport/mod.rs"] mod transport; use std::{process::Command, sync::Arc, time::Duration}; use bytes::Bytes; use config::Config; use rustls::RootCertStore; use tempfile::tempdir; use tokio::time::timeout; use transport::{TlsTcpConnector, TlsTcpServer, TransportConnector, TransportSession}; const SECRET: &str = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; fn free_port() -> u16 { std::net::TcpListener::bind("127.0.0.1:0") .unwrap() .local_addr() .unwrap() .port() } #[tokio::test] async fn tls_tcp_authenticates_and_round_trips_opaque_datagrams() { if Command::new("openssl").arg("version").output().is_err() { return; } let dir = tempdir().unwrap(); let cert = dir.path().join("cert.pem"); let key = dir.path().join("key.pem"); let generated = Command::new("openssl") .args([ "req", "-x509", "-newkey", "rsa:2048", "-nodes", "-subj", "/CN=localhost", "-days", "1", "-keyout", ]) .arg(&key) .args(["-out"]) .arg(&cert) .output() .unwrap(); assert!( generated.status.success(), "openssl failed: {:?}", generated ); let port = free_port(); let server_config = Config::from_str(&format!( "[server]\nlisten = \"127.0.0.1\"\n[backend]\ntarget = \"127.0.0.1:51820\"\n[transports.direct_udp]\nenabled = false\n[transports.quic]\nenabled = false\n[transports.http3]\nenabled = false\n[transports.tls_tcp]\nenabled = true\nport = {port}\n[tls]\ncertificate = \"{}\"\nprivate_key = \"{}\"\n[[auth.clients]]\nid = \"test\"\nsecret = \"{SECRET}\"\n", cert.display(), key.display() )) .unwrap() .into_server() .unwrap(); let client_config = Config::from_str(&format!( "[client]\nserver = \"localhost\"\nid = \"test\"\nsecret = \"{SECRET}\"\n[transport]\nmode = \"tls_tcp\"\n[transport.tls_tcp]\nport = {port}\n[network]\nmax_datagram_size = 1200\n" )) .unwrap() .into_client() .unwrap(); let certs = transport::tls_tcp::load_certificates(&cert).unwrap(); let mut roots = RootCertStore::empty(); roots.add(certs[0].clone()).unwrap(); let client_tls = (*transport::tls_tcp::client_tls_config(roots)).clone(); let server = Arc::new(TlsTcpServer::bind(&server_config).await.unwrap()); let accept = { let server = server.clone(); tokio::spawn(async move { server.accept_session().await }) }; let client = TlsTcpConnector::with_client_config(client_config, client_tls); let client_session = client.connect().await.unwrap(); let server_session = accept.await.unwrap().unwrap(); client_session .send_datagram(Bytes::from_static(b"tls-opaque")) .await .unwrap(); assert_eq!( timeout(Duration::from_secs(2), server_session.recv_datagram()) .await .unwrap() .unwrap(), Bytes::from_static(b"tls-opaque") ); client_session.close().await.unwrap(); server_session.close().await.unwrap(); }