# How to Set Up an MITM Proxy with TPROXY for Decrypting CLI Traffic in OmniRoute

> Learn to set up an MITM proxy with TPROXY in OmniRoute. Transparently intercept and decrypt CLI traffic without system proxy changes. Explore the TproxyConfig interface and setup script.

- Repository: [Diego Rodrigues de Sa e Souza/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- Tags: how-to-guide
- Published: 2026-07-04

---

**OmniRoute uses a Linux TPROXY-based subsystem to transparently intercept outbound TCP connections from local CLI tools without modifying system-wide proxy settings, configured through the `TproxyConfig` interface and managed via [`src/mitm/tproxy/setup.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/mitm/tproxy/setup.ts).**

OmniRoute is an open-source traffic management tool that includes a sophisticated Man-in-the-Middle (MITM) subsystem for decrypting CLI traffic. By leveraging the Linux TPROXY mechanism, it can capture outbound TCP connections from processes running on the same host—something traditional NAT-based redirection cannot handle. This guide explains how to configure and deploy the TPROXY capture using OmniRoute's type-safe configuration model and transactional command execution.

## Understanding the TPROXY Architecture

The implementation resides in `src/mitm/tproxy/` and operates through three coordinated layers that ensure safe, reversible network modifications.

### The Configuration Model

At the core is the **`TproxyConfig`** interface defined in [`src/mitm/tproxy/commands.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/mitm/tproxy/commands.ts) (lines 35-46). This TypeScript interface describes the capture parameters: target port (`dport`), firewall mark (`mark`), listener port (`onPort`), routing table ID (`routeTable`), and optional bypass mark (`bypassMark`) to prevent interception loops.

### Command Generation

The **`buildTproxyApplyCommands`** and **`buildTproxyRevertCommands`** functions translate configurations into exact `iptables` and `ip` command arrays. According to the logic in [`commands.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/commands.ts) (lines 98-122), the revert list is constructed as the precise inverse of the apply list, ensuring that system crashes or failures never leave orphaned firewall rules.

### Transactional Execution

The **`applyTproxy`** and **`revertTproxy`** functions in [`src/mitm/tproxy/setup.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/mitm/tproxy/setup.ts) execute these commands using safe `execFile` calls without shell string interpolation. If errors occur during the apply phase (lines 40-52), the system triggers an automatic best-effort cleanup to maintain idempotency.

## Configuring the TPROXY Capture

To intercept HTTPS traffic from local CLI tools, create a `TproxyConfig` instance and invoke the apply function.

```typescript
import { applyTproxy, revertTproxy } from "./src/mitm/tproxy/setup";
import type { TproxyConfig } from "./src/mitm/tproxy/commands";

const cfg: TproxyConfig = {
  dport: 443,          // Target TLS connections
  mark: 0x2333,        // Firewall mark for OUTPUT rule
  onPort: 8443,       // OmniRoute listener receiving intercepted traffic
  routeTable: 233,     // Policy-routing table ID
  bypassMark: 0x9999,  // Prevents proxy loopbacks (optional)
};

// Apply TPROXY rules - modifies host iptables and routing tables
await applyTproxy(cfg);

```

The **`bypassMark`** field is critical—it marks the proxy's own upstream connections to avoid infinite interception loops.

## Enabling MITM via the HTTP API

OmniRoute exposes a REST endpoint at [`src/app/api/settings/mitm/route.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/app/api/settings/mitm/route.ts) for dashboard integration. You can programmatically enable MITM using a standard HTTP POST:

```bash
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
  }'

```

The endpoint validates the payload using `validateTproxyConfig` (found in [`commands.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/commands.ts) lines 62-75) before invoking `applyTproxy`. Send a DELETE request to the same endpoint to trigger `revertTproxy` and disable interception.

## Monitoring and Reverting the Capture

To check the current MITM state or disable capture programmatically:

```typescript
import { listActiveTproxy } from "./src/mitm/manager.runtime";

// Returns persisted config or null if MITM is disabled
const active = await listActiveTproxy();
console.log(active);

// Later, to remove rules:
await revertTproxy(cfg);

```

The [`src/mitm/manager.runtime.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/mitm/manager.runtime.ts) module persists configurations and coordinates between the UI/API layer and the underlying TPROXY implementation.

## Why TPROXY Matters for Local Traffic

Standard NAT-based redirection fails for locally generated traffic because packets from CLI tools never traverse the `PREROUTING` chain. As documented in [`commands.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/commands.ts) (lines 8-15), OmniRoute's TPROXY implementation marks new local outbound connections in the `mangle OUTPUT` chain, routes them back to the loopback device via an `ip rule`, and captures them in `mangle PREROUTING` using the `TPROXY` target. This hands packets to OmniRoute's IP-TRANSPARENT listener while the `bypassMark` prevents the proxy from intercepting its own connections.

## Summary

- OmniRoute's MITM subsystem uses Linux TPROXY to intercept local CLI traffic that bypasses traditional NAT redirection
- Configuration is type-safe through the `TproxyConfig` interface in [`src/mitm/tproxy/commands.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/mitm/tproxy/commands.ts)
- Command generation produces reversible `iptables`/`ip` sequences via `buildTproxyApplyCommands` and `buildTproxyRevertCommands`
- Transactional execution in [`src/mitm/tproxy/setup.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/mitm/tproxy/setup.ts) ensures automatic rollback on failure
- The HTTP API at [`src/app/api/settings/mitm/route.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/app/api/settings/mitm/route.ts) enables dashboard-driven configuration

## Frequently Asked Questions

### What makes TPROXY different from standard NAT redirection for MITM?

TPROXY operates on the `mangle` table and can intercept traffic originating from the local host, whereas NAT redirection only catches forwarded traffic traversing `PREROUTING`. This allows OmniRoute to decrypt connections from CLI tools running on the same machine without requiring global proxy environment variables.

### How does OmniRoute prevent infinite interception loops?

The `bypassMark` field in `TproxyConfig` assigns a specific firewall mark to the proxy's own upstream connections. The iptables rules skip processing for packets bearing this mark, ensuring that OmniRoute's traffic exits normally while other local processes remain intercepted.

### What happens if the `applyTproxy` command fails mid-execution?

The transactional runner in [`src/mitm/tproxy/setup.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/mitm/tproxy/setup.ts) (lines 40-52) implements automatic rollback. If any command in the apply sequence fails, the system executes the corresponding revert commands to restore the original firewall and routing state, preventing partial configuration that could break connectivity.

### Can I intercept multiple ports simultaneously?

Yes. Create multiple `TproxyConfig` instances with different `dport` values (e.g., 80 for HTTP and 443 for HTTPS) and unique `mark`/`routeTable` combinations. Invoke `applyTproxy` for each configuration, or make separate API calls to `/api/settings/mitm` for each target port.