Skip to main content

soth_mitm/
lib.rs

1// Internal items are only reachable when __internal is enabled; suppress dead-code
2// warnings for the public build where those modules are gated out.
3#![cfg_attr(not(feature = "__internal"), allow(dead_code))]
4
5//! # soth-mitm
6//!
7//! Rust intercepting proxy crate with deterministic handler/event contracts.
8//!
9//! `soth-mitm` provides a MITM (man-in-the-middle) proxy that intercepts HTTP/1.1,
10//! HTTP/2, WebSocket, gRPC, and SSE traffic over TLS. It exposes a trait-based
11//! handler API that lets you inspect, allow, or block requests in real time.
12//!
13//! ## Quick Start
14//!
15//! ```rust,no_run
16//! use bytes::Bytes;
17//! use soth_mitm::{
18//!     HandlerDecision, InterceptHandler, MitmConfig, MitmProxyBuilder, RawRequest,
19//! };
20//!
21//! struct MyHandler;
22//!
23//! impl InterceptHandler for MyHandler {
24//!     async fn on_request(&self, request: &RawRequest) -> HandlerDecision {
25//!         if request.path.contains("/blocked") {
26//!             return HandlerDecision::Block {
27//!                 status: 403,
28//!                 body: Bytes::from_static(b"blocked"),
29//!             };
30//!         }
31//!         HandlerDecision::Allow
32//!     }
33//! }
34//!
35//! fn main() -> Result<(), Box<dyn std::error::Error>> {
36//!     let mut config = MitmConfig::default();
37//!     config
38//!         .interception
39//!         .destinations
40//!         .push("api.example.com:443".to_string());
41//!
42//!     let _proxy = MitmProxyBuilder::new(config, MyHandler).build()?;
43//!     Ok(())
44//! }
45//! ```
46//!
47//! ## Feature Flags
48//!
49//! | Flag | Default | Description |
50//! |------|---------|-------------|
51//! | `openssl-backend` | off | Enables OpenSSL-based CA material validation on cert load |
52//! | `__internal` | off | Exposes internal modules for integration tests — **not stable API** |
53//!
54//! ## Minimum Supported Rust Version
55//!
56//! This crate requires **Rust 1.88** or later.
57//!
58//! ## License
59//!
60//! Licensed under the [Mozilla Public License 2.0](https://www.mozilla.org/en-US/MPL/2.0/).
61
62// Consolidated sub-crate modules
63pub(crate) mod engine;
64pub(crate) mod observe;
65pub(crate) mod policy;
66pub(crate) mod protocol;
67pub(crate) mod server;
68pub(crate) mod tls;
69
70// Facade modules
71mod actions;
72mod builder;
73mod ca;
74mod ca_trust;
75mod config;
76mod destination;
77mod errors;
78#[cfg(test)]
79mod fingerprint_capture;
80mod handler;
81mod metrics;
82mod process;
83mod proxy;
84mod runtime;
85mod types;
86
87pub use actions::HandlerDecision;
88pub use builder::MitmProxyBuilder;
89pub use ca::{
90    generate_ca, install_ca_system_trust, is_ca_trusted, load_ca, load_ca_from_files,
91    uninstall_ca_system_trust, CertificateAuthority,
92};
93pub use config::{
94    BodyConfig, ConnectionPoolConfig, FlowRuntimeConfig, H2ResponseOverflowMode, HandlerConfig,
95    InterceptMode, InterceptionScope, MitmConfig, ProcessAttributionConfig, TlsConfig,
96    UpstreamConfig,
97};
98pub use errors::{CaError, MitmError};
99pub use handler::InterceptHandler;
100pub use metrics::ProxyMetrics;
101pub use proxy::{MitmProxy, MitmProxyHandle};
102pub use types::{
103    ConnectionMeta, FlowId, FrameDirection, FrameKind, ProcessInfo, RawRequest, RawResponse,
104    SocketFamily, StreamChunk, TlsInfo, TlsVersion,
105};
106
107// Re-export key transitive types that appear in the public API surface.
108// Users should not need to add separate `bytes`, `http`, or `uuid` deps.
109pub use bytes::Bytes;
110pub use http::HeaderMap;
111pub use uuid::Uuid;
112
113/// Re-initializes the global DNS resolver with new nameserver configuration.
114///
115/// Safe to call at any time, including while the proxy is handling traffic.
116/// In-flight DNS queries on the previous resolver complete via Arc refcounting;
117/// new queries immediately use the replacement resolver.
118///
119/// Pass `None` to auto-detect system nameservers, or supply explicit entries
120/// such as `"8.8.8.8"`, `"1.1.1.1:53"`, or `"[2606:4700::1111]:53"`.
121pub fn reload_dns_resolver(nameservers: Option<&[String]>) {
122    server::dns_resolver::reinstall_dns_resolver(nameservers);
123}
124
125// --- Internal modules gated behind the `__internal` feature ---
126// These expose consolidated sub-crate internals for integration tests and
127// benchmarks. They are NOT part of the stable public API and may change
128// without notice between any versions.
129
130#[cfg(feature = "__internal")]
131#[doc(hidden)]
132pub mod bench_tls {
133    pub use crate::tls::{build_http1_client_config, build_http1_server_config_for_host};
134}
135
136#[cfg(feature = "__internal")]
137#[doc(hidden)]
138pub mod test_engine {
139    pub use crate::engine::{
140        parse_connect_request_head_with_mode, parse_connect_request_line_with_mode, server,
141        CompatibilityOverrideConfig, ConnectParseError, ConnectParseMode, DownstreamCertProfile,
142        InterceptMode, MitmConfig, MitmConfigError, MitmEngine, RouteEndpointConfig, RouteMode,
143        TlsFingerprintClass, TlsFingerprintMode, TlsProfile, UpstreamClientAuthMode,
144        UpstreamSniMode,
145    };
146}
147
148#[cfg(feature = "__internal")]
149#[doc(hidden)]
150pub mod test_policy {
151    pub use crate::policy::{DefaultPolicyEngine, FlowAction, PolicyEngine};
152}
153
154#[cfg(feature = "__internal")]
155#[doc(hidden)]
156pub mod test_protocol {
157    pub use crate::protocol::{
158        validate_stage_order,
159        // anti-hijack
160        AntiHijackSanitizationStage,
161        ApplicationProtocol,
162        DecoderFailureCode,
163        // decoder chain
164        DecoderFrame,
165        DecoderPipelineRegistry,
166        DecoderPipelineResult,
167        DecoderStage,
168        DecoderStageProcessor,
169        DecoderStageStatus,
170        // grpc envelope
171        GrpcEnvelopeMalformedCode,
172        GrpcEnvelopeParser,
173        GrpcEnvelopeParserLimits,
174        GrpcEnvelopeRecord,
175        LayeredDecoderPipeline,
176        SseParser,
177        StageProcessOutcome,
178        // websocket
179        WebSocketTurn,
180        WebSocketTurnAggregator,
181        WsDirection,
182        WsFrameKind,
183        SANITIZED_ATTRIBUTE,
184        SANITIZED_PREFIX_ATTRIBUTE,
185        SANITIZED_PROVENANCE_ATTRIBUTE,
186    };
187}
188
189#[cfg(feature = "__internal")]
190#[doc(hidden)]
191pub mod test_observe {
192    pub use crate::observe::event_log_v2::{
193        deterministic_event_record_v2, DeterministicEventRecordV2, EventLogV2Config,
194        EventLogV2Consumer,
195    };
196    pub use crate::observe::{
197        Event, EventConsumer, EventEnvelope, EventType, FlowContext, NoopEventConsumer,
198        VecEventConsumer, EVENT_SCHEMA_VERSION,
199    };
200}
201
202#[cfg(feature = "__internal")]
203#[doc(hidden)]
204pub mod test_server {
205    pub use crate::server::{
206        adapt_mitmproxy_tls_callback, parse_http1_request_head_bytes,
207        parse_http1_response_head_bytes, FlowHooks, FrameKind, H2ResponseOverflowMode,
208        MitmproxyTlsAdapterEvent, MitmproxyTlsCallback, MitmproxyTlsHook, NoopFlowHooks,
209        RawRequest, RawResponse, RuntimeGovernor, SidecarConfig, SidecarServer, StreamChunk,
210        TlsDiagnostics, TlsDiagnosticsSnapshot, TlsLearningDecision, TlsLearningGuardrails,
211        TlsLearningOutcome, TlsLearningSignal, TlsLearningSnapshot,
212    };
213}
214
215#[cfg(feature = "__internal")]
216#[doc(hidden)]
217pub mod test_tls {
218    pub use crate::tls::{
219        build_http1_client_config, build_http1_server_config_for_host, build_http_client_config,
220        build_http_server_config_for_host, classify_tls_error, CertificateAuthorityConfig,
221        MitmCertificateStore, TlsFailureReason,
222    };
223}