@@ -9,12 +9,14 @@ use hyper::{
99 Method , Request , Response , StatusCode ,
1010} ;
1111use hyper_util:: rt:: { TokioExecutor , TokioIo } ;
12+ use moka:: sync:: Cache ;
1213use std:: { borrow:: Borrow , future:: Future , net:: SocketAddr , sync:: Arc } ;
13- use tls:: server_config ;
14+ use tls:: { generate_cert , CertifiedKeyDer } ;
1415use tokio:: net:: { TcpListener , TcpStream , ToSocketAddrs } ;
1516
1617pub use futures;
1718pub use hyper;
19+ pub use moka;
1820pub use tokio_native_tls;
1921
2022pub mod default_client;
@@ -29,12 +31,20 @@ pub struct MitmProxy<C> {
2931 ///
3032 /// If None, proxy will just tunnel HTTPS traffic and will not observe HTTPS traffic.
3133 pub root_cert : Option < C > ,
34+ /// Cache to store generated certificates. If None, cache will not be used.
35+ /// If root_cert is None, cache will not be used.
36+ ///
37+ /// The key of cache is hostname.
38+ pub cert_cache : Option < Cache < String , CertifiedKeyDer > > ,
3239}
3340
3441impl < C > MitmProxy < C > {
3542 /// Create a new MitmProxy
36- pub fn new ( root_cert : Option < C > ) -> Self {
37- Self { root_cert }
43+ pub fn new ( root_cert : Option < C > , cache : Option < Cache < String , CertifiedKeyDer > > ) -> Self {
44+ Self {
45+ root_cert,
46+ cert_cache : cache,
47+ }
3848 }
3949}
4050
@@ -119,15 +129,20 @@ impl<C: Borrow<rcgen::CertifiedKey> + Send + Sync + 'static> MitmProxy<C> {
119129 ) ;
120130 return ;
121131 } ;
122- if let Some ( root_cert) = proxy. root_cert . as_ref ( ) {
123- let Ok ( server_config) =
124- // Even if URL is modified by middleman, we should sign with original host name to communicate client.
125- server_config ( connect_authority. host ( ) . to_string ( ) , root_cert. borrow ( ) , true )
126- else {
127- tracing:: error!( "Failed to create server config for {}" , connect_authority. host( ) ) ;
128- return ;
132+ if let Some ( server_config) =
133+ proxy. server_config ( connect_authority. host ( ) . to_string ( ) , true )
134+ {
135+ let server_config = match server_config {
136+ Ok ( server_config) => server_config,
137+ Err ( err) => {
138+ tracing:: error!(
139+ "Failed to create server config for {}, {}" ,
140+ connect_authority. host( ) ,
141+ err
142+ ) ;
143+ return ;
144+ }
129145 } ;
130- // TODO: Cache server_config
131146 let server_config = Arc :: new ( server_config) ;
132147 let tls_acceptor = tokio_rustls:: TlsAcceptor :: from ( server_config) ;
133148 let client = match tls_acceptor. accept ( TokioIo :: new ( client) ) . await {
@@ -189,6 +204,48 @@ impl<C: Borrow<rcgen::CertifiedKey> + Send + Sync + 'static> MitmProxy<C> {
189204 . map ( |res| res. map ( |b| b. boxed ( ) ) )
190205 }
191206 }
207+
208+ fn get_certified_key ( & self , host : String ) -> Option < CertifiedKeyDer > {
209+ if let Some ( root_cert) = self . root_cert . as_ref ( ) {
210+ Some ( if let Some ( cache) = self . cert_cache . as_ref ( ) {
211+ cache. get_with ( host. clone ( ) , move || {
212+ generate_cert ( host, root_cert. borrow ( ) )
213+ } )
214+ } else {
215+ generate_cert ( host, root_cert. borrow ( ) )
216+ } )
217+ } else {
218+ None
219+ }
220+ }
221+
222+ fn server_config (
223+ & self ,
224+ host : String ,
225+ h2 : bool ,
226+ ) -> Option < Result < rustls:: ServerConfig , rustls:: Error > > {
227+ if let Some ( cert) = self . get_certified_key ( host) {
228+ let config = rustls:: ServerConfig :: builder ( )
229+ . with_no_client_auth ( )
230+ . with_single_cert (
231+ vec ! [ rustls:: pki_types:: CertificateDer :: from( cert. cert_der) ] ,
232+ rustls:: pki_types:: PrivateKeyDer :: Pkcs8 (
233+ rustls:: pki_types:: PrivatePkcs8KeyDer :: from ( cert. key_der ) ,
234+ ) ,
235+ ) ;
236+
237+ Some ( if h2 {
238+ config. map ( |mut server_config| {
239+ server_config. alpn_protocols = vec ! [ "h2" . into( ) , "http/1.1" . into( ) ] ;
240+ server_config
241+ } )
242+ } else {
243+ config
244+ } )
245+ } else {
246+ None
247+ }
248+ }
192249}
193250
194251fn no_body < E > ( status : StatusCode ) -> Response < BoxBody < Bytes , E > > {
0 commit comments