# How to Set Up the MITM Proxy with TPROXY in OmniRoute to Decrypt CLI Traffic

> Learn to set up the MITM proxy with TPROXY in OmniRoute to transparently decrypt CLI traffic. Capture outbound TCP connections and decrypt HTTPS without changing proxy settings.

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

---

**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`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/mitm/tproxy/commands.ts), transactional execution in [`src/mitm/tproxy/setup.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/mitm/tproxy/setup.ts), and runtime coordination via [`src/mitm/manager.runtime.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/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`](https://github.com/diegosouzapw/OmniRoute/blob/main/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`](https://github.com/diegosouzapw/OmniRoute/blob/main/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 the `OUTPUT` chain rule (e.g., 0x2333)
- `onPort`: The local port where OmniRoute listens for intercepted traffic
- `routeTable`: The policy routing table ID used for the diversion route
- `bypassMark`: 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`](https://github.com/diegosouzapw/OmniRoute/blob/main/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`](https://github.com/diegosouzapw/OmniRoute/blob/main/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:

```typescript
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`](https://github.com/diegosouzapw/OmniRoute/blob/main/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`](https://github.com/diegosouzapw/OmniRoute/blob/main/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:

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

```

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`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/mitm/manager.runtime.ts), which returns the persisted configuration or null if MITM is disabled.

```typescript
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`](https://github.com/diegosouzapw/OmniRoute/blob/main/commands.ts), safe execution in [`setup.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/setup.ts), and runtime management in [`manager.runtime.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/manager.runtime.ts).
- The **TPROXY mechanism** intercepts local outbound traffic by marking packets in the `mangle OUTPUT` chain and routing them through a custom policy table to the `TPROXY` target.
- **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 via `listActiveTproxy()`.
- The **native transparent-socket helper** must be compiled according to [`src/mitm/tproxy/native/README.md`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/mitm/tproxy/native/README.md) for 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`](https://github.com/diegosouzapw/OmniRoute/blob/main/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`](https://github.com/diegosouzapw/OmniRoute/blob/main/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`](https://github.com/diegosouzapw/OmniRoute/blob/main/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.