Browse Source

chore: move rule-based handler to separate crate

Signed-off-by: zu1k <[email protected]>
zu1k 3 years ago
parent
commit
2c44c2c66f

+ 18 - 5
Cargo.lock

@@ -681,6 +681,7 @@ dependencies = [
  "clap",
  "env_logger",
  "good-mitm-core",
+ "good-mitm-rule",
  "hyper-proxy",
  "log",
  "rustls",
@@ -696,13 +697,9 @@ dependencies = [
 name = "good-mitm-core"
 version = "0.1.2"
 dependencies = [
- "anyhow",
  "async-trait",
  "bytes",
- "cached",
  "cfg-if",
- "cookie",
- "fancy-regex",
  "http",
  "hyper",
  "hyper-proxy",
@@ -711,7 +708,6 @@ dependencies = [
  "log",
  "moka",
  "openssl",
- "quick-js",
  "rand",
  "rcgen",
  "rustls",
@@ -725,6 +721,23 @@ dependencies = [
  "wildmatch",
 ]
 
+[[package]]
+name = "good-mitm-rule"
+version = "0.1.0"
+dependencies = [
+ "anyhow",
+ "async-trait",
+ "cached",
+ "cookie",
+ "fancy-regex",
+ "good-mitm-core",
+ "http",
+ "hyper",
+ "log",
+ "quick-js",
+ "serde",
+]
+
 [[package]]
 name = "h2"
 version = "0.3.14"

+ 5 - 2
Cargo.toml

@@ -18,9 +18,11 @@ opt-level = "s"
 codegen-units = 1
 
 [dependencies]
+mitm-core = { path = "crates/core", package = "good-mitm-core" }
+rule = { path = "crates/rule", package = "good-mitm-rule" }
+
 anyhow = "1.0"
 clap = { version = "3.0", features = ["derive"] }
-core = { path = "./core", package = "good-mitm-core" }
 thiserror = "1"
 log = "0.4"
 env_logger = "0.9"
@@ -35,6 +37,7 @@ trust_cert = { path = "crates/trust_cert" }
 
 [workspace]
 members = [
-    "core",
+    "crates/core",
+    "crates/rule",
     "crates/trust_cert"
 ]

+ 2 - 8
core/Cargo.toml → crates/core/Cargo.toml

@@ -8,12 +8,9 @@ repository = "https://github.com/zu1k/good-mitm"
 license = "MIT"
 
 [dependencies]
-anyhow = "1.0"
+async-trait = "0.1"
 bytes = { version = "1", features = ["serde"] }
-cached = "0.39"
 cfg-if = "1"
-cookie = "0.16"
-fancy-regex = "0.10"
 http = "0.2"
 hyper = { version = "0.14", features = ["client", "http1", "server", "stream", "tcp"]  }
 hyper-proxy = { version = "0.9", default-features = false }
@@ -31,13 +28,10 @@ tokio = { version = "1", features = ["rt"] }
 tokio-rustls = { version = "0.23", default-features = false, features = ["tls12"] }
 tokio-util = { version = "0.7", features = ["io"] }
 wildmatch = "2.1"
-quick-js = { version = "0.4", features = ["log"] }
 rustls = { version = "0.20", features = ["dangerous_configuration"] }
-rand = "0.8.5"
-async-trait = "0.1.57"
+rand = "0.8"
 
 [features]
 default = ["h2", "request-native-tls"]
 request-native-tls = ["hyper-tls", "openssl"]
 h2 = ["hyper-rustls/http2"]
-custom_handler = []

+ 20 - 4
core/src/ca.rs → crates/core/src/ca.rs

@@ -1,14 +1,13 @@
 use crate::error::Error;
-use cookie::time::OffsetDateTime;
 use http::uri::Authority;
 use moka::future::Cache;
 use rand::{thread_rng, Rng};
 use rcgen::{
-    DistinguishedName, DnType, ExtendedKeyUsagePurpose, KeyPair, KeyUsagePurpose, RcgenError,
-    SanType,
+    BasicConstraints, Certificate, CertificateParams, DistinguishedName, DnType,
+    ExtendedKeyUsagePurpose, IsCa, KeyPair, KeyUsagePurpose, RcgenError, SanType,
 };
 use std::sync::Arc;
-use time::ext::NumericalDuration;
+use time::{ext::NumericalDuration, OffsetDateTime};
 use tokio_rustls::rustls::{self, ServerConfig};
 
 const CERT_TTL_DAYS: u64 = 365;
@@ -28,6 +27,23 @@ pub struct CertificateAuthority {
 }
 
 impl CertificateAuthority {
+    pub fn gen_ca() -> Result<Certificate, RcgenError> {
+        let mut params = CertificateParams::default();
+        let mut distinguished_name = DistinguishedName::new();
+        distinguished_name.push(DnType::CommonName, "Good-MITM");
+        distinguished_name.push(DnType::OrganizationName, "Good-MITM");
+        distinguished_name.push(DnType::CountryName, "CN");
+        distinguished_name.push(DnType::LocalityName, "CN");
+        params.distinguished_name = distinguished_name;
+        params.key_usages = vec![
+            KeyUsagePurpose::DigitalSignature,
+            KeyUsagePurpose::KeyCertSign,
+            KeyUsagePurpose::CrlSign,
+        ];
+        params.is_ca = IsCa::Ca(BasicConstraints::Unconstrained);
+        Certificate::from_params(params)
+    }
+
     /// Attempts to create a new certificate authority.
     ///
     /// This will fail if the provided key or certificate is invalid, or if the key does not match

+ 0 - 0
core/src/error.rs → crates/core/src/error.rs


+ 58 - 0
crates/core/src/handler.rs

@@ -0,0 +1,58 @@
+use async_trait::async_trait;
+use hyper::{Body, Request, Response};
+use std::{
+    marker::PhantomData,
+    sync::{Arc, RwLock},
+};
+use wildmatch::WildMatch;
+
+use crate::mitm::{HttpContext, RequestOrResponse};
+
+pub trait CustomContextData: Clone + Default + Send + Sync + 'static {}
+
+#[async_trait]
+pub trait HttpHandler<D: CustomContextData>: Clone + Send + Sync + 'static {
+    async fn handle_request(
+        &self,
+        _ctx: &mut HttpContext<D>,
+        req: Request<Body>,
+    ) -> RequestOrResponse {
+        RequestOrResponse::Request(req)
+    }
+
+    async fn handle_response(
+        &self,
+        _ctx: &mut HttpContext<D>,
+        res: Response<Body>,
+    ) -> Response<Body> {
+        res
+    }
+}
+
+#[derive(Clone, Default)]
+pub struct MitmFilter<D: CustomContextData> {
+    filters: Arc<RwLock<Vec<WildMatch>>>,
+
+    _custom_contex_data: PhantomData<D>,
+}
+
+impl<D: CustomContextData> MitmFilter<D> {
+    pub fn new(filters: Vec<String>) -> Self {
+        let filters = filters.iter().map(|f| WildMatch::new(f)).collect();
+        Self {
+            filters: Arc::new(RwLock::new(filters)),
+            ..Default::default()
+        }
+    }
+
+    pub async fn filter(&self, _ctx: &HttpContext<D>, req: &Request<Body>) -> bool {
+        let host = req.uri().host().unwrap_or_default();
+        let list = self.filters.read().unwrap();
+        for m in list.iter() {
+            if m.matches(host) {
+                return true;
+            }
+        }
+        false
+    }
+}

+ 0 - 0
core/src/http_client.rs → crates/core/src/http_client.rs


+ 0 - 2
core/src/lib.rs → crates/core/src/lib.rs

@@ -17,12 +17,10 @@ pub use rcgen;
 pub use tokio_rustls;
 
 mod ca;
-mod cache;
 mod error;
 pub mod handler;
 mod http_client;
 pub mod mitm;
-pub mod rule;
 
 #[derive(TypedBuilder)]
 pub struct Proxy<F, H, D>

+ 1 - 1
core/src/mitm.rs → crates/core/src/mitm.rs

@@ -39,7 +39,7 @@ where
     pub client: HttpClient,
 
     pub http_handler: Arc<H>,
-    pub mitm_filter: Arc<MitmFilter>,
+    pub mitm_filter: Arc<MitmFilter<D>>,
 
     pub custom_contex_data: PhantomData<D>,
 }

+ 19 - 0
crates/rule/Cargo.toml

@@ -0,0 +1,19 @@
+[package]
+name = "good-mitm-rule"
+version = "0.1.0"
+edition = "2021"
+
+
+[dependencies]
+mitm-core = { path = "../core", package = "good-mitm-core" }
+
+anyhow = "1.0"
+async-trait = "0.1"
+cached = "0.39"
+cookie = "0.16"
+fancy-regex = "0.10"
+http = "0.2"
+hyper = { version = "0.14", features = ["client", "http1", "server", "stream", "tcp"]  }
+log = "0.4"
+quick-js = { version = "0.4", features = ["log"] }
+serde = { version = "1.0", features = ["derive"] }

+ 0 - 0
core/src/rule/action/js.rs → crates/rule/src/action/js.rs


+ 0 - 0
core/src/rule/action/log.rs → crates/rule/src/action/log.rs


+ 0 - 0
core/src/rule/action/mod.rs → crates/rule/src/action/mod.rs


+ 0 - 0
core/src/rule/action/modify.rs → crates/rule/src/action/modify.rs


+ 0 - 0
core/src/cache.rs → crates/rule/src/cache.rs


+ 0 - 0
core/src/rule/filter/mod.rs → crates/rule/src/filter.rs


+ 4 - 51
core/src/handler.rs → crates/rule/src/handler.rs

@@ -1,34 +1,12 @@
+use crate::Rule;
 use async_trait::async_trait;
 use hyper::{header, Body, Request, Response};
 use log::info;
-use std::sync::{Arc, RwLock};
-use wildmatch::WildMatch;
-
-use crate::{
+use mitm_core::{
+    handler::{CustomContextData, HttpHandler},
     mitm::{HttpContext, RequestOrResponse},
-    rule::Rule,
 };
-
-pub trait CustomContextData: Clone + Default + Send + Sync + 'static {}
-
-#[async_trait]
-pub trait HttpHandler<D: CustomContextData>: Clone + Send + Sync + 'static {
-    async fn handle_request(
-        &self,
-        _ctx: &mut HttpContext<D>,
-        req: Request<Body>,
-    ) -> RequestOrResponse {
-        RequestOrResponse::Request(req)
-    }
-
-    async fn handle_response(
-        &self,
-        _ctx: &mut HttpContext<D>,
-        res: Response<Body>,
-    ) -> Response<Body> {
-        res
-    }
-}
+use std::sync::Arc;
 
 #[derive(Clone)]
 pub struct RuleHttpHandler {
@@ -118,28 +96,3 @@ impl HttpHandler<RuleHandlerCtx> for RuleHttpHandler {
         res
     }
 }
-
-#[derive(Clone, Default)]
-pub struct MitmFilter {
-    filters: Arc<RwLock<Vec<WildMatch>>>,
-}
-
-impl MitmFilter {
-    pub fn new(filters: Vec<String>) -> Self {
-        let filters = filters.iter().map(|f| WildMatch::new(f)).collect();
-        Self {
-            filters: Arc::new(RwLock::new(filters)),
-        }
-    }
-
-    pub async fn filter(&self, _ctx: &HttpContext<RuleHandlerCtx>, req: &Request<Body>) -> bool {
-        let host = req.uri().host().unwrap_or_default();
-        let list = self.filters.read().unwrap();
-        for m in list.iter() {
-            if m.matches(host) {
-                return true;
-            }
-        }
-        false
-    }
-}

+ 8 - 6
core/src/rule/mod.rs → crates/rule/src/lib.rs

@@ -1,13 +1,15 @@
+pub use action::Action;
+pub use filter::Filter;
+pub use handler::*;
 use hyper::{header, header::HeaderValue, Body, Request, Response, StatusCode};
 use log::*;
+use mitm_core::mitm::RequestOrResponse;
 use std::vec::Vec;
 
-use crate::{cache, mitm::RequestOrResponse};
-pub use action::Action;
-pub use filter::Filter;
-
 mod action;
+mod cache;
 mod filter;
+mod handler;
 
 #[derive(Debug, Clone)]
 pub struct Rule {
@@ -85,7 +87,7 @@ impl Rule {
                     action::log_req(&tmp_req).await;
                 }
 
-                Action::Js(code) => {
+                Action::Js(ref code) => {
                     info!("[LogRequest] {}", url);
                     if let Ok(req) = action::js::modify_req(code, tmp_req).await {
                         return RequestOrResponse::Request(req);
@@ -120,7 +122,7 @@ impl Rule {
                     action::log_res(&tmp_res).await;
                 }
 
-                Action::Js(code) => {
+                Action::Js(ref code) => {
                     info!("[LogResponse] {}", url);
                     if let Ok(res) = action::js::modify_res(code, tmp_res).await {
                         return res;

+ 2 - 15
src/ca.rs

@@ -1,22 +1,9 @@
-use core::rcgen::*;
 use log::error;
+use mitm_core::rcgen::*;
 use std::fs;
 
 pub fn gen_ca() -> Certificate {
-    let mut params = CertificateParams::default();
-    let mut distinguished_name = DistinguishedName::new();
-    distinguished_name.push(DnType::CommonName, "Good-MITM");
-    distinguished_name.push(DnType::OrganizationName, "Good-MITM");
-    distinguished_name.push(DnType::CountryName, "CN");
-    distinguished_name.push(DnType::LocalityName, "CN");
-    params.distinguished_name = distinguished_name;
-    params.key_usages = vec![
-        KeyUsagePurpose::DigitalSignature,
-        KeyUsagePurpose::KeyCertSign,
-        KeyUsagePurpose::CrlSign,
-    ];
-    params.is_ca = IsCa::Ca(BasicConstraints::Unconstrained);
-    let cert = Certificate::from_params(params).unwrap();
+    let cert = mitm_core::CertificateAuthority::gen_ca().expect("mitm-core generate cert");
     let cert_crt = cert.serialize_pem().unwrap();
 
     fs::create_dir("ca").unwrap();

+ 1 - 1
src/error.rs

@@ -1,4 +1,4 @@
-use core::rcgen::RcgenError;
+use mitm_core::rcgen::RcgenError;
 use thiserror::Error;
 
 #[derive(Debug, Error)]

+ 7 - 7
src/file/rule.rs → src/file/frule.rs

@@ -8,23 +8,23 @@ pub struct Rule {
     #[serde(alias = "mitm")]
     pub mitm_list: Option<SingleOrMulti<String>>,
     #[serde(alias = "filter")]
-    pub filters: SingleOrMulti<core::rule::Filter>,
+    pub filters: SingleOrMulti<rule::Filter>,
     #[serde(alias = "action")]
-    pub actions: SingleOrMulti<core::rule::Action>,
+    pub actions: SingleOrMulti<rule::Action>,
 }
 
-impl From<Rule> for (core::rule::Rule, Vec<String>) {
+impl From<Rule> for (rule::Rule, Vec<String>) {
     fn from(rule: Rule) -> Self {
-        let filters: Vec<core::rule::Filter> = rule
+        let filters: Vec<rule::Filter> = rule
             .filters
             .into_vec()
             .iter()
-            .map(core::rule::Filter::init)
+            .map(rule::Filter::init)
             .collect();
 
         let mut mitm_filters: Vec<String> = filters
             .iter()
-            .filter_map(core::rule::Filter::mitm_filtter_pattern)
+            .filter_map(rule::Filter::mitm_filtter_pattern)
             .collect();
 
         let mut mitm_list_2 = match rule.mitm_list {
@@ -33,7 +33,7 @@ impl From<Rule> for (core::rule::Rule, Vec<String>) {
         };
         mitm_filters.append(&mut mitm_list_2);
 
-        let rule = core::rule::Rule {
+        let rule = rule::Rule {
             filters,
             actions: rule.actions.into_vec(),
             url: None,

+ 5 - 5
src/file/mod.rs

@@ -3,12 +3,12 @@ use std::{fs, io::BufReader, path::Path};
 
 use single_multi::SingleOrMulti;
 
-pub mod rule;
+pub mod frule;
 mod single_multi;
 
 pub fn load_rules_amd_mitm_filters<P: AsRef<Path>>(
     path: P,
-) -> Result<(Vec<core::rule::Rule>, Vec<String>)> {
+) -> Result<(Vec<rule::Rule>, Vec<String>)> {
     let m = fs::metadata(&path).expect("Not a valid path");
     if m.file_type().is_dir() {
         load_rules_amd_mitm_filters_from_dir(path)
@@ -19,10 +19,10 @@ pub fn load_rules_amd_mitm_filters<P: AsRef<Path>>(
 
 fn load_rules_amd_mitm_filters_from_file<P: AsRef<Path>>(
     path: P,
-) -> Result<(Vec<core::rule::Rule>, Vec<String>)> {
+) -> Result<(Vec<rule::Rule>, Vec<String>)> {
     let file = fs::File::open(path)?;
     let reader = BufReader::new(file);
-    let rules: Vec<rule::Rule> = serde_yaml::from_reader(reader)?;
+    let rules: Vec<frule::Rule> = serde_yaml::from_reader(reader)?;
 
     let (rules, filters) = rules
         .into_iter()
@@ -38,7 +38,7 @@ fn load_rules_amd_mitm_filters_from_file<P: AsRef<Path>>(
 
 fn load_rules_amd_mitm_filters_from_dir<P: AsRef<Path>>(
     path: P,
-) -> Result<(Vec<core::rule::Rule>, Vec<String>)> {
+) -> Result<(Vec<rule::Rule>, Vec<String>)> {
     let dir = fs::read_dir(path).expect("Not a valid dir");
 
     let (rules, filters) = dir

+ 2 - 1
src/main.rs

@@ -2,9 +2,10 @@
 
 use anyhow::{Ok, Result};
 use clap::Parser;
-use core::{handler::RuleHttpHandler, CertificateAuthority, Proxy};
 use hyper_proxy::Intercept;
 use log::*;
+use mitm_core::{CertificateAuthority, Proxy};
+use rule::RuleHttpHandler;
 use rustls_pemfile as pemfile;
 use std::{fs, sync::Arc};