Contents

VIEW SOURCE
CLI TOOL MIT LICENSE PYTHON 3.10+ KILL-SWITCH

Transparent Tor Proxy

TTP is a Linux CLI tool that intercepts all outgoing network traffic and forces it through the Tor network using nftables, without requiring per-application configuration. It uses modern Linux primitives, loads firewall rules atomically, and is designed to always restore your network, even after a crash or power outage.

bash
$ git clone https://github.com/onyks-os/TransparentTorProxy.git
$ cd TransparentTorProxy && pip install .
$ sudo ttp start
[TTP] Detecting Tor... found (v0.4.9.6), service active (user: debian-tor).
[TTP] Stateless nftables rules applied (Table: inet ttp).
[TTP] DNS set via resolvectl on interface ens3.
[TTP] Waiting for Tor to bootstrap... 100%
[TTP] ✅ Session active. Exit IP: 109.70.100.11
⚠ SECURITY NOTICE
TTP routes traffic through Tor but does not guarantee anonymity. Your safety also depends on your behavior (signing into accounts, browser fingerprinting, etc.). For high-risk activities use Tails or Tor Browser directly.
0x02

Installation

Requirements

Requirement Notes
Linux with systemd Tested on Debian 13 Trixie and Fedora 41+
Python 3.10+ Required for union type hints and modern stdlib features
nftables Pre-installed on Debian 12+, Fedora 33+, Arch. Replaces iptables as firewall backend.
Root privileges Required for firewall and DNS modifications, and all commands must be run with sudo

System-wide deployment (Recommended)

For most users, we recommend using the system-wide installer. This places TTP in /opt/ttp, creates a symbolic link in /usr/local/bin, and sets up all necessary permissions.

bash
$ git clone https://github.com/onyks-os/TransparentTorProxy.git
$ cd TransparentTorProxy
$ sudo ./install.sh

Alternative: Local pip installation

bash
$ pip install .
ℹ NOTE
After installation, the ttp command is registered system-wide via the pyproject.toml entry point ttp = "ttp.cli:app". Tor itself does not need to be pre-installed, as TTP detects its absence and installs it automatically using the system's package manager.

Python dependencies

Package Source Purpose
stem PyPI Official Python library from the Tor Project. Used to connect to Tor's Control Port/Socket, monitor bootstrap progress, and send NEWNYM signals.
typer PyPI Modern CLI framework. Provides argument parsing, --help generation, and clean command routing.
rich PyPI Terminal output formatting: panels, progress bars, colored text.
0x03

Architecture

TTP is structured as a set of independent Python modules, each with a single responsibility. No module imports from cli.py. UI logic (rich, typer) is confined exclusively to cli.py while all other modules return plain data.

tor_detect.py

Read-only module. Checks if Tor is installed (shutil.which), running (systemctl is-active + pgrep), and correctly configured (TransPort 9040, DNSPort 9053, ControlPort 9051 in torrc). Dynamically detects the Tor system user and SELinux enforcement state. Returns a structured dictionary, but never modifies anything.

tor_install.py

Invoked only when tor_detect reports Tor is missing or misconfigured. Detects the system package manager (apt-get, pacman, dnf, zypper) and installs Tor. Performs SELinux optimization on Fedora/RHEL, sanitizes /etc/tor/torrc, validates with tor --verify-config, then restarts the correct systemd unit.

firewall.py

Implements a multi-chain, "Safe-Release" architecture. Generates a stateless ruleset with three chains: prerouting, output (NAT), and filter_out (Filter). The latter acts as a dedicated Kill-Switch. Applied atomically via nft -f.

dns.py

Manages DNS redirection to 127.0.0.1. Mode 1 uses resolvectl to set DNS and the global routing domain (~.) when active. Mode 2 overwrites /etc/resolv.conf. Uses a Hard-Reset strategy (revert → restart → flush caches) for robust restoration.

state.py

Writes and reads a JSON lock file at /var/lib/ttp/ttp.lock containing: pid, timestamp, dns_backup, and dns_mode. On startup, checks if the lock's PID is still alive. A dead PID means an orphaned session, exposing attempt_recovery() to auto-restore.

tor_control.py

Encapsulates all Stem library usage. Connects to Tor's control interface, monitors bootstrap progress via status/bootstrap-phase, sends NEWNYM to rotate circuits, and verifies actual Tor routing via check.torproject.org/api/ip.

