Configurable Rust HTTP MITM proxy with TLS , HTTP/2 and TCP fingerprint spoofing.
An HTTP MITM proxy built with Rust, tokio, and btls.
This project has been completely rewritten to leverage btls (BoringSSL) for advanced TLS fingerprinting capabilities. The TLS fingerprinting layer (JA3/JA4) is now fully spoofable — cipher suites, curves, signature algorithms, ALPN, record size limit, certificate compression, GREASE, extension permutation/ordering, OCSP stapling, Certificate Transparency (SCT), session tickets, ALPS, and Encrypted Client Hello (ECH, resolved live via DoH, with GREASE fallback) are all driven by a YAML profile. HTTP/2 fingerprinting (Akamai) and HTTP/1.1 header ordering/rewriting are also fully configurable. TCP (L4) fingerprinting is live too: SYN packets of upstream connections are rewritten in NFQUEUE (TTL, window size, MSS, window scale, DF flag, timestamps, exact TCP option order, per-domain marks) with automatic iptables management.
MITM (Man-in-the-Middle) — Transparent HTTPS interception. It uses rcgen to dynamically issue and sign certificates on-the-fly, caching them via moka for performance.
BoringSSL Integration — Uses btls and tokio-btls for TLS handshake handling and MITM interception.
TLS Fingerprint Spoofing (JA3/JA4) — complete. The upstream TLS connection is built entirely from a YAML profile passed via -c / --config <path> (see config.yaml for the format):
brotli, zlib, zstd) with real decompression support.TLS.md for details.Upstream-First ALPN Negotiation — The proxy establishes and negotiates TLS with the upstream server before completing the browser-side TLS handshake. The ALPN selected by the upstream server is then used to configure the client-side TLS acceptor, preventing the browser from selecting a protocol that the upstream connection does not support.
HTTP/2 Fingerprint Spoofing (Akamai) — Fully configurable HTTP/2 fingerprinting through the YAML profile:
END_STREAM placement for empty requests.HTTP/1.1 Header Spoofing — Configurable header order and content for plain HTTP/1.1 upstream connections (when ALPN doesn't negotiate h2), mirroring the same override/removal semantics used for HTTP/2.
TCP Fingerprint Spoofing (L4) — complete. Outgoing upstream connections are fingerprinted at the packet level via Linux NFQUEUE (src/tcp_fingerprint/):
Accept verdict by default so queues never stall.SO_MARK-based routing to per-domain TCP profiles, automatic iptables management (top-inserted above tools like zapret/nfqws, deduplicated, removed on Ctrl+C shutdown) with --queue-bypass safety.TCP.md and the tcp block in config.yaml.Upstream HTTP Proxy Support — Can proxy connections through an upstream HTTP proxy via the CONNECT method.
Per-Domain Profile Routing — Pass -d / --domain <path> with a map of domain patterns to partial profile overlays (see domain.yaml). Each connection is matched by SNI (exact → *.root → *.label.* → label.* → base profile) and served with its own TCP/TLS/HTTP2/HTTP1/upstream settings, prebuilt once at startup. Only the fields that differ from the base profile need to be specified; everything else is inherited.
Asynchronous — Built on tokio for high-performance, non-blocking asynchronous I/O.
cap_net_admin,cap_net_raw=+eip (for SO_MARK, NFQUEUE bind, and automatic iptables; without it set "auto_iptables": false in the tcp block and apply the mangle rules by hand — see TCP.md)The proxy uses tracing with per-module filtering via RUST_LOG.
Examples:
RUST_LOG='H2=error' cargo run --release -- -c profile.yaml
RUST_LOG='TCP=debug,H2=error,TLS=warn' cargo run --release -- -c profile.yaml
RUST_LOG='CA=info,TLS=warn,H2=error' cargo run --release -- -c profile.yaml
Supported tags are the same module names used in the code: TCP, HTTP, H1, H2, TLS, CA, ECH, CFG, IPT, NFQUEUE, Runtime.
Log lines include a timestamp by default, so debugging sessions are easier to correlate.
git clone https://github.com/3Radiance/mitm-proxy-ja3-ja4.git
cd mitm-proxy-ja3-ja4
cargo build --release
All settings — port, upstream proxy, and CA file paths — live in the YAML config passed via -c / --config <path>. There are no --port / --upstream CLI flags.
config:
port: 9090
upstream_proxy: "127.0.0.1:10808"
cert: "/path/to/ca.crt"
key: "/path/to/ca.key"
To run without an upstream proxy, set upstream_proxy: null.
cargo run --release -- --config profile.yaml
# or
cargo run --release -- -c profile.yaml
Upon the first run, if cert/key do not exist yet, the proxy will generate the CA files at the configured paths:
ca.crt — Root CA certificate. You must import this into Firefox/your browser and trust it to identify websites.ca.key — Private key for the CA.cargo run --release -- -c profile.yaml -d domain.yaml
domain.yaml maps domain patterns to partial overlays — only the fields that differ from the base profile:
"browserleaks.com":
config:
upstream_proxy: null
tls:
enable_ech: false
"*.google.com":
tls:
enable_ech: true
"tls.peet.ws":
tcp:
mark: "0x11"
ttl: 100
window_size: 64130
mss: 1400
window_scale: 7
dont_fragment: true
timestamp: false
tcp_options_order:
- mss
- sack_perm
- wscale
- nop