How to create a Tor router?

Hello,
I want to set up a Linux gateway that routes traffic over Tor so that anyone who enters the Linux IP address can access the internet via Tor.
I changed the Tor configuration file as follows:

TransPort 9040
DNSPort 53
VirtualAddrNetwork 10.192.0.0/10
AutomapHostsOnResolve 1

The iptables rules are as follows:

#!/bin/bash

# Clear existing rules
iptables -F
iptables -t nat -F
iptables -t mangle -F

# Enable forwarding and network settings
sysctl -w net.ipv4.ip_forward=1
sysctl -w net.ipv4.conf.all.rp_filter=0
sysctl -w net.ipv4.conf.enp0s3.rp_filter=0
sysctl -w net.ipv4.conf.all.route_localnet=1

# Set default policies
iptables -P INPUT DROP
iptables -P FORWARD ACCEPT
iptables -P OUTPUT ACCEPT

# Allow loopback interface
iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT

# SSH ACCEPT RULES
# Allow established SSH connections
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# Allow new SSH connections on port 22 from anywhere
iptables -A INPUT -p tcp --dport 22 -j ACCEPT

# FORWARD RULES for gateway functionality
# Allow forwarding between interfaces
iptables -A FORWARD -i enp0s3 -o enp0s3 -j ACCEPT

# Allow established connections in FORWARD chain
iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT

# Allow DNS responses back from Google DNS
iptables -A FORWARD -p udp --sport 53 -j ACCEPT

# Allow Tor traffic to forward
iptables -A FORWARD -p tcp --dport 9040 -j ACCEPT
iptables -A FORWARD -p tcp --sport 9040 -j ACCEPT

# OUTPUT RULES
# Allow Tor to send responses
iptables -A OUTPUT -p tcp --dport 9040 -j ACCEPT
iptables -A INPUT -p tcp --sport 9040 -j ACCEPT

# NAT RULES - Traffic redirection for ALL IPs (no restrictions)
# DNS: Forward all DNS queries to Google DNS (not through Tor)
iptables -t nat -A PREROUTING -i enp0s3 -p udp --dport 53 -j DNAT --to-destination 8.8.8.8:53

# TCP: Redirect all other TCP traffic to Tor
iptables -t nat -A PREROUTING -i enp0s3 -p tcp -j REDIRECT --to-port 9040

# Optional: Allow ICMP (ping) for debugging
iptables -A INPUT -p icmp -j ACCEPT

# Log dropped packets for debugging (optional)
iptables -A INPUT -j LOG --log-prefix "INPUT_DROP: " --log-level 4

But I can’t browse anything. My Linux server can see the traffic:

# tcpdump -i enp0s3 -v src host 172.21.50.77
tcpdump: listening on enp0s3, link-type EN10MB (Ethernet), snapshot length 262144 bytes
06:48:26.177486 IP (tos 0x0, ttl 128, id 29909, offset 0, flags [none], proto UDP (17), length 56)
    172.21.50.77.54664 > 172.21.50.52.domain: 35298+ A? zone94.com. (28)
06:48:26.177546 IP (tos 0x0, ttl 127, id 29909, offset 0, flags [none], proto UDP (17), length 56)
    172.21.50.77.54664 > dns.google.domain: 35298+ A? zone94.com. (28)
06:48:27.079925 IP (tos 0x0, ttl 128, id 29910, offset 0, flags [none], proto UDP (17), length 76)
    172.21.50.77.50283 > 172.21.50.52.domain: 37312+ A? self.events.data.microsoft.com. (48)
06:48:27.080035 IP (tos 0x0, ttl 127, id 29910, offset 0, flags [none], proto UDP (17), length 76)
    172.21.50.77.50283 > dns.google.domain: 37312+ A? self.events.data.microsoft.com. (48)
06:48:27.180032 IP (tos 0x0, ttl 128, id 29911, offset 0, flags [none], proto UDP (17), length 56)
    172.21.50.77.54664 > 172.21.50.52.domain: 35298+ A? zone94.com. (28)
06:48:27.180077 IP (tos 0x0, ttl 127, id 29911, offset 0, flags [none], proto UDP (17), length 56)
    172.21.50.77.54664 > dns.google.domain: 35298+ A? zone94.com. (28)
06:48:28.187805 IP (tos 0x0, ttl 128, id 29912, offset 0, flags [none], proto UDP (17), length 56)
    172.21.50.77.54664 > 172.21.50.52.domain: 35298+ A? zone94.com. (28)
06:48:28.187856 IP (tos 0x0, ttl 127, id 29912, offset 0, flags [none], proto UDP (17), length 56)
    172.21.50.77.54664 > dns.google.domain: 35298+ A? zone94.com. (28)

