diff --git a/src/backend/mod.rs b/src/backend/mod.rs index c8298c3..9bc28e5 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -13,14 +13,20 @@ pub use self::{ upstream::{ReverseProxy, Upstream, UpstreamGroup, UpstreamGroupBuilder}, upstream_opts::UpstreamOption, }; -use crate::utils::{BytesName, PathNameBytesExp, ServerNameBytesExp}; +use crate::{ + certs::CryptoSource, + utils::{BytesName, PathNameBytesExp, ServerNameBytesExp}, +}; use derive_builder::Builder; use rustc_hash::FxHashMap as HashMap; use std::{borrow::Cow, path::PathBuf}; /// Struct serving information to route incoming connections, like server name to be handled and tls certs/keys settings. #[derive(Builder)] -pub struct Backend { +pub struct Backend +where + T: CryptoSource, +{ #[builder(setter(into))] /// backend application name, e.g., app1 pub app_name: String, @@ -39,8 +45,14 @@ pub struct Backend { pub https_redirection: Option, #[builder(setter(custom), default)] pub client_ca_cert_path: Option, + + #[builder(default)] + pub crypto_source: Option, } -impl<'a> BackendBuilder { +impl<'a, T> BackendBuilder +where + T: CryptoSource, +{ pub fn server_name(&mut self, server_name: impl Into>) -> &mut Self { self.server_name = Some(server_name.into().to_ascii_lowercase()); self @@ -63,9 +75,23 @@ fn opt_string_to_opt_pathbuf(input: &Option) -> Option { input.to_owned().as_ref().map(PathBuf::from) } -#[derive(Default)] /// HashMap and some meta information for multiple Backend structs. -pub struct Backends { - pub apps: HashMap, // hyper::uriで抜いたhostで引っ掛ける +pub struct Backends +where + T: CryptoSource, +{ + pub apps: HashMap>, // hyper::uriで抜いたhostで引っ掛ける pub default_server_name_bytes: Option, // for plaintext http } + +impl Backends +where + T: CryptoSource, +{ + pub fn new() -> Self { + Backends { + apps: HashMap::>::default(), + default_server_name_bytes: None, + } + } +} diff --git a/src/cert_file_reader.rs b/src/cert_file_reader.rs index c3a3310..dc25b09 100644 --- a/src/cert_file_reader.rs +++ b/src/cert_file_reader.rs @@ -11,7 +11,7 @@ use std::{ path::PathBuf, }; -#[derive(Builder, Debug)] +#[derive(Builder, Debug, Clone)] /// Crypto-related file reader implementing certs::CryptoRead trait pub struct CryptoFileSource { #[builder(setter(custom))] diff --git a/src/config/parse.rs b/src/config/parse.rs index 1593aba..83aa546 100644 --- a/src/config/parse.rs +++ b/src/config/parse.rs @@ -1,9 +1,12 @@ use super::toml::ConfigToml; -use crate::{backend::Backends, error::*, globals::*, log::*, utils::BytesName}; +use crate::{backend::Backends, certs::CryptoSource, error::*, globals::*, log::*, utils::BytesName}; use clap::Arg; use tokio::runtime::Handle; -pub fn build_globals(runtime_handle: Handle) -> std::result::Result { +pub fn build_globals(runtime_handle: Handle) -> std::result::Result, anyhow::Error> +where + T: CryptoSource + Clone, +{ let _ = include_str!("../../Cargo.toml"); let options = clap::command!().arg( Arg::new("config_file") @@ -72,7 +75,7 @@ pub fn build_globals(runtime_handle: Handle) -> std::result::Result for &Application { +impl TryInto> for &Application +where + T: CryptoSource + Clone, +{ type Error = anyhow::Error; - fn try_into(self) -> std::result::Result { + fn try_into(self) -> std::result::Result, Self::Error> { let server_name_string = self.server_name.as_ref().ok_or(anyhow!("Missing server_name"))?; // backend builder diff --git a/src/globals.rs b/src/globals.rs index 64f9d8d..b85733b 100644 --- a/src/globals.rs +++ b/src/globals.rs @@ -1,3 +1,4 @@ +use crate::certs::CryptoSource; use crate::{backend::Backends, constants::*}; use std::net::SocketAddr; use std::sync::{ @@ -8,12 +9,15 @@ use tokio::time::Duration; /// Global object containing proxy configurations and shared object like counters. /// But note that in Globals, we do not have Mutex and RwLock. It is indeed, the context shared among async tasks. -pub struct Globals { +pub struct Globals +where + T: CryptoSource, +{ /// Configuration parameters for proxy transport and request handlers pub proxy_config: ProxyConfig, // TODO: proxy configはarcに包んでこいつだけ使いまわせばいいように変えていく。backendsも? /// Backend application objects to which http request handler forward incoming requests - pub backends: Backends, + pub backends: Backends, /// Shared context - Counter for serving requests pub request_count: RequestCount, diff --git a/src/handler/handler_main.rs b/src/handler/handler_main.rs index d2a47be..2016f2c 100644 --- a/src/handler/handler_main.rs +++ b/src/handler/handler_main.rs @@ -2,6 +2,7 @@ use super::{utils_headers::*, utils_request::*, utils_synth_response::*, HandlerContext}; use crate::{ backend::{Backend, UpstreamGroup}, + certs::CryptoSource, error::*, globals::Globals, log::*, @@ -18,17 +19,19 @@ use std::{env, net::SocketAddr, sync::Arc}; use tokio::{io::copy_bidirectional, time::timeout}; #[derive(Clone, Builder)] -pub struct HttpMessageHandler +pub struct HttpMessageHandler where T: Connect + Clone + Sync + Send + 'static, + U: CryptoSource + Clone, { forwarder: Arc>, - globals: Arc, + globals: Arc>, } -impl HttpMessageHandler +impl HttpMessageHandler where T: Connect + Clone + Sync + Send + 'static, + U: CryptoSource + Clone, { fn return_with_error_log(&self, status_code: StatusCode, log_data: &mut MessageLog) -> Result> { log_data.status_code(&status_code).output(); @@ -194,11 +197,10 @@ where //////////////////////////////////////////////////// // Functions to generate messages - fn generate_response_forwarded( - &self, - response: &mut Response, - chosen_backend: &Backend, - ) -> Result<()> { + fn generate_response_forwarded(&self, response: &mut Response, chosen_backend: &Backend) -> Result<()> + where + B: core::fmt::Debug, + { let headers = response.headers_mut(); remove_connection_header(headers); remove_hop_header(headers); diff --git a/src/main.rs b/src/main.rs index 526c290..7f8dcfc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,4 @@ +use certs::CryptoSource; #[cfg(not(target_env = "msvc"))] use tikv_jemallocator::Jemalloc; @@ -18,7 +19,8 @@ mod proxy; mod utils; use crate::{ - config::build_globals, error::*, globals::*, handler::HttpMessageHandlerBuilder, log::*, proxy::ProxyBuilder, + cert_file_reader::CryptoFileSource, config::build_globals, error::*, globals::*, handler::HttpMessageHandlerBuilder, + log::*, proxy::ProxyBuilder, }; use futures::future::select_all; use hyper::Client; @@ -34,7 +36,7 @@ fn main() { let runtime = runtime_builder.build().unwrap(); runtime.block_on(async { - let globals = match build_globals(runtime.handle().clone()) { + let globals: Globals = match build_globals(runtime.handle().clone()) { Ok(g) => g, Err(e) => { error!("Invalid configuration: {}", e); @@ -48,7 +50,10 @@ fn main() { } // entrypoint creates and spawns tasks of proxy services -async fn entrypoint(globals: Arc) -> Result<()> { +async fn entrypoint(globals: Arc>) -> Result<()> +where + T: CryptoSource + Clone + Send + Sync + 'static, +{ // let connector = TrustDnsResolver::default().into_rustls_webpki_https_connector(); let connector = hyper_rustls::HttpsConnectorBuilder::new() .with_webpki_roots() diff --git a/src/proxy/crypto_service.rs b/src/proxy/crypto_service.rs index 629119b..bb582fa 100644 --- a/src/proxy/crypto_service.rs +++ b/src/proxy/crypto_service.rs @@ -1,6 +1,6 @@ use crate::{ cert_file_reader::read_certs_and_keys, // TODO: Trait defining read_certs_and_keys and add struct implementing the trait to backend when build backend - certs::CertsAndKeys, + certs::{CertsAndKeys, CryptoSource}, globals::Globals, log::*, utils::ServerNameBytesExp, @@ -18,8 +18,11 @@ use x509_parser::prelude::*; #[derive(Clone)] /// Reloader service for certificates and keys for TLS -pub struct CryptoReloader { - globals: Arc, +pub struct CryptoReloader +where + T: CryptoSource, +{ + globals: Arc>, } pub type SniServerCryptoMap = HashMap>; @@ -37,8 +40,11 @@ pub struct ServerCryptoBase { } #[async_trait] -impl Reload for CryptoReloader { - type Source = Arc; +impl Reload for CryptoReloader +where + T: CryptoSource + Sync + Send, +{ + type Source = Arc>; async fn new(source: &Self::Source) -> Result> { Ok(Self { globals: source.clone(), diff --git a/src/proxy/proxy_h3.rs b/src/proxy/proxy_h3.rs index 12ebd7d..324060f 100644 --- a/src/proxy/proxy_h3.rs +++ b/src/proxy/proxy_h3.rs @@ -1,14 +1,15 @@ use super::Proxy; -use crate::{error::*, log::*, utils::ServerNameBytesExp}; +use crate::{certs::CryptoSource, error::*, log::*, utils::ServerNameBytesExp}; use bytes::{Buf, Bytes}; use h3::{quic::BidiStream, server::RequestStream}; use hyper::{client::connect::Connect, Body, Request, Response}; use std::net::SocketAddr; use tokio::time::{timeout, Duration}; -impl Proxy +impl Proxy where T: Connect + Clone + Sync + Send + 'static, + U: CryptoSource + Clone + Sync + Send + 'static, { pub(super) async fn connection_serve_h3( self, diff --git a/src/proxy/proxy_main.rs b/src/proxy/proxy_main.rs index a0f9660..e5a02a5 100644 --- a/src/proxy/proxy_main.rs +++ b/src/proxy/proxy_main.rs @@ -1,5 +1,7 @@ // use super::proxy_handler::handle_request; -use crate::{error::*, globals::Globals, handler::HttpMessageHandler, log::*, utils::ServerNameBytesExp}; +use crate::{ + certs::CryptoSource, error::*, globals::Globals, handler::HttpMessageHandler, log::*, utils::ServerNameBytesExp, +}; use derive_builder::{self, Builder}; use hyper::{client::connect::Connect, server::conn::Http, service::service_fn, Body, Request}; use std::{net::SocketAddr, sync::Arc}; @@ -32,19 +34,21 @@ where } #[derive(Clone, Builder)] -pub struct Proxy +pub struct Proxy where T: Connect + Clone + Sync + Send + 'static, + U: CryptoSource + Clone + Sync + Send + 'static, { pub listening_on: SocketAddr, pub tls_enabled: bool, // TCP待受がTLSかどうか - pub msg_handler: HttpMessageHandler, - pub globals: Arc, + pub msg_handler: HttpMessageHandler, + pub globals: Arc>, } -impl Proxy +impl Proxy where T: Connect + Clone + Sync + Send + 'static, + U: CryptoSource + Clone + Sync + Send, { pub(super) fn client_serve( self, diff --git a/src/proxy/proxy_tls.rs b/src/proxy/proxy_tls.rs index e01f9d3..5e846f0 100644 --- a/src/proxy/proxy_tls.rs +++ b/src/proxy/proxy_tls.rs @@ -2,7 +2,7 @@ use super::{ crypto_service::{CryptoReloader, ServerCrypto, ServerCryptoBase, SniServerCryptoMap}, proxy_main::{LocalExecutor, Proxy}, }; -use crate::{constants::*, error::*, log::*, utils::BytesName}; +use crate::{certs::CryptoSource, constants::*, error::*, log::*, utils::BytesName}; use hot_reload::{ReloaderReceiver, ReloaderService}; use hyper::{client::connect::Connect, server::conn::Http}; #[cfg(feature = "http3")] @@ -15,9 +15,10 @@ use tokio::{ time::{timeout, Duration}, }; -impl Proxy +impl Proxy where T: Connect + Clone + Sync + Send + 'static, + U: CryptoSource + Clone + Sync + Send + 'static, { // TCP Listener Service, i.e., http/2 and http/1.1 async fn listener_service( @@ -181,7 +182,7 @@ where } pub async fn start_with_tls(self, server: Http) -> Result<()> { - let (cert_reloader_service, cert_reloader_rx) = ReloaderService::::new( + let (cert_reloader_service, cert_reloader_rx) = ReloaderService::, ServerCryptoBase>::new( &self.globals.clone(), CERTS_WATCH_DELAY_SECS, !LOAD_CERTS_ONLY_WHEN_UPDATED,