system_info.py

Pure data-gathering module used by ttp diagnose. Collects OS info, Tor service status, active torrc settings, nftables ruleset, DNS state, and Tor control interface status. Returns a flat dict[str, str]. Every subprocess call is wrapped in a try/except so a single failure never aborts the full diagnostic.

exceptions.py

Defines a custom exception hierarchy for the project. Includes TTPError (base) and specialized classes: FirewallError, DNSError, StateError, and TorError. Used to distinguish between fatal issues and recoverable states.

0x04

Execution Flow

ttp start

1. Root check, Signal registration & SELinux

Verifies os.geteuid() == 0. Registers SIGINT and SIGTERM handlers. On Fedora/RHEL, ensures the TTP SELinux policy module is installed to allow Tor port binding.

2. Orphan detection

Reads /var/lib/ttp/ttp.lock. If the lock exists and its PID is dead, the session is orphaned. state.attempt_recovery() is called automatically to restore firewall and DNS.

3. Tor detection & auto-install

tor_install.ensure_tor_ready() orchestrates detection → install → torrc configuration → service restart. The torrc is always validated before restarting.

4. Stateless multi-chain firewall application

A stateless ruleset is written to /var/lib/ttp/ttp.rules and loaded atomically via nft -f. This includes NAT redirection and a filter-based Kill-Switch to prevent leaks during bootstrap or unexpected process failure.

5. DNS redirection

The active network interface is auto-detected. DNS is redirected to 127.0.0.1 using resolvectl or by overwriting /etc/resolv.conf.

6. Lock file write

A JSON lock file is written to /var/lib/ttp/ttp.lock containing DNS backup info and PID. This is the only persistent record of the active session.

7. Bootstrap wait & verification

Connects to Tor's control interface and polls status/bootstrap-phase. Once at 100%, waits 2 seconds for circuits to settle, then verifies routing against multiple endpoints (e.g., check.torproject.org).

ttp stop

Restore firewall

Removes the TTP rules by destroying the table: nft destroy table inet ttp.

Restore DNS

Reads DNS mode and backup from lock. Performs a Hard-Reset (resolvectl revert, restart service, flush caches) or rewrites /etc/resolv.conf.

Delete lock

Removes /var/lib/ttp/ttp.lock. Session is terminated.

0x05

Firewall Rules

TTP generates a single nftables table. The ruleset is written to a temporary file and loaded with a single nft -f call, meaning all rules apply atomically, or none do.

nftables
# TTP - Transparent Tor Proxy rules
# Applied atomically via nft -f
table inet ttp {
chain prerouting {
type nat hook prerouting priority dstnat; policy accept;
udp dport 53 dnat ip to 127.0.0.1:9053
tcp dport 53 dnat ip to 127.0.0.1:9053
ip protocol tcp dnat ip to 127.0.0.1:9040
}
chain output {
type nat hook output priority -150; policy accept;
# 1. Tor user EXEMPTION (Allow daemon to reach net)
meta skuid 114 accept
# 2. DNS Redirection: Force queries to Tor's DNSPort
udp dport 53 dnat ip to 127.0.0.1:9053
tcp dport 53 dnat ip to 127.0.0.1:9053
# 3. Exempt local traffic (Required for NATed packets)
ip daddr 127.0.0.0/8 accept
# 4. Redirect all other TCP traffic to Tor's TransPort
ip protocol tcp dnat ip to 127.0.0.1:9040
}
chain filter_out {
type filter hook output priority filter; policy accept;
# Kill-switch: Ensure only Tor and Local traffic leaves
meta skuid 114 accept
meta skuid 0 accept
ip daddr 127.0.0.0/8 accept
meta nfproto ipv6 drop
reject
}
}
⚠ RULE ORDERING: DNS BEFORE LOOPBACK
The DNS redirect (udp dport 53 dnat ip to 127.0.0.1:9053) must appear before the loopback accept rule in the output chain. When resolv.conf points to 127.0.0.1, DNS queries are addressed to the loopback interface. If the loopback accept rule fires first, the packet is accepted without redirection, causing silent DNS leak.
ℹ KILL SWITCH
TTP implements a dedicated filter_out chain that acts as a global Kill-Switch. It explicitly allows Tor, root, and local traffic while rejecting everything else. This ensures that no cleartext traffic can bypass the NAT redirection, covering edge cases like pre-existing connections or processes failing to be intercepted.
0x06