What is wrong?

Thank you.

This won’t work as a general “route all traffic through Tor” gateway.

Tor’s TransPort can transparently handle TCP, but Tor is not a normal IP/VPN gateway. Tor transports TCP streams, not arbitrary IP packets like UDP, ICMP, QUIC, etc.

A Tor transparent gateway is possible, but only with carefully redirected TCP plus DNS-to-Tor for a controlled LAN/subnet. For most cases, a SOCKS proxy is simpler and safer.

I installed and ran nipe. I also changed the Tor configuration as follows:

SocksPort 127.0.0.1:9050
TransPort 127.0.0.1:9040
DNSPort 127.0.0.1:5353
AutomapHostsOnResolve 1
VirtualAddrNetworkIPv4 10.192.0.0/10

I configured dnsmasq as follows:

# Listen on your gateway IP
listen-address=127.0.0.1,172.21.50.52

# Bind to interface
bind-interfaces

# Forward DNS queries to Tor's DNSPort
server=127.0.0.1#5353

# Don't forward reverse lookups for local networks
no-negcache

# Log queries for debugging
log-queries

# Don't read /etc/resolv.conf
no-resolv

# Cache size
cache-size=1000

# Log queries for debugging
log-queries
log-facility=/var/log/dnsmasq.log

The resolv.conf file is as follows:

nameserver 127.0.0.1
options edns0

On Debian:

# nslookup google.com 172.21.50.52
Server:		172.21.50.52
Address:	172.21.50.52#53

Non-authoritative answer:
Name:	google.com
Address: 142.251.39.142
Name:	google.com
Address: 2a00:1450:400e:809::200e

But, from my client:

# tcpdump -i enp0s3 -n host 172.21.50.77 and port 53
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on enp0s3, link-type EN10MB (Ethernet), snapshot length 262144 bytes
03:51:43.999793 IP 172.21.50.77.63645 > 172.21.50.52.53: 34385+ A? api.intelsa.intel.com. (39)
03:51:44.522355 IP 172.21.50.77.63646 > 172.21.50.52.53: 1+ PTR? 52.50.21.172.in-addr.arpa. (43)
03:51:46.530926 IP 172.21.50.77.63647 > 172.21.50.52.53: 2+ A? google.com.mydomain.com. (41)
03:51:48.532525 IP 172.21.50.77.63648 > 172.21.50.52.53: 3+ AAAA? google.com.mydomain.com. (41)
03:51:50.536529 IP 172.21.50.77.63649 > 172.21.50.52.53: 4+ A? google.com. (28)
03:51:52.542196 IP 172.21.50.77.63650 > 172.21.50.52.53: 5+ AAAA? google.com. (28)

Why?

Hello,

Do you understand my point? I want to use Linux as a Default Gateway but have traffic routed over the Tor network. Do you know of an article that teaches this?

You can add two default routes in different routing tables, then configure the OS to use uidrange or something else to match the tor processes.

uidrange NUMBER-NUMBER
select the uid value to match.

Hello,

The /etc/tor/torrc is:

SocksPort 127.0.0.1:9050
TransPort 127.0.0.1:9040
DNSPort 127.0.0.1:5300
AutomapHostsOnResolve 1
VirtualAddrNetworkIPv4 10.192.0.0/10
TransListenAddress 0.0.0.0
DNSPort 0.0.0.0:5353

And I asked AI to modify the iptables rules to use uidrange:

#!/bin/bash

# =============================================
# FIXED TOR GATEWAY FOR YOUR SETUP
# =============================================

# Your actual interface (only one interface visible)
_OUT_IF="enp0s3"           # Your only interface (WAN + LAN combined)

# Get the actual gateway
_MAIN_GW=$(ip route show default | awk '/default/ {print $3}')

# Get your LAN subnet (assuming 192.168.1.0/24 based on your iptables)
_LAN_NET="192.168.1.0/24"

# Tor settings
_TOR_UID=$(id -u debian-tor)
_TRANS_PORT="9040"
_DNS_PORT="5353"
_VIRT_ADDR="10.192.0.0/10"

echo "=== FIXING TOR GATEWAY SETUP ==="
echo "Main gateway: $_MAIN_GW"
echo "Tor UID: $_TOR_UID"
echo "Output interface: $_OUT_IF"

# =============================================
# 1. FIX POLICY ROUTING
# =============================================

# Remove existing rules
ip rule del uidrange $_TOR_UID-$_TOR_UID lookup tor_bypass 2>/dev/null
ip rule del priority 1000 2>/dev/null

