1use error::Error;
2use handler::{CustomContextData, HttpHandler, MitmFilter};
3use http_client::gen_client;
4use hyper_proxy::Proxy as UpstreamProxy;
5use mitm::MitmProxy;
6use std::{future::Future, marker::PhantomData, net::SocketAddr, sync::Arc};
7use tokio::net::TcpListener;
8use typed_builder::TypedBuilder;
9
10pub use ca::CertificateAuthority;
11pub use hyper;
12pub use rcgen;
13pub use tokio_rustls;
14
15mod ca;
16mod error;
17pub mod handler;
18mod http_client;
19pub mod mitm;
20
21#[derive(TypedBuilder)]
22pub struct Proxy<F, H, D>
23where
24 F: Future<Output = ()>,
25 H: HttpHandler<D>,
26 D: CustomContextData,
27{
28 pub listen_addr: SocketAddr,
30 pub shutdown_signal: F,
32 pub ca: CertificateAuthority,
34 pub upstream_proxy: Option<UpstreamProxy>,
35
36 pub mitm_filters: Vec<String>,
37 pub handler: H,
38
39 #[builder(default)]
40 _custom_contex_data: PhantomData<D>,
41}
42
43impl<F, H, D> Proxy<F, H, D>
44where
45 F: Future<Output = ()>,
46 H: HttpHandler<D>,
47 D: CustomContextData,
48{
49 pub async fn start_proxy(self) -> Result<(), Error> {
50 let client = gen_client(self.upstream_proxy)?;
51 let ca = Arc::new(self.ca);
52 let http_handler = Arc::new(self.handler);
53 let mitm_filter = Arc::new(MitmFilter::new(self.mitm_filters));
54
55 let tcp_listener = TcpListener::bind(self.listen_addr).await?;
56 loop {
57 let client = client.clone();
58 let ca = Arc::clone(&ca);
59 let http_handler = Arc::clone(&http_handler);
60 let mitm_filter = Arc::clone(&mitm_filter);
61
62 if let Ok((tcp_stream, _)) = tcp_listener.accept().await {
63 tokio::spawn(async move {
64 let mitm_proxy = MitmProxy {
65 ca: ca.clone(),
66 client: client.clone(),
67 http_handler: Arc::clone(&http_handler),
68 mitm_filter: Arc::clone(&mitm_filter),
69 custom_contex_data: Default::default(),
70 };
71
72 let mut tls_content_type = [0; 1];
73 if tcp_stream.peek(&mut tls_content_type).await.is_ok() {
74 if tls_content_type[0] <= 0x40 {
75 mitm_proxy.serve_tls(tcp_stream).await;
77 } else {
78 _ = mitm_proxy.serve_stream(tcp_stream).await;
80 }
81 }
82 });
83 }
84 }
85 }
86}