#http-proxy #proxy #events #http

http-mitm-proxy

A HTTP proxy server library intended to be a backend of application like Burp proxy

13 breaking releases

Uses new Rust 2024

0.14.0 Mar 3, 2025
0.12.0 Dec 6, 2024
0.11.0 Nov 10, 2024
0.8.0 Jul 27, 2024
0.3.0 Nov 27, 2023

#1221 in Network programming

Download history 267/week @ 2024-12-01 120/week @ 2024-12-08 35/week @ 2024-12-15 39/week @ 2024-12-22 69/week @ 2024-12-29 142/week @ 2025-01-05 73/week @ 2025-01-12 157/week @ 2025-01-19 101/week @ 2025-01-26 86/week @ 2025-02-02 106/week @ 2025-02-09 86/week @ 2025-02-16 151/week @ 2025-02-23 242/week @ 2025-03-02 118/week @ 2025-03-09 34/week @ 2025-03-16

580 downloads per month
Used in 2 crates

MIT license

34KB
555 lines

http-mitm-proxy

Crates.io

A HTTP proxy server library intended to be a backend of application like Burp proxy.

  • Sniff HTTP and HTTPS traffic by signing certificate on the fly.
  • Server Sent Event
  • WebSocket ("raw" traffic only. Parsers will not be implemented in this crate.)

Usage

use std::path::PathBuf;

use clap::{Args, Parser};
use http_mitm_proxy::{DefaultClient, MitmProxy, hyper::service::service_fn, moka::sync::Cache};
use tracing_subscriber::EnvFilter;

#[derive(Parser)]
struct Opt {
    #[clap(flatten)]
    external_cert: Option<ExternalCert>,
}

#[derive(Args, Debug)]
struct ExternalCert {
    #[arg(required = false)]
    cert: PathBuf,
    #[arg(required = false)]
    private_key: PathBuf,
}

fn make_root_cert() -> rcgen::CertifiedKey {
    let mut param = rcgen::CertificateParams::default();

    param.distinguished_name = rcgen::DistinguishedName::new();
    param.distinguished_name.push(
        rcgen::DnType::CommonName,
        rcgen::DnValue::Utf8String("<HTTP-MITM-PROXY CA>".to_string()),
    );
    param.key_usages = vec![
        rcgen::KeyUsagePurpose::KeyCertSign,
        rcgen::KeyUsagePurpose::CrlSign,
    ];
    param.is_ca = rcgen::IsCa::Ca(rcgen::BasicConstraints::Unconstrained);

    let key_pair = rcgen::KeyPair::generate().unwrap();
    let cert = param.self_signed(&key_pair).unwrap();

    rcgen::CertifiedKey { cert, key_pair }
}

#[tokio::main]
async fn main() {
    let opt = Opt::parse();

    tracing_subscriber::fmt()
        .with_env_filter(EnvFilter::from_default_env())
        .init();

    let root_cert = if let Some(external_cert) = opt.external_cert {
        // Use existing key
        let param = rcgen::CertificateParams::from_ca_cert_pem(
            &std::fs::read_to_string(&external_cert.cert).unwrap(),
        )
        .unwrap();
        let key_pair =
            rcgen::KeyPair::from_pem(&std::fs::read_to_string(&external_cert.private_key).unwrap())
                .unwrap();

        let cert = param.self_signed(&key_pair).unwrap();

        rcgen::CertifiedKey { cert, key_pair }
    } else {
        make_root_cert()
    };

    let root_cert_pem = root_cert.cert.pem();
    let root_cert_key = root_cert.key_pair.serialize_pem();

    let proxy = MitmProxy::new(
        // This is the root cert that will be used to sign the fake certificates
        Some(root_cert),
        Some(Cache::new(128)),
    );

    let client = DefaultClient::new();
    let server = proxy
        .bind(
            ("127.0.0.1", 3003),
            service_fn(move |req| {
                let client = client.clone();
                async move {
                    let uri = req.uri().clone();

                    // You can modify request here
                    // or You can just return response anywhere

                    let (res, _upgrade) = client.send_request(req).await?;

                    println!("{} -> {}", uri, res.status());

                    // You can modify response here

                    Ok::<_, http_mitm_proxy::default_client::Error>(res)
                }
            }),
        )
        .await
        .unwrap();

    println!("HTTP Proxy is listening on http://127.0.0.1:3003");

    println!();
    println!("Trust this cert if you want to use HTTPS");
    println!();
    println!("{}", root_cert_pem);
    println!();

    /*
        Save this cert to ca.crt and use it with curl like this:
        curl https://www.google.com -x http://127.0.0.1:3003 --cacert ca.crt
    */

    println!("Private key");
    println!("{}", root_cert_key);

    server.await;
}

Dependencies

~19–50MB
~880K SLoC