DNS Handling

DNS leak prevention is critical for anonymity. TTP redirects all DNS (UDP port 53) to Tor's DNSPort at 127.0.0.1:9053 via the nftables NAT rule, and additionally redirects the system resolver to 127.0.0.1.

PREFERRED resolvectl

Used when systemd-resolved is active. Runs: resolvectl dns <iface> 127.0.0.1. Integrates cleanly with the resolver daemon, no file overwrite.

FALLBACK resolv.conf

Used when systemd-resolved is not active. Saves the original content of /etc/resolv.conf, then overwrites it. Never used on systems where systemd-resolved is running.

ℹ DOUBLE PROTECTION
DNS leak prevention works on two levels simultaneously: the nftables NAT rule intercepts all UDP port 53 traffic at the kernel level, and the system resolver configuration ensures glibc lookups go through Tor's DNSPort.
0x07

CLI Reference

All commands require sudo. Global flags --verbose / -v and --quiet / -q are available on all commands.

sudo ttp start [--interface/-i <iface>]

Starts the transparent proxy session. Orchestrates the full startup sequence.

output
[TTP] Detecting Tor... found (v0.4.9.6), service active (user: debian-tor).
[TTP] Stateless nftables rules applied (Table: inet ttp).
[TTP] DNS set via resolvectl on interface ens3.
[TTP] Waiting for Tor to bootstrap... 100%
[TTP] Tor is 100% bootstrapped.
[TTP] Verifying Tor routing...
[TTP] ✅ Session active. Exit IP: 109.70.100.11
[TTP] Use 'ttp stop' to terminate. 'ttp refresh' to change IP.
sudo ttp stop

Stops the session and restores the network to its original state.

output
[TTP] Removing nftables rules...
[TTP] Restoring DNS...
[TTP] 🔴 Session terminated. Traffic in cleartext.
sudo ttp refresh

Requests a new Tor circuit without stopping the session. Traffic continues to flow through Tor uninterrupted while the circuit rotates.

sudo ttp status

Shows the current session status. Reads the lock file and fetches the current exit IP.

output
[TTP] Status: ACTIVE
[TTP] Exit IP: 185.181.61.201
[TTP] Session started: 2026-04-19T01:07:33.384801+00:00
[TTP] Process PID: 3392
sudo ttp diagnose

Runs a comprehensive system diagnostic and prints a detailed report. Checks Tor service status, torrc configuration, active nftables rules, and DNS settings.

sudo ttp uninstall

Performs a deep cleanup of the TTP state. Stops any active session, removes the SELinux policy module, and deletes log files. Note: This does not remove the ttp binary itself; for that, use uninstall.sh.

0x08

Crash Recovery

TTP is designed around the assumption that any process can die at any time. The lock file at /var/lib/ttp/ttp.lock contains all information needed to undo changes.

NORMAL
ttp stop

Reads lock → restores firewall via backup file → restores DNS via saved content → deletes lock. Clean exit.

HANDLED
Ctrl+C  /  kill (SIGINT, SIGTERM)

Signal handlers registered at startup intercept the signal and call the same cleanup routine as ttp stop before exiting.

RECOVERED
kill -9  /  power outage

The lock file survives. On the next ttp start, if the process is dead, the lock is orphaned and state.attempt_recovery() is called automatically to restore firewall and DNS.

⚠ MANUAL RECOVERY
If for any reason automatic recovery does not run, you can restore the network manually:
# Destroy TTP firewall rules
$ sudo nft destroy table inet ttp
# Restore DNS (resolvectl mode)
$ sudo resolvectl revert <interface>
# Remove stale lock
$ sudo rm /var/lib/ttp/ttp.lock

Or use the nuclear option: sudo ./restore-network.sh

0x09

Distro Support

TTP handles the main differences between distributions automatically.

Distribution Service Unit Tor User Package Manager Status
Debian 13 tor@default debian-tor apt-get Tested (VM)
Ubuntu 22.04+ tor@default debian-tor apt-get Tested (VM)
Fedora 41+ tor toranon dnf Tested (Docker)
Arch Linux tor tor pacman Tested (Docker)
openSUSE tor _tor zypper Experimental
ℹ DEBIAN SERVICE UNIT
On Debian, tor.service is a multi-instance master that reports active (exited) even when no daemon is actually running. The real daemon lives in tor@default.service. TTP detects this safely.
0x0A

Development

Running unit tests

Unit tests are fully mocked, no root, no network, no system modifications.

bash
$ pip install -e ".[dev]"
$ pytest tests/ -v -m "not integration"

VM integration tests

Integration tests require root and a real Tor daemon. They run inside a QEMU VM (Debian 13) or Docker containers.

bash
# Docker integration tests
$ ./vm-helpers/run_integration_tests.sh debian
$ ./vm-helpers/run_integration_tests.sh fedora
$ ./vm-helpers/run_integration_tests.sh arch
# QEMU VM workflow
$ ./vm-helpers/start.sh
$ ./vm-helpers/snapshot.sh save pre-test
$ ./vm-helpers/send.sh
$ ssh -p 2222 debian@localhost
# If network breaks:
$ ./vm-helpers/snapshot.sh load pre-test

Project structure

tree
├── pyproject.toml # Package metadata and dependencies
├── README.md
├── CONTRIBUTING.md
├── SECURITY.md
├── CHANGELOG.md
├── install.sh # Recommended system-wide installer
├── uninstall.sh # System-wide uninstaller
├── restore-network.sh # Emergency network recovery script
├── assets/ # Branding and system policies
│ ├── gif/ # Demo animations
│ └── selinux/ # SELinux policy source (.te only)
├── packaging/ # Native packaging files (.deb, .rpm, Arch)
│ ├── build_deb.sh
│ ├── build_rpm.sh
│ ├── ttp.spec
│ ├── PKGBUILD
│ └── ttp.service
├── vm-helpers/ # QEMU VM management scripts
│ ├── start.sh
│ ├── send.sh
│ ├── snapshot.sh
│ ├── run_integration_tests.sh
│ ├── Dockerfile.debian.test
│ ├── Dockerfile.fedora.test
│ └── Dockerfile.arch.test
├── ttp/ # Source code
│ ├── cli.py # Typer entry point
│ ├── exceptions.py # Custom exception hierarchy
│ ├── tor_detect.py # Tor detection logic
│ ├── tor_install.py # Auto-install & configuration
│ ├── firewall.py # Atomic nftables management
│ ├── dns.py # DNS leak prevention
│ ├── state.py # Lock file and crash recovery
│ ├── tor_control.py # Tor daemon interaction and API
│ └── system_info.py # System diagnostic gathering
├── tests/ # Unit tests (mocked)
└── docs/
└── TDD.md # Technical Design Document
0x0B

Known Limitations

⚠ TOR BROWSER / EXPLICIT SOCKS5 PROXY
Applications that configure an explicit SOCKS5 proxy (e.g. Tor Browser, some curl invocations) will create a double Tor hop - their traffic goes through Tor once via TTP's transparent redirect and a second time via their own SOCKS5 connection. This is not a security issue but adds latency. Use a regular browser while TTP is active.
⚠ IPv6 BLOCKED
All outgoing IPv6 traffic is dropped while TTP is active. Some ISPs force IPv6 and applications may fail to connect if they don't fall back to IPv4. Routing IPv6 transparently through Tor requires additional configuration complexity; this is deferred to a future version.
⚠ UDP (NON-DNS) NOT PROXIED
Only TCP traffic and DNS (UDP port 53) are handled. Other UDP traffic (e.g. VoIP, some games, QUIC/HTTP3) is blocked by the kill switch, not proxied through Tor. Tor's TransPort only supports TCP.
⚠ EXIT IP VARIATION ON ttp status
Different connections may show different exit IPs due to Tor's stream isolation. The IP shown by ttp status reflects the circuit used to reach check.torproject.org, which may differ from the circuit used by other applications.
ℹ torrc OVERWRITE
When TTP installs and configures Tor, it modifies /etc/tor/torrc to add required directives. The original file is backed up to torrc.bak before any changes. Custom configurations are preserved where possible.
0x0C

Uninstallation

TTP provides two levels of removal depending on how you installed it.

CLI COMMAND ttp uninstall

Use this to clean up the system state while keeping the TTP binary. It stops any active session, removes the SELinux policy module, and clears log files.

SHELL SCRIPT ./uninstall.sh

A complete system removal. If you used install.sh, this script will remove /opt/ttp, the symlink in /usr/local/bin, and perform all the cleanups of the CLI command.