How to Set Up the MITM Proxy with TPROXY in OmniRoute to Decrypt CLI Traffic
OmniRoute implements a Linux TPROXY subsystem under src/mitm/tproxy/ that transparently captures local outbound TCP connections by marking packets in the mangle OUTPUT chain and diverting them to an IP-TRANSPARENT listener, enabling decryption of HTTPS traffic from CLI tools without modifying system proxy settings.
OmniRoute provides a sophisticated man-in-the-middle (MITM) subsystem designed to intercept and decrypt traffic from command-line tools that ignore traditional HTTP proxy variables. When you set up the MITM proxy with TPROXY in OmniRoute, the system utilizes the Linux TPROXY mechanism to capture outbound connections from local processes, routing them through an internal transparent listener that terminates TLS. The implementation spans configuration management in src/mitm/tproxy/commands.ts, transactional execution in src/mitm/tproxy/setup.ts, and runtime coordination via src/mitm/manager.runtime.ts.
Why TPROXY for Local Outbound Interception?
Standard NAT-based redirection fails for traffic originating from the same host because local packets never traverse the PREROUTING chain. As implemented in src/mitm/tproxy/commands.ts (lines 8-15), the TPROXY recipe marks new local outbound connections in the mangle OUTPUT chain using the configured mark value, routes them back to the local loopback device via a custom ip rule and routeTable, and finally captures them in mangle PREROUTING with a TPROXY target. This hands the packets to OmniRoute’s IP-TRANSPARENT listener, which handles the TLS decryption. The bypassMark field prevents the proxy's own upstream connections from being re-intercepted, avoiding infinite loops.
Configuration Structure and Validation
The MITM configuration centers on the TproxyConfig interface defined in src/mitm/tproxy/commands.ts (lines 35-46).
The TproxyConfig Interface
A valid configuration requires five key fields:
dport: The target port to intercept (e.g., 443 for HTTPS traffic)mark: The firewall mark used in theOUTPUTchain rule (e.g., 0x2333)onPort: The local port where OmniRoute listens for intercepted trafficrouteTable: The policy routing table ID used for the diversion routebypassMark: An optional mark applied to the proxy's own connections to prevent interception loops
Generating iptables Commands
The buildTproxyApplyCommands and buildTproxyRevertCommands functions in src/mitm/tproxy/commands.ts (lines 98-122) translate a TproxyConfig into exact iptables and ip command arrays. The builder guarantees that the revert list is the precise inverse of the apply list, ensuring that system crashes never leave stray firewall rules or routing entries.
Applying and Reverting TPROXY Rules
The applyTproxy and revertTproxy functions in src/mitm/tproxy/setup.ts execute command arrays via execFile without shell string interpolation, preventing injection vulnerabilities. If errors occur during the apply phase (lines 40-52), the system triggers an automatic best-effort cleanup to maintain host idempotency.
To enable interception for HTTPS traffic:
import { applyTproxy, revertTproxy } from "./src/mitm/tproxy/setup";
import type { TproxyConfig } from "./src/mitm/tproxy/commands";
const cfg: TproxyConfig = {
dport: 443,
mark: 0x2333,
onPort: 8443,
routeTable: 233,
bypassMark: 0x9999,
};
// Apply rules to iptables and routing tables
await applyTproxy(cfg);
// Later, revert to normal routing
await revertTproxy(cfg);
Native Helper Compilation
For the TPROXY listener to function, OmniRoute requires a native transparent-socket helper. Compilation instructions are available in src/mitm/tproxy/native/README.md, which provides the build steps for the component that handles the IP-TRANSPARENT socket options required for packet interception.
Enabling MITM via the HTTP API
OmniRoute exposes TPROXY configuration through the HTTP endpoint at src/app/api/settings/mitm/route.ts, allowing dashboard integration and remote management. The endpoint validates configurations using validateTproxyConfig (lines 62-75) before applying changes.
Enable interception via curl:
curl -X POST https://<omniroute-host>/api/settings/mitm \
-H "Content-Type: application/json" \
-d '{
"dport": 443,
"mark": 9001,
"onPort": 8443,
"routeTable": 9001,
"bypassMark": 1234
}'
Send a DELETE request to the same endpoint to clear the configuration and invoke revertTproxy.
Monitoring Active Captures
Inspect the current MITM state using listActiveTproxy from src/mitm/manager.runtime.ts, which returns the persisted configuration or null if MITM is disabled.
import { listActiveTproxy } from "./src/mitm/manager.runtime";
const active = await listActiveTproxy();
console.log(active); // Returns TproxyConfig or null
Summary
- OmniRoute uses a three-layer TPROXY architecture: configuration modeling in
commands.ts, safe execution insetup.ts, and runtime management inmanager.runtime.ts. - The TPROXY mechanism intercepts local outbound traffic by marking packets in the
mangle OUTPUTchain and routing them through a custom policy table to theTPROXYtarget. - Safety guarantees include inverse command generation for clean reverts and automatic rollback on apply failures.
- Configuration can be applied programmatically via
applyTproxy(), through the HTTP API at/api/settings/mitm, or monitored vialistActiveTproxy(). - The native transparent-socket helper must be compiled according to
src/mitm/tproxy/native/README.mdfor the listener to function.
Frequently Asked Questions
What is the purpose of the bypassMark parameter?
The bypassMark parameter assigns a firewall mark to OmniRoute's own upstream connections, preventing the proxy from intercepting its own traffic and creating an infinite loop. This mark is applied to outbound connections made by the transparent listener, ensuring they bypass the mangle OUTPUT rule that would otherwise redirect them back to the proxy.
How does OmniRoute ensure firewall rules are cleaned up after a failure?
The buildTproxyRevertCommands function generates commands that are the exact inverse of the apply sequence, stored alongside the active configuration. If applyTproxy encounters an error during execution (lines 40-52 in setup.ts), it triggers an automatic best-effort cleanup routine that executes the revert commands to restore the system to its previous state.
Can I intercept traffic from specific CLI tools only?
While the current implementation intercepts all outbound traffic to the specified dport from the local host, you can extend the iptables commands generated in src/mitm/tproxy/commands.ts to include owner matching (--uid-owner) or cgroup filtering. This would require modifying the buildTproxyApplyCommands function to append additional criteria before the MARK target.
Where does OmniRoute persist the TPROXY configuration?
The MITM manager in src/mitm/manager.runtime.ts persists the TproxyConfig object to the application's internal settings store, which survives process restarts. When OmniRoute starts, it retrieves this configuration via listActiveTproxy() and can optionally reapply the interception rules, maintaining continuity across deployments.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →