How to Configure the MITM TPROXY Proxy to Capture Traffic from CLI Tools that Ignore Proxy Environment Variables in OmniRoute
Use OmniRoute's kernel-level TPROXY capture mode to intercept outbound TCP traffic via iptables rules, bypassing the need for proxy environment variables entirely.
OmniRoute's MITM subsystem provides a TPROXY capture mode that operates at the kernel level to intercept traffic from command-line tools that hard-code direct connections or ignore standard http_proxy and https_proxy settings. Unlike traditional proxy configurations that rely on environment variables, this transparent proxy implementation uses Linux netfilter rules to redirect packets before they leave the system, making it effective for capturing traffic from curl, git, and proprietary CLIs.
How TPROXY Interception Works in OmniRoute
The TPROXY implementation in diegosouzapw/OmniRoute bypasses the application layer entirely by intercepting packets at the kernel level. When you configure the MITM proxy TPROXY mode, OmniRoute applies iptables rules to the PREROUTING mangle chain, redirecting outbound TCP connections to a local transparent listener without modifying the destination IP headers.
Key components handle the lifecycle:
src/mitm/tproxy/setup.tscontains the transactional builderapplyTproxy()andrevertTproxy()that manage iptables rule insertion and rollbacksrc/mitm/tproxy/captureMode.tsimplements the transparent listener that reads the original destination viasocket.localAddresssrc/mitm/tproxy/caTrust.tshandles dynamic per-SNI CA generation and OS trust-store installation
Configuring TPROXY Capture Step-by-Step
Starting the TPROXY Capture Session
Initiate capture by sending a POST request to the local-only API endpoint POST /api/tools/agent-bridge/tproxy. This endpoint, defined in src/app/api/tools/agent-bridge/tproxy/route.ts, orchestrates the startup sequence:
- Transactionally applies iptables TPROXY rules (
applyTproxyinsrc/mitm/tproxy/setup.ts) - Opens a transparent listener on the specified port
- Installs a per-SNI dynamic CA into the OS trust store
// Client-side helper to start capture
import { startCapture } from '@/lib/inspector/tproxyCaptureApi';
await startCapture({
onPort: 8443, // listener port
mark: 9011, // iptables MARK value
sudoPassword: '••••', // required on non-root desktop builds
});
Preventing Capture Loops with Socket Marking
To avoid OmniRoute intercepting its own outbound connections, the system uses the setSocketMark primitive from the native addon. In src/mitm/tproxy/transparentSocket.ts, this function tags egress sockets with a specific mark value that the iptables OUTPUT chain excludes.
import { setSocketMark } from '@/mitm/tproxy/transparentSocket';
import net from 'net';
const socket = net.createConnection({ host, port });
await setSocketMark(socket); // ensures OUTPUT rule skips this socket
The iptables configuration applies separate rules: TPROXY redirection for general traffic and an exclusion for packets bearing the process-specific mark.
Configuring Capture Parameters
The request body schema, defined in src/lib/inspector/tproxyCaptureApi.ts, accepts:
onPort: The local port where the transparent listener binds (default: 8443)mark: The iptables MARK value used for loop prevention (default: 9011)sudoPassword: Authentication for iptables manipulation on desktop builds
Stopping the Session
Terminate capture by sending a DELETE request to the same endpoint. This triggers stopTproxy() in src/mitm/tproxy/captureManager.ts, which calls revertTproxy() to safely rollback iptables rules, close the listener, and remove the CA from the trust store.
// Server-side entry point for stop operations
import { stopTproxy } from '@/mitm/tproxy/captureManager';
export async function DELETE(req: Request) {
await stopTproxy(); // exact inverse of start, safe-idempotent rollback
return Response.json({ success: true });
}
Implementation Examples
Transactional iptables Rule Application
The src/mitm/tproxy/setup.ts module provides atomic rule management:
import { applyTproxy, revertTproxy } from '@/mitm/tproxy/setup';
export async function startTproxy(cfg: TproxyConfig) {
await applyTproxy(cfg); // runs PREROUTING mangle TPROXY + OUTPUT mark commands
}
export async function stopTproxy(cfg: TproxyConfig) {
await revertTproxy(cfg); // exact inverse, safe-idempotent rollback
}
Server-Side API Route Handler
The complete request handler in src/app/api/tools/agent-bridge/tproxy/route.ts:
import { startTproxy, stopTproxy } from '@/mitm/tproxy/captureManager';
export async function POST(req: Request) {
const cfg = await req.json(); // validates via StartTproxyBodySchema
await startTproxy(cfg); // applies rules, opens listener, installs CA
return Response.json({ success: true });
}
Summary
- Configure the MITM proxy TPROXY in OmniRoute by posting to
/api/tools/agent-bridge/tproxy, which triggers kernel-level packet interception via iptables rules insrc/mitm/tproxy/setup.ts - The transparent listener in
src/mitm/tproxy/captureMode.tsreceives original destination information throughsocket.localAddress, eliminating the need for proxy environment variables - Use
setSocketMarkfromsrc/mitm/tproxy/transparentSocket.tsto mark OmniRoute's own sockets and prevent capture loops via iptables mark exclusions - Dynamic CA installation via
src/mitm/tproxy/caTrust.tsenables TLS decryption without requiring application-level proxy configuration - The entire flow is reversible through the
DELETEendpoint, which safely rolls back all system modifications
Frequently Asked Questions
What is TPROXY and why does it capture traffic that ignores proxy settings?
TPROXY is a Linux netfilter target that intercepts TCP packets at the kernel level before they reach the network interface. Because it operates below the application layer, it does not rely on applications checking http_proxy environment variables. According to the OmniRoute source code in src/mitm/tproxy/captureMode.ts, the transparent listener receives the original destination IP through socket options, allowing interception of hard-coded connections from CLIs like curl or git that bypass standard proxy configurations.
How does OmniRoute prevent infinite loops when capturing its own traffic?
The implementation uses socket marking via the native addon exposed in src/mitm/tproxy/transparentSocket.ts. The setSocketMark function tags egress sockets with a specific mark value (default: 9011). The iptables OUTPUT chain includes a rule that excludes packets bearing this mark from TPROXY redirection, ensuring that OmniRoute's own outbound connections—such as API calls or CA updates—do not get recursively intercepted.
Is root access required to configure TPROXY in OmniRoute?
Yes, manipulating iptables rules and binding transparent sockets requires elevated privileges. The startCapture helper in src/lib/inspector/tproxyCaptureApi.ts accepts an optional sudoPassword parameter for non-root desktop builds. On production deployments, OmniRoute should run with appropriate capabilities or as root to execute the applyTproxy commands in src/mitm/tproxy/setup.ts.
Can TPROXY capture mode decrypt HTTPS traffic from CLI tools?
Yes, because TPROXY intercepts the TCP connection before TLS handshakes occur, OmniRoute can perform TLS termination. The src/mitm/tproxy/caTrust.ts module dynamically generates a per-SNI CA certificate and installs it into the system trust store. This allows the transparent proxy in src/mitm/tproxy/captureMode.ts to present valid certificates to the client while establishing a separate TLS connection to the target server, enabling full traffic inspection in the Traffic Inspector UI.
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 →