diff --git a/rpxy-bin/Cargo.toml b/rpxy-bin/Cargo.toml index d6dd842..a8c89e6 100644 --- a/rpxy-bin/Cargo.toml +++ b/rpxy-bin/Cargo.toml @@ -13,7 +13,8 @@ publish.workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [features] -default = ["http3-quinn", "cache", "rustls-backend"] +# default = ["http3-quinn", "cache", "rustls-backend"] +default = ["cache", "rustls-backend"] http3-quinn = ["rpxy-lib/http3-quinn"] http3-s2n = ["rpxy-lib/http3-s2n"] native-tls-backend = ["rpxy-lib/native-tls-backend"] @@ -30,7 +31,6 @@ mimalloc = { version = "*", default-features = false } anyhow = "1.0.86" rustc-hash = "1.1.0" serde = { version = "1.0.202", default-features = false, features = ["derive"] } -derive_builder = "0.20.0" tokio = { version = "1.37.0", default-features = false, features = [ "net", "rt-multi-thread", @@ -39,7 +39,6 @@ tokio = { version = "1.37.0", default-features = false, features = [ "macros", ] } async-trait = "0.1.80" -rustls-pemfile = "1.0.4" # config diff --git a/rpxy-bin/src/cert_file_reader.rs b/rpxy-bin/src/cert_file_reader.rs deleted file mode 100644 index 30c6794..0000000 --- a/rpxy-bin/src/cert_file_reader.rs +++ /dev/null @@ -1,183 +0,0 @@ -use crate::log::*; -use async_trait::async_trait; -use derive_builder::Builder; -use rpxy_lib::{ - reexports::{Certificate, PrivateKey}, - CertsAndKeys, CryptoSource, -}; -use std::{ - fs::File, - io::{self, BufReader, Cursor, Read}, - path::{Path, PathBuf}, -}; - -#[derive(Builder, Debug, Clone)] -/// Crypto-related file reader implementing certs::CryptoRead trait -pub struct CryptoFileSource { - #[builder(setter(custom))] - /// Always exist - pub tls_cert_path: PathBuf, - - #[builder(setter(custom))] - /// Always exist - pub tls_cert_key_path: PathBuf, - - #[builder(setter(custom), default)] - /// This may not exist - pub client_ca_cert_path: Option, -} - -impl CryptoFileSourceBuilder { - pub fn tls_cert_path>(&mut self, v: T) -> &mut Self { - self.tls_cert_path = Some(v.as_ref().to_path_buf()); - self - } - pub fn tls_cert_key_path>(&mut self, v: T) -> &mut Self { - self.tls_cert_key_path = Some(v.as_ref().to_path_buf()); - self - } - pub fn client_ca_cert_path>(&mut self, v: Option) -> &mut Self { - self.client_ca_cert_path = Some(v.map(|p| p.as_ref().to_path_buf())); - self - } -} - -#[async_trait] -impl CryptoSource for CryptoFileSource { - type Error = io::Error; - /// read crypto materials from source - async fn read(&self) -> Result { - read_certs_and_keys( - &self.tls_cert_path, - &self.tls_cert_key_path, - self.client_ca_cert_path.as_ref(), - ) - } - /// Returns true when mutual tls is enabled - fn is_mutual_tls(&self) -> bool { - self.client_ca_cert_path.is_some() - } -} - -/// Read certificates and private keys from file -fn read_certs_and_keys( - cert_path: &PathBuf, - cert_key_path: &PathBuf, - client_ca_cert_path: Option<&PathBuf>, -) -> Result { - debug!("Read TLS server certificates and private key"); - - let certs: Vec<_> = { - let certs_path_str = cert_path.display().to_string(); - let mut reader = BufReader::new( - File::open(cert_path) - .map_err(|e| io::Error::new(e.kind(), format!("Unable to load the certificates [{certs_path_str}]: {e}")))?, - ); - rustls_pemfile::certs(&mut reader) - .map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "Unable to parse the certificates"))? - } - .drain(..) - .map(Certificate) - .collect(); - - let cert_keys: Vec<_> = { - let cert_key_path_str = cert_key_path.display().to_string(); - let encoded_keys = { - let mut encoded_keys = vec![]; - File::open(cert_key_path) - .map_err(|e| { - io::Error::new( - e.kind(), - format!("Unable to load the certificate keys [{cert_key_path_str}]: {e}"), - ) - })? - .read_to_end(&mut encoded_keys)?; - encoded_keys - }; - let mut reader = Cursor::new(encoded_keys); - let pkcs8_keys = rustls_pemfile::pkcs8_private_keys(&mut reader).map_err(|_| { - io::Error::new( - io::ErrorKind::InvalidInput, - "Unable to parse the certificates private keys (PKCS8)", - ) - })?; - reader.set_position(0); - let mut rsa_keys = rustls_pemfile::rsa_private_keys(&mut reader)?; - let mut keys = pkcs8_keys; - keys.append(&mut rsa_keys); - if keys.is_empty() { - return Err(io::Error::new( - io::ErrorKind::InvalidInput, - "No private keys found - Make sure that they are in PKCS#8/PEM format", - )); - } - keys.drain(..).map(PrivateKey).collect() - }; - - let client_ca_certs = if let Some(path) = client_ca_cert_path { - debug!("Read CA certificates for client authentication"); - // Reads client certificate and returns client - let certs: Vec<_> = { - let certs_path_str = path.display().to_string(); - let mut reader = BufReader::new(File::open(path).map_err(|e| { - io::Error::new( - e.kind(), - format!("Unable to load the client certificates [{certs_path_str}]: {e}"), - ) - })?); - rustls_pemfile::certs(&mut reader) - .map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "Unable to parse the client certificates"))? - } - .drain(..) - .map(Certificate) - .collect(); - Some(certs) - } else { - None - }; - - Ok(CertsAndKeys { - certs, - cert_keys, - client_ca_certs, - }) -} - -#[cfg(test)] -mod tests { - use super::*; - #[tokio::test] - async fn read_server_crt_key_files() { - let tls_cert_path = "../example-certs/server.crt"; - let tls_cert_key_path = "../example-certs/server.key"; - let crypto_file_source = CryptoFileSourceBuilder::default() - .tls_cert_key_path(tls_cert_key_path) - .tls_cert_path(tls_cert_path) - .build(); - assert!(crypto_file_source.is_ok()); - - let crypto_file_source = crypto_file_source.unwrap(); - let crypto_elem = crypto_file_source.read().await; - assert!(crypto_elem.is_ok()); - } - - #[tokio::test] - async fn read_server_crt_key_files_with_client_ca_crt() { - let tls_cert_path = "../example-certs/server.crt"; - let tls_cert_key_path = "../example-certs/server.key"; - let client_ca_cert_path = Some("../example-certs/client.ca.crt"); - let crypto_file_source = CryptoFileSourceBuilder::default() - .tls_cert_key_path(tls_cert_key_path) - .tls_cert_path(tls_cert_path) - .client_ca_cert_path(client_ca_cert_path) - .build(); - assert!(crypto_file_source.is_ok()); - - let crypto_file_source = crypto_file_source.unwrap(); - let crypto_elem = crypto_file_source.read().await; - assert!(crypto_elem.is_ok()); - - let crypto_elem = crypto_elem.unwrap(); - assert!(crypto_elem.client_ca_certs.is_some()); - } -} diff --git a/rpxy-bin/src/config/parse.rs b/rpxy-bin/src/config/parse.rs index 535954f..95c87d2 100644 --- a/rpxy-bin/src/config/parse.rs +++ b/rpxy-bin/src/config/parse.rs @@ -1,8 +1,5 @@ use super::toml::ConfigToml; -use crate::{ - cert_file_reader::CryptoFileSource, - error::{anyhow, ensure}, -}; +use crate::error::{anyhow, ensure}; use clap::{Arg, ArgAction}; use hot_reload::{ReloaderReceiver, ReloaderService}; use rpxy_certs::{build_cert_reloader, CryptoFileSourceBuilder, CryptoReloader, ServerCryptoBase}; @@ -43,7 +40,7 @@ pub fn parse_opts() -> Result { Ok(Opts { config_file_path, watch }) } -pub fn build_settings(config: &ConfigToml) -> std::result::Result<(ProxyConfig, AppConfigList), anyhow::Error> { +pub fn build_settings(config: &ConfigToml) -> std::result::Result<(ProxyConfig, AppConfigList), anyhow::Error> { // build proxy config let proxy_config: ProxyConfig = config.try_into()?; @@ -74,7 +71,7 @@ pub fn build_settings(config: &ConfigToml) -> std::result::Result<(ProxyConfig, } // build applications - let mut app_config_list_inner = Vec::>::new(); + let mut app_config_list_inner = Vec::::new(); // let mut backends = Backends::new(); for (app_name, app) in apps.0.iter() { diff --git a/rpxy-bin/src/config/toml.rs b/rpxy-bin/src/config/toml.rs index 7cd3653..9b6502b 100644 --- a/rpxy-bin/src/config/toml.rs +++ b/rpxy-bin/src/config/toml.rs @@ -1,5 +1,4 @@ use crate::{ - cert_file_reader::{CryptoFileSource, CryptoFileSourceBuilder}, constants::*, error::{anyhow, ensure}, }; @@ -214,7 +213,7 @@ impl ConfigToml { } impl Application { - pub fn build_app_config(&self, app_name: &str) -> std::result::Result, anyhow::Error> { + pub fn build_app_config(&self, app_name: &str) -> std::result::Result { let server_name_string = self.server_name.as_ref().ok_or(anyhow!("Missing server_name"))?; // reverse proxy settings @@ -224,11 +223,6 @@ impl Application { let tls_config = if self.tls.is_some() { let tls = self.tls.as_ref().unwrap(); ensure!(tls.tls_cert_key_path.is_some() && tls.tls_cert_path.is_some()); - let inner = CryptoFileSourceBuilder::default() - .tls_cert_path(tls.tls_cert_path.as_ref().unwrap()) - .tls_cert_key_path(tls.tls_cert_key_path.as_ref().unwrap()) - .client_ca_cert_path(tls.client_ca_cert_path.as_deref()) - .build()?; let https_redirection = if tls.https_redirection.is_none() { true // Default true @@ -236,10 +230,7 @@ impl Application { tls.https_redirection.unwrap() }; - Some(TlsConfig { - inner, - https_redirection, - }) + Some(TlsConfig { https_redirection }) } else { None }; diff --git a/rpxy-bin/src/main.rs b/rpxy-bin/src/main.rs index 3c0a63f..d3988e3 100644 --- a/rpxy-bin/src/main.rs +++ b/rpxy-bin/src/main.rs @@ -1,7 +1,6 @@ #[global_allocator] static ALLOC: mimalloc::MiMalloc = mimalloc::MiMalloc; -mod cert_file_reader; mod config; mod constants; mod error; @@ -141,7 +140,7 @@ async fn rpxy_service_with_watcher( /// Wrapper of entry point for rpxy service with certificate management service async fn rpxy_entrypoint( proxy_config: &rpxy_lib::ProxyConfig, - app_config_list: &rpxy_lib::AppConfigList, + app_config_list: &rpxy_lib::AppConfigList, cert_service_and_rx: Option<&( ReloaderService, ReloaderReceiver, diff --git a/rpxy-lib/Cargo.toml b/rpxy-lib/Cargo.toml index fd5df4d..c597d65 100644 --- a/rpxy-lib/Cargo.toml +++ b/rpxy-lib/Cargo.toml @@ -13,7 +13,8 @@ publish.workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [features] -default = ["http3-quinn", "sticky-cookie", "cache", "rustls-backend"] +default = ["sticky-cookie", "cache", "rustls-backend"] +# default = ["http3-quinn", "sticky-cookie", "cache", "rustls-backend"] http3-quinn = ["socket2", "quinn", "h3", "h3-quinn", "rpxy-certs/http3"] http3-s2n = [ "h3", @@ -73,8 +74,8 @@ hyper-rustls = { version = "0.27.1", default-features = false, features = [ # tls and cert management for server rpxy-certs = { path = "../rpxy-certs/", default-features = false } hot_reload = "0.1.5" -rustls = { version = "0.21.12", default-features = false } -tokio-rustls = { version = "0.24.1", features = ["early-data"] } +rustls = { version = "0.23.8", default-features = false } +tokio-rustls = { version = "0.26.0", features = ["early-data"] } webpki = "0.22.4" x509-parser = "0.16.0" diff --git a/rpxy-lib/src/backend/backend_main.rs b/rpxy-lib/src/backend/backend_main.rs index d9fa649..663120e 100644 --- a/rpxy-lib/src/backend/backend_main.rs +++ b/rpxy-lib/src/backend/backend_main.rs @@ -1,5 +1,4 @@ use crate::{ - crypto::CryptoSource, error::*, log::*, name_exp::{ByteName, ServerName}, @@ -13,10 +12,7 @@ use super::upstream::PathManager; /// Struct serving information to route incoming connections, like server name to be handled and tls certs/keys settings. #[derive(Builder)] -pub struct BackendApp -where - T: CryptoSource, -{ +pub struct BackendApp { #[builder(setter(into))] /// backend application name, e.g., app1 pub app_name: String, @@ -28,50 +24,27 @@ where /// tls settings: https redirection with 30x #[builder(default)] pub https_redirection: Option, - /// TLS settings: source meta for server cert, key, client ca cert - #[builder(default)] - pub crypto_source: Option, } -impl<'a, T> BackendAppBuilder -where - T: CryptoSource, -{ +impl<'a> BackendAppBuilder { pub fn server_name(&mut self, server_name: impl Into>) -> &mut Self { self.server_name = Some(server_name.to_server_name()); self } } +#[derive(Default)] /// HashMap and some meta information for multiple Backend structs. -pub struct BackendAppManager -where - T: CryptoSource, -{ +pub struct BackendAppManager { /// HashMap of Backend structs, key is server name - pub apps: HashMap>, + pub apps: HashMap, /// for plaintext http pub default_server_name: Option, } -impl Default for BackendAppManager -where - T: CryptoSource, -{ - fn default() -> Self { - Self { - apps: HashMap::>::default(), - default_server_name: None, - } - } -} - -impl TryFrom<&AppConfig> for BackendApp -where - T: CryptoSource + Clone, -{ +impl TryFrom<&AppConfig> for BackendApp { type Error = RpxyError; - fn try_from(app_config: &AppConfig) -> Result { + fn try_from(app_config: &AppConfig) -> Result { let mut backend_builder = BackendAppBuilder::default(); let path_manager = PathManager::try_from(app_config)?; backend_builder @@ -83,28 +56,20 @@ where backend_builder.build()? } else { let tls = app_config.tls.as_ref().unwrap(); - backend_builder - .https_redirection(Some(tls.https_redirection)) - .crypto_source(Some(tls.inner.clone())) - .build()? + backend_builder.https_redirection(Some(tls.https_redirection)).build()? }; Ok(backend) } } -impl TryFrom<&AppConfigList> for BackendAppManager -where - T: CryptoSource + Clone, -{ +impl TryFrom<&AppConfigList> for BackendAppManager { type Error = RpxyError; - fn try_from(config_list: &AppConfigList) -> Result { + fn try_from(config_list: &AppConfigList) -> Result { let mut manager = Self::default(); for app_config in config_list.inner.iter() { - let backend: BackendApp = BackendApp::try_from(app_config)?; - manager - .apps - .insert(app_config.server_name.clone().to_server_name(), backend); + let backend: BackendApp = BackendApp::try_from(app_config)?; + manager.apps.insert(app_config.server_name.clone().to_server_name(), backend); info!( "Registering application {} ({})", diff --git a/rpxy-lib/src/backend/upstream.rs b/rpxy-lib/src/backend/upstream.rs index 702be29..7d9d569 100644 --- a/rpxy-lib/src/backend/upstream.rs +++ b/rpxy-lib/src/backend/upstream.rs @@ -6,7 +6,6 @@ use super::load_balance::{ // use super::{BytesName, LbContext, PathNameBytesExp, UpstreamOption}; use super::upstream_opts::UpstreamOption; use crate::{ - crypto::CryptoSource, error::RpxyError, globals::{AppConfig, UpstreamUri}, log::*, @@ -28,12 +27,9 @@ pub struct PathManager { inner: HashMap, } -impl TryFrom<&AppConfig> for PathManager -where - T: CryptoSource, -{ +impl TryFrom<&AppConfig> for PathManager { type Error = RpxyError; - fn try_from(app_config: &AppConfig) -> Result { + fn try_from(app_config: &AppConfig) -> Result { let mut inner: HashMap = HashMap::default(); app_config.reverse_proxy.iter().for_each(|rpc| { diff --git a/rpxy-lib/src/constants.rs b/rpxy-lib/src/constants.rs index acc9381..9e2bc6a 100644 --- a/rpxy-lib/src/constants.rs +++ b/rpxy-lib/src/constants.rs @@ -1,21 +1,10 @@ pub const RESPONSE_HEADER_SERVER: &str = "rpxy"; -// pub const LISTEN_ADDRESSES_V4: &[&str] = &["0.0.0.0"]; -// pub const LISTEN_ADDRESSES_V6: &[&str] = &["[::]"]; pub const TCP_LISTEN_BACKLOG: u32 = 1024; -// pub const HTTP_LISTEN_PORT: u16 = 8080; -// pub const HTTPS_LISTEN_PORT: u16 = 8443; pub const PROXY_IDLE_TIMEOUT_SEC: u64 = 20; pub const UPSTREAM_IDLE_TIMEOUT_SEC: u64 = 20; pub const TLS_HANDSHAKE_TIMEOUT_SEC: u64 = 15; // default as with firefox browser pub const MAX_CLIENTS: usize = 512; pub const MAX_CONCURRENT_STREAMS: u32 = 64; -pub const CERTS_WATCH_DELAY_SECS: u32 = 60; -pub const LOAD_CERTS_ONLY_WHEN_UPDATED: bool = true; - -// #[cfg(feature = "http3")] -// pub const H3_RESPONSE_BUF_SIZE: usize = 65_536; // 64KB -// #[cfg(feature = "http3")] -// pub const H3_REQUEST_BUF_SIZE: usize = 65_536; // 64KB // handled by quinn #[allow(non_snake_case)] #[cfg(any(feature = "http3-quinn", feature = "http3-s2n"))] diff --git a/rpxy-lib/src/error.rs b/rpxy-lib/src/error.rs index 3b1afc9..85c05f4 100644 --- a/rpxy-lib/src/error.rs +++ b/rpxy-lib/src/error.rs @@ -59,8 +59,8 @@ pub enum RpxyError { // certificate reloader errors #[error("No certificate reloader when building a proxy for TLS")] NoCertificateReloader, - #[error("Certificate reload error: {0}")] - CertificateReloadError(#[from] hot_reload::ReloaderError), + // #[error("Certificate reload error: {0}")] + // CertificateReloadError(#[from] hot_reload::ReloaderError), // backend errors #[error("Invalid reverse proxy setting")] diff --git a/rpxy-lib/src/globals.rs b/rpxy-lib/src/globals.rs index 1c272dc..fec0a53 100644 --- a/rpxy-lib/src/globals.rs +++ b/rpxy-lib/src/globals.rs @@ -1,9 +1,6 @@ -use crate::{ - constants::*, - count::RequestCount, - crypto::{CryptoSource, ServerCryptoBase}, -}; +use crate::{constants::*, count::RequestCount}; use hot_reload::ReloaderReceiver; +use rpxy_certs::ServerCryptoBase; use std::{net::SocketAddr, sync::Arc, time::Duration}; /// Global object containing proxy configurations and shared object like counters. @@ -17,10 +14,8 @@ pub struct Globals { pub runtime_handle: tokio::runtime::Handle, /// Shared context - Notify object to stop async tasks pub term_notify: Option>, - /// Shared context - Certificate reloader service receiver - pub cert_reloader_rx: Option>, /// Shared context - Certificate reloader service receiver // TODO: newer one - pub cert_reloader_rx_new: Option>, + pub cert_reloader_rx: Option>, } /// Configuration parameters for proxy transport and request handlers @@ -129,24 +124,18 @@ impl Default for ProxyConfig { /// Configuration parameters for backend applications #[derive(PartialEq, Eq, Clone)] -pub struct AppConfigList -where - T: CryptoSource, -{ - pub inner: Vec>, +pub struct AppConfigList { + pub inner: Vec, pub default_app: Option, } /// Configuration parameters for single backend application #[derive(PartialEq, Eq, Clone)] -pub struct AppConfig -where - T: CryptoSource, -{ +pub struct AppConfig { pub app_name: String, pub server_name: String, pub reverse_proxy: Vec, - pub tls: Option>, + pub tls: Option, } /// Configuration parameters for single reverse proxy corresponding to the path @@ -167,10 +156,6 @@ pub struct UpstreamUri { /// Configuration parameters on TLS for a single backend application #[derive(PartialEq, Eq, Clone)] -pub struct TlsConfig -where - T: CryptoSource, -{ - pub inner: T, +pub struct TlsConfig { pub https_redirection: bool, } diff --git a/rpxy-lib/src/lib.rs b/rpxy-lib/src/lib.rs index 4d728a4..ccb647e 100644 --- a/rpxy-lib/src/lib.rs +++ b/rpxy-lib/src/lib.rs @@ -1,7 +1,6 @@ mod backend; mod constants; mod count; -mod crypto; mod error; mod forwarder; mod globals; @@ -12,8 +11,13 @@ mod name_exp; mod proxy; /* ------------------------------------------------ */ use crate::{ - crypto::build_cert_reloader, error::*, forwarder::Forwarder, globals::Globals, log::*, - message_handler::HttpMessageHandlerBuilder, proxy::Proxy, + // crypto::build_cert_reloader, + error::*, + forwarder::Forwarder, + globals::Globals, + log::*, + message_handler::HttpMessageHandlerBuilder, + proxy::Proxy, }; use futures::future::select_all; use hot_reload::ReloaderReceiver; @@ -21,26 +25,19 @@ use rpxy_certs::ServerCryptoBase; use std::sync::Arc; /* ------------------------------------------------ */ -pub use crate::{ - crypto::{CertsAndKeys, CryptoSource}, - globals::{AppConfig, AppConfigList, ProxyConfig, ReverseProxyConfig, TlsConfig, UpstreamUri}, -}; +pub use crate::globals::{AppConfig, AppConfigList, ProxyConfig, ReverseProxyConfig, TlsConfig, UpstreamUri}; pub mod reexports { pub use hyper::Uri; - pub use rustls::{Certificate, PrivateKey}; } /// Entrypoint that creates and spawns tasks of reverse proxy services -pub async fn entrypoint( +pub async fn entrypoint( proxy_config: &ProxyConfig, - app_config_list: &AppConfigList, + app_config_list: &AppConfigList, cert_rx: Option<&ReloaderReceiver>, // TODO: runtime_handle: &tokio::runtime::Handle, term_notify: Option>, -) -> RpxyResult<()> -where - T: CryptoSource + Clone + Send + Sync + 'static, -{ +) -> RpxyResult<()> { #[cfg(all(feature = "http3-quinn", feature = "http3-s2n"))] warn!("Both \"http3-quinn\" and \"http3-s2n\" features are enabled. \"http3-quinn\" will be used"); @@ -82,26 +79,16 @@ where // 1. build backends, and make it contained in Arc let app_manager = Arc::new(backend::BackendAppManager::try_from(app_config_list)?); - // 2. build crypto reloader service - let (cert_reloader_service, cert_reloader_rx) = match proxy_config.https_port { - Some(_) => { - let (s, r) = build_cert_reloader(&app_manager).await?; - (Some(s), Some(r)) - } - None => (None, None), - }; - - // 3. build global shared context + // 2. build global shared context let globals = Arc::new(Globals { proxy_config: proxy_config.clone(), request_count: Default::default(), runtime_handle: runtime_handle.clone(), term_notify: term_notify.clone(), - cert_reloader_rx: cert_reloader_rx.clone(), - cert_reloader_rx_new: cert_rx.cloned(), // TODO: newer one + cert_reloader_rx: cert_rx.cloned(), }); - // 4. build message handler containing Arc-ed http_client and backends, and make it contained in Arc as well + // 3. build message handler containing Arc-ed http_client and backends, and make it contained in Arc as well let forwarder = Arc::new(Forwarder::try_new(&globals).await?); let message_handler = Arc::new( HttpMessageHandlerBuilder::default() @@ -111,7 +98,7 @@ where .build()?, ); - // 5. spawn each proxy for a given socket with copied Arc-ed message_handler. + // 4. spawn each proxy for a given socket with copied Arc-ed message_handler. // build hyper connection builder shared with proxy instances let connection_builder = proxy::connection_builder(&globals); @@ -132,23 +119,9 @@ where globals.runtime_handle.spawn(async move { proxy.start().await }) }); - // wait for all future - match cert_reloader_service { - Some(cert_service) => { - tokio::select! { - _ = cert_service.start() => { - error!("Certificate reloader service got down"); - } - _ = select_all(futures_iter) => { - error!("Some proxy services are down"); - } - } - } - None => { - if let (Ok(Err(e)), _, _) = select_all(futures_iter).await { - error!("Some proxy services are down: {}", e); - } - } + if let (Ok(Err(e)), _, _) = select_all(futures_iter).await { + error!("Some proxy services are down: {}", e); + return Err(e); } Ok(()) diff --git a/rpxy-lib/src/message_handler/handler_main.rs b/rpxy-lib/src/message_handler/handler_main.rs index c46ac85..9ce63f8 100644 --- a/rpxy-lib/src/message_handler/handler_main.rs +++ b/rpxy-lib/src/message_handler/handler_main.rs @@ -7,7 +7,6 @@ use super::{ }; use crate::{ backend::{BackendAppManager, LoadBalanceContext}, - crypto::CryptoSource, error::*, forwarder::{ForwardRequest, Forwarder}, globals::Globals, @@ -34,20 +33,18 @@ pub(super) struct HandlerContext { #[derive(Clone, Builder)] /// HTTP message handler for requests from clients and responses from backend applications, /// responsible to manipulate and forward messages to upstream backends and downstream clients. -pub struct HttpMessageHandler +pub struct HttpMessageHandler where C: Send + Sync + Connect + Clone + 'static, - U: CryptoSource + Clone, { forwarder: Arc>, pub(super) globals: Arc, - app_manager: Arc>, + app_manager: Arc, } -impl HttpMessageHandler +impl HttpMessageHandler where C: Send + Sync + Connect + Clone + 'static, - U: CryptoSource + Clone, { /// Handle incoming request message from a client. /// Responsible to passthrough responses from backend applications or generate synthetic error responses. @@ -64,14 +61,7 @@ where log_data.client_addr(&client_addr); let http_result = self - .handle_request_inner( - &mut log_data, - req, - client_addr, - listen_addr, - tls_enabled, - tls_server_name, - ) + .handle_request_inner(&mut log_data, req, client_addr, listen_addr, tls_enabled, tls_server_name) .await; // passthrough or synthetic response diff --git a/rpxy-lib/src/message_handler/handler_manipulate_messages.rs b/rpxy-lib/src/message_handler/handler_manipulate_messages.rs index fe55fe5..2d77d2c 100644 --- a/rpxy-lib/src/message_handler/handler_manipulate_messages.rs +++ b/rpxy-lib/src/message_handler/handler_manipulate_messages.rs @@ -3,17 +3,15 @@ use crate::{ backend::{BackendApp, UpstreamCandidates}, constants::RESPONSE_HEADER_SERVER, log::*, - CryptoSource, }; use anyhow::{anyhow, ensure, Result}; use http::{header, HeaderValue, Request, Response, Uri}; use hyper_util::client::legacy::connect::Connect; use std::net::SocketAddr; -impl HttpMessageHandler +impl HttpMessageHandler where C: Send + Sync + Connect + Clone + 'static, - U: CryptoSource + Clone, { //////////////////////////////////////////////////// // Functions to generate messages @@ -21,7 +19,7 @@ where #[allow(unused_variables)] /// Manipulate a response message sent from a backend application to forward downstream to a client. - pub(super) fn generate_response_forwarded(&self, response: &mut Response, backend_app: &BackendApp) -> Result<()> { + pub(super) fn generate_response_forwarded(&self, response: &mut Response, backend_app: &BackendApp) -> Result<()> { let headers = response.headers_mut(); remove_connection_header(headers); remove_hop_header(headers); diff --git a/rpxy-lib/src/proxy/mod.rs b/rpxy-lib/src/proxy/mod.rs index 2cc9b75..59bfc3f 100644 --- a/rpxy-lib/src/proxy/mod.rs +++ b/rpxy-lib/src/proxy/mod.rs @@ -11,10 +11,16 @@ mod proxy_quic_s2n; use crate::{ globals::Globals, hyper_ext::rt::{LocalExecutor, TokioTimer}, + name_exp::ServerName, }; use hyper_util::server::{self, conn::auto::Builder as ConnectionBuilder}; +use rustc_hash::FxHashMap as HashMap; +use rustls::ServerConfig; use std::sync::Arc; +/// SNI to ServerConfig map type +pub type SniServerCryptoMap = HashMap>; + pub(crate) use proxy_main::Proxy; /// build connection builder shared with proxy instances diff --git a/rpxy-lib/src/proxy/proxy_main.rs b/rpxy-lib/src/proxy/proxy_main.rs index 9d3baa8..21b2c6b 100644 --- a/rpxy-lib/src/proxy/proxy_main.rs +++ b/rpxy-lib/src/proxy/proxy_main.rs @@ -1,7 +1,6 @@ use super::socket::bind_tcp_socket; use crate::{ constants::TLS_HANDSHAKE_TIMEOUT_SEC, - crypto::{CryptoSource, ServerCrypto, SniServerCryptoMap}, error::*, globals::Globals, hyper_ext::{ @@ -20,14 +19,15 @@ use hyper::{ service::service_fn, }; use hyper_util::{client::legacy::connect::Connect, rt::TokioIo, server::conn::auto::Builder as ConnectionBuilder}; +use rpxy_certs::ServerCrypto; use std::{net::SocketAddr, sync::Arc, time::Duration}; use tokio::time::timeout; /// Wrapper function to handle request for HTTP/1.1 and HTTP/2 /// HTTP/3 is handled in proxy_h3.rs which directly calls the message handler -async fn serve_request( +async fn serve_request( req: Request, - handler: Arc>, + handler: Arc>, client_addr: SocketAddr, listen_addr: SocketAddr, tls_enabled: bool, @@ -35,7 +35,6 @@ async fn serve_request( ) -> RpxyResult> where T: Send + Sync + Connect + Clone, - U: CryptoSource + Clone, { handler .handle_request( @@ -50,10 +49,9 @@ where #[derive(Clone)] /// Proxy main object responsible to serve requests received from clients at the given socket address. -pub(crate) struct Proxy +pub(crate) struct Proxy where T: Send + Sync + Connect + Clone + 'static, - U: CryptoSource + Clone + Sync + Send + 'static, { /// global context shared among async tasks pub globals: Arc, @@ -64,13 +62,12 @@ where /// hyper connection builder serving http request pub connection_builder: Arc>, /// message handler serving incoming http request - pub message_handler: Arc>, + pub message_handler: Arc>, } -impl Proxy +impl Proxy where T: Send + Sync + Connect + Clone + 'static, - U: CryptoSource + Clone + Sync + Send + 'static, { /// Serves requests from clients fn serve_connection(&self, stream: I, peer_addr: SocketAddr, tls_server_name: Option) @@ -164,15 +161,11 @@ where let Some(mut server_crypto_rx) = self.globals.cert_reloader_rx.clone() else { return Err(RpxyError::NoCertificateReloader); }; - // TODO: newer one - let Some(mut server_crypto_rx_new) = self.globals.cert_reloader_rx_new.clone() else { - return Err(RpxyError::NoCertificateReloader); - }; let tcp_socket = bind_tcp_socket(&self.listening_on)?; let tcp_listener = tcp_socket.listen(self.globals.proxy_config.tcp_listen_backlog)?; info!("Start TCP proxy serving with HTTPS request for configured host names"); - let mut server_crypto_map: Option> = None; + let mut server_crypto_map: Option> = None; loop { select! { tcp_cnx = tcp_listener.accept().fuse() => { @@ -234,28 +227,16 @@ where error!("Reloader is broken"); break; } - let cert_keys_map = server_crypto_rx.borrow().clone().unwrap(); - let Some(server_crypto): Option> = (&cert_keys_map).try_into().ok() else { + let server_crypto_base = server_crypto_rx.borrow().clone().unwrap(); + let Some(server_config): Option> = (&server_crypto_base).try_into().ok() else { error!("Failed to update server crypto"); break; }; - server_crypto_map = Some(server_crypto.inner_local_map.clone()); - } - // TODO: newer one - _ = server_crypto_rx_new.changed().fuse() => { - if server_crypto_rx_new.borrow().is_none() { - error!("Reloader is broken"); - break; - } - let cert_keys_map = server_crypto_rx_new.borrow().clone().unwrap(); - // let Some(server_crypto) = cert_keys_map.try_into().ok() else { - // break; - // }; - // let Some(server_crypto): Option> = (&cert_keys_map).try_into().ok() else { - // error!("Failed to update server crypto"); - // break; - // }; - // server_crypto_map = Some(server_crypto.inner_local_map.clone()); + let map = server_config.individual_config_map.clone().iter().map(|(k,v)| { + let server_name = ServerName::from(k.as_slice()); + (server_name, v.clone()) + }).collect::>(); + server_crypto_map = Some(Arc::new(map)); } } }