# Flush routing tables
ip route flush table tor_bypass 2>/dev/null
ip route flush table tor_direct 2>/dev/null

# Recreate tor_bypass table (for Tor's own direct connections)
ip route add default via $_MAIN_GW dev $_OUT_IF table tor_bypass
ip route add $_LAN_NET dev $_OUT_IF table tor_bypass

# tor_direct table (for traffic going through Tor proxy)
ip route add default dev lo table tor_direct

# CRITICAL FIX: Allow Tor's own traffic to bypass Tor (use tor_bypass)
ip rule add uidrange $_TOR_UID-$_TOR_UID lookup tor_bypass priority 100

# All other traffic uses main table (which we'll redirect to Tor)
# Don't add extra rules that conflict

echo "Fixed routing rules:"
ip rule show
echo ""
echo "tor_bypass table:"
ip route show table tor_bypass
echo ""
echo "tor_direct table:"
ip route show table tor_direct

# =============================================
# 2. FIX IPTABLES - ADD MISSING NAT RULES
# =============================================

# Flush everything
iptables -F
iptables -t nat -F
iptables -t mangle -F
iptables -X

# Default policies
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT DROP

# =============================================
# NAT TABLE (THIS WAS MISSING!)
# =============================================

# Redirect DNS to Tor
iptables -t nat -A OUTPUT -d 127.0.0.1 -p udp --dport 53 -j REDIRECT --to-ports $_DNS_PORT

# Redirect virtual address range to Tor
iptables -t nat -A OUTPUT -d $_VIRT_ADDR -p tcp --tcp-flags FIN,SYN,RST,ACK SYN -j REDIRECT --to-ports $_TRANS_PORT

# IMPORTANT: Don't redirect Tor's own traffic (using routing table, not iptables owner)
iptables -t nat -A OUTPUT -o lo -j RETURN

# Don't redirect LAN traffic
iptables -t nat -A OUTPUT -d $_LAN_NET -j RETURN

# Redirect all other TCP to Tor
iptables -t nat -A OUTPUT -p tcp --tcp-flags FIN,SYN,RST,ACK SYN -j REDIRECT --to-ports $_TRANS_PORT

# For Windows client (forwarded traffic)
iptables -t nat -A PREROUTING -i $_OUT_IF -p tcp --tcp-flags FIN,SYN,RST,ACK SYN -j REDIRECT --to-ports $_TRANS_PORT
iptables -t nat -A PREROUTING -i $_OUT_IF -p udp --dport 53 -j REDIRECT --to-ports $_DNS_PORT

# =============================================
# FILTER TABLE - INPUT
# =============================================

iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -m state --state NEW -j ACCEPT
iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT
iptables -A INPUT -s $_LAN_NET -p udp --dport $_DNS_PORT -j ACCEPT

# =============================================
# FILTER TABLE - FORWARD (for Windows client)
# =============================================

iptables -A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A FORWARD -i $_OUT_IF -o $_OUT_IF -j ACCEPT

# =============================================
# FILTER TABLE - OUTPUT
# =============================================

iptables -A OUTPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT
iptables -A OUTPUT -p icmp -j ACCEPT

# Allow Tor user to make direct connections (this works with policy routing)
iptables -A OUTPUT -o $_OUT_IF -p tcp --tcp-flags FIN,SYN,RST,ACK SYN -m state --state NEW -j ACCEPT

# Allow connections to Tor's proxy ports
iptables -A OUTPUT -d 127.0.0.1 -p tcp --dport $_TRANS_PORT -j ACCEPT
iptables -A OUTPUT -d 127.0.0.1 -p udp --dport $_DNS_PORT -j ACCEPT

# Allow SSH
iptables -A OUTPUT -p tcp --sport 22 -m state --state ESTABLISHED -j ACCEPT

echo ""
echo "=== NAT TABLE RULES (now added) ==="
iptables -t nat -S

echo ""
echo "=== VERIFICATION ==="

# Test if Tor is working
if systemctl is-active --quiet tor; then
    echo "âś“ Tor is running"
else
    echo "âś— Tor is NOT running - start with: systemctl start tor"
fi

# Test DNS through Tor
echo "Testing DNS through Tor..."
timeout 2 dig @127.0.0.1 -p $_DNS_PORT google.com +short

echo ""
echo "=== FIX COMPLETE ==="
echo "To test Tor: sudo -u debian-tor curl --socks5-hostname 127.0.0.1:9050 https://check.torproject.org/api/ip"

I got the same result.

Can you tell me which part is wrong?

Use LLMs to generate code which you can’t understand is very dangerous, please don’t do this.