# How to Set Up OmniRoute's MITM Proxy with TPROXY for Traffic Inspection

> Learn to set up OmniRoute's MITM proxy with TPROXY for transparent traffic inspection. Intercept and analyze local TCP traffic effectively using netfilter and custom routing.

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

---

**OmniRoute's built-in MITM proxy uses Linux TPROXY transparent capture mode to intercept local TCP traffic by marking outbound connections in the netfilter mangle table, routing marked packets through a custom routing table to the loopback interface, and redirecting them to a local listener socket that terminates and re-issues TLS sessions.**

OmniRoute is an open-source routing platform that ships with a built-in **MITM (Man-in-the-Middle) proxy** capable of capturing and inspecting TCP traffic from local applications without altering system-wide proxy settings. This guide explains how to configure the **TPROXY** interception mechanism using the actual source implementation from the `diegosouzapw/OmniRoute` repository. By following the exact code paths in `src/mitm/tproxy/`, you can deploy a transparent proxy that inspects HTTPS traffic for debugging, security auditing, or LLM request routing.

## How TPROXY Interception Works in OmniRoute

The transparent interception relies on four sequential packet-flow stages implemented in the Linux networking stack. According to the source code in [`src/mitm/tproxy/commands.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/mitm/tproxy/commands.ts), the system manipulates the **mangle** table and custom routing tables to redirect traffic without modifying application configurations.

1. **Mark outbound connections** using an `iptables` rule in the `OUTPUT` chain that applies a firewall mark (fwmark) to packets destined for the target port.

2. **Add an IP rule** that routes packets bearing this fwmark to a custom routing table ID.

3. **Create a local-only route** (`0.0.0.0/0 → lo`) within that custom table, forcing marked packets to re-enter the host's local stack.

4. **Redirect in PREROUTING** using a `TPROXY` rule that sends the marked packets to the listener socket running on a specified local port, preserving the original destination address.

The listener socket, implemented in [`src/mitm/tproxy/transparentSocket.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/mitm/tproxy/transparentSocket.ts), binds with the `IP_TRANSPARENT` flag enabled, allowing it to receive packets addressed to foreign IP addresses. The [`src/mitm/tproxy/tlsCapture.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/mitm/tproxy/tlsCapture.ts) module then handles TLS termination using a dynamically generated CA, enabling plaintext inspection of HTTPS sessions.

## Prerequisites

Before configuring the MITM proxy, ensure your environment meets the following requirements defined in the OmniRoute source:

- **Linux kernel** ≥ 6.8 with TPROXY support enabled.
- **iptables** and **ip** (iproute2) utilities installed and available in `$PATH`.
- **Root privileges** or `CAP_NET_ADMIN` capability for modifying netfilter rules and routing tables.
- **Node.js** version ≥ 22 && < 23 or ≥ 24 && < 27 (as specified in the repository's [`package.json`](https://github.com/diegosouzapw/OmniRoute/blob/main/package.json)).

## Step-by-Step Setup Guide

### Install OmniRoute

Clone the repository and install dependencies at the specific release version containing the TPROXY implementation:

```bash
git clone https://github.com/diegosouzapw/OmniRoute.git
cd OmniRoute
git checkout release/v3.8.49
npm ci

```

### Generate the Self-Signed CA

The MITM proxy requires a certificate authority to re-sign intercepted TLS traffic. Generate the CA using the built-in test script:

```bash
node --import tsx/esm --test src/mitm/cert/generate.ts

```

This places the generated certificate files under `src/mitm/cert/`, which the MITM server automatically loads during startup.

### Configure TproxyConfig

Create a configuration object matching the `TproxyConfig` interface defined in [`src/mitm/tproxy/commands.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/mitm/tproxy/commands.ts). This example targets HTTPS traffic (port 443):

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

const cfg: TproxyConfig = {
  dport: 443,          // Destination port to intercept
  mark: 0x2333,        // Arbitrary fwmark (must be positive)
  onPort: 8443,        // Local port where the MITM listener binds
  routeTable: 233,     // Routing table ID for the local route
  bypassMark: 0x9999,  // Optional: SO_MARK for the proxy's own outbound traffic
};

```

### Apply the TPROXY Rules

The `applyTproxy` function in [`src/mitm/tproxy/setup.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/mitm/tproxy/setup.ts) executes the iptables and ip commands generated by `buildTproxyApplyCommands`. It uses a **no-shell** `execFile` implementation and provides crash-safe cleanup:

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

// Install firewall and routing rules
await applyTproxy(cfg);

```

If any command fails during application, `applyTproxy` automatically invokes `revertTproxy` to clean up partial state, maintaining the crash-safe invariant documented in the source.

### Start the MITM Service

Launch the runtime manager to begin interception. The entry point at [`src/mitm/manager.runtime.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/mitm/manager.runtime.ts) dynamically imports the native implementation to avoid build-time module errors:

```bash
node --import tsx/esm src/mitm/manager.runtime.ts start

```

The manager performs the following sequence:

- Loads the generated CA from `src/mitm/cert/`.
- Initializes the transparent socket with `IP_TRANSPARENT` enabled.
- Calls `applyTproxy` to install interception rules.
- Begins handling connections through OmniRoute's internal request pipeline.

Alternatively, use the high-level `MitmManager` API:

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

const manager = new MitmManager({
  dport: 443,
  mark: 0x2333,
  onPort: 8443,
  routeTable: 233,
  bypassMark: 0x9999,
});

await manager.start();  // Applies TPROXY rules and starts listener

```

### Verify the Setup

Confirm that the TPROXY rules are active:

```bash

# Check OUTPUT chain marking rule

sudo iptables -t mangle -L OUTPUT -v -n | grep MARK

# Check PREROUTING TPROXY redirection

sudo iptables -t mangle -L PREROUTING -v -n | grep TPROXY

# Verify fwmark routing rule and local route table

sudo ip rule list | grep 0x2333
sudo ip route show table 233

```

Test interception by making an HTTPS request from the host. The connection should appear in OmniRoute's logs while the `iptables` counters increment.

### Tear Down

Remove the TPROXY rules using the idempotent revert function:

```typescript
await revertTproxy(cfg);

```

The `MitmManager` also calls `revertTproxy` automatically during `manager.stop()` or process shutdown. Because the function is idempotent, missing rules (from previous crashes) are ignored safely.

## Complete Implementation Example

The following TypeScript program demonstrates a minimal setup that starts the MITM proxy for HTTPS inspection:

```typescript
// file: start-mitm.ts
import { applyTproxy, revertTproxy } from "./src/mitm/tproxy/setup";
import type { TproxyConfig } from "./src/mitm/tproxy/commands";
import { spawn } from "node:child_process";

async function main() {
  const cfg: TproxyConfig = {
    dport: 443,
    mark: 0x2333,
    onPort: 8443,
    routeTable: 233,
    bypassMark: 0x9999,
  };

  await applyTproxy(cfg);

  const child = spawn("node", [
    "--import", "tsx/esm",
    "src/mitm/manager.runtime.ts",
    "start"
  ], { stdio: "inherit" });

  const shutdown = async () => {
    child.kill();
    await revertTproxy(cfg);
    process.exit(0);
  };
  
  process.on("SIGINT", shutdown);
  process.on("SIGTERM", shutdown);
}

main().catch((e) => {
  console.error("Failed to start MITM:", e);
  process.exit(1);
});

```

## Core Source Files

Understanding these key files in `diegosouzapw/OmniRoute` helps with advanced customization:

- **[`src/mitm/tproxy/commands.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/mitm/tproxy/commands.ts)** – Builds typed `iptables` and `ip` commands for applying and reverting TPROXY rules based on `TproxyConfig`.

- **[`src/mitm/tproxy/setup.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/mitm/tproxy/setup.ts)** – Executes command lists safely using `execFile`, guaranteeing crash-safe cleanup via automatic revert on failure.

- **[`src/mitm/manager.runtime.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/mitm/manager.runtime.ts)** – Runtime entry point that imports the native manager implementation while avoiding Turbopack alias issues.

- **[`src/mitm/tproxy/transparentSocket.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/mitm/tproxy/transparentSocket.ts)** – Low-level socket implementation binding with `IP_TRANSPARENT` to receive redirected packets.

- **[`src/mitm/tproxy/tlsCapture.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/mitm/tproxy/tlsCapture.ts)** – Handles TLS termination and re-encryption using the generated self-signed CA.

- **[`src/mitm/cert/generate.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/mitm/cert/generate.ts)** – Generates the self-signed CA and host certificates required for HTTPS inspection.

- **[`src/mitm/manager.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/mitm/manager.ts)** – High-level controller orchestrating certificate generation, socket startup, and TPROXY lifecycle management.

## Summary

- OmniRoute uses **TPROXY** transparent proxy mode to intercept local TCP traffic without modifying application proxy settings.
- The interception flow requires **four netfilter components**: OUTPUT chain marking, ip rule for fwmark, local route table, and PREROUTING TPROXY redirection.
- Configuration uses the **`TproxyConfig`** interface in [`src/mitm/tproxy/commands.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/mitm/tproxy/commands.ts) to define target ports, marks, and routing tables.
- **`applyTproxy`** and **`revertTproxy`** in [`src/mitm/tproxy/setup.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/mitm/tproxy/setup.ts) provide crash-safe rule management with automatic cleanup on failure.
- The **`MitmManager`** class offers a high-level API that handles certificate generation, socket initialization, and graceful shutdown.
- Node.js versions **≥22 && <23** or **≥24 && <27** and Linux kernel **≥6.8** are required for full functionality.

## Frequently Asked Questions

### What is the purpose of the bypassMark parameter in TproxyConfig?

The **`bypassMark`** parameter assigns a specific SO_MARK value to outbound connections initiated by the MITM proxy itself. This mark prevents the proxy's own traffic from being re-intercepted by the TPROXY rules, avoiding infinite loops where the proxy would try to proxy its own connections. Set this to any value distinct from the main interception `mark`.

### Why does OmniRoute require IP_TRANSPARENT socket capability?

The **`IP_TRANSPARENT` socket option**, enabled in [`src/mitm/tproxy/transparentSocket.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/mitm/tproxy/transparentSocket.ts), allows the MITM listener to bind to and receive packets addressed to foreign IP addresses (the original destinations). Without this capability, the TPROXY redirection would fail because the local socket could not accept packets originally destined for remote HTTPS servers on port 443.

### How does OmniRoute handle TLS encryption for intercepted HTTPS traffic?

OmniRoute generates a self-signed Certificate Authority using [`src/mitm/cert/generate.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/mitm/cert/generate.ts). When the transparent socket captures a connection, **[`src/mitm/tproxy/tlsCapture.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/mitm/tproxy/tlsCapture.ts)** terminates the TLS session using a certificate signed by this CA, decrypts the traffic for inspection, then establishes a new TLS connection to the original upstream destination. The client must trust the generated CA certificate to avoid security warnings.

### What happens if the MITM process crashes while TPROXY rules are active?

The **`applyTproxy`** function in [`src/mitm/tproxy/setup.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/mitm/tproxy/setup.ts) implements a crash-safe invariant: if any iptables or ip command fails during setup, it immediately calls **`revertTproxy`** to remove partially applied rules. However, if the process crashes after successful setup, rules may persist. In this case, running `revertTproxy` manually (or restarting the host) cleans up the residual state, as the revert function is idempotent and ignores missing rules.