I've successfully set up Tor for transparent proxying using iptables (ie, all outgoing traffic is sent through Tor without the application's knowledge). In doing so, I discovered both an odd problem and an equally odd fix (workaround?).

My rules are as follows. No user-defined chains or other rules present, all policies are ACCEPT.

-t nat -A OUTPUT -o lo -j RETURN
-t nat -A OUTPUT -p tcp -m owner --uid-owner tor -j RETURN
-t nat -A OUTPUT -p tcp --syn -j REDIRECT --to-ports 54
-t nat -A OUTPUT -p udp --dport 53 -j REDIRECT --to-ports 55


-A OUTPUT -o lo -j ACCEPT # Rule A
-A OUTPUT -d -j ACCEPT # Rule B
-A OUTPUT -p tcp -m owner --uid-owner tor -j ACCEPT

In other words:

  • All traffic from/to localhost is untouched.
  • All traffic generated by Tor is untouched.
  • All outgoing TCP connections are sent through Tor (transparent proxying port is 54).
  • All outgoing DNS queries are resolved by Tor (DNS on port 55).
  • To prevent leakage, all other outgoing traffic is hit on the head with a brick and dropped in a ditch.

(While this setup has some problems, like failing to respond to connections from the LAN, those are irrelevant to the issue at hand.)

If Rule B is not present, all outgoing connections are immediately rejected by Rule C. I know they are rejected by Rule C because changing the rejection type (ex. --reject-with icmp-proto-unreachable) results in a different error. Example error messages without Rule B:

# With Rule C --reject-with icmp-port-unreachable, the default:
$ curl # (google.com; DNS also doesn't work)
curl: (7) Failed connect to; Connection refused

# With Rule C --reject-with icmp-proto-unreachable:
$ curl
curl: (7) Failed connect to; Protocol not available

With Rule B, connections work fine.

Based on my understanding of iptables, when an outgoing TCP connection is made, the third rule in OUTPUT chain of nat will rewrite the packet's destination to The packet will then enter OUTPUT chain of filter, and it should be matched by Rule A, since its outgoing interface is now the loopback interface. However, it is not matched by Rule A, and if Rule B (which does match it) is not present, the packet gets dragged into an alley and mugged by Rule C.

Why aren't Rule A and Rule B equivalent? How is matching the loopback interface different from matching the loopback address, in this situation?

  • Further research indicates that this may be because there is no routing decision between nat OUTPUT and filter OUTPUT. So even if the packet's destination address is altered, its outgoing interface is not updated until after filter OUTPUT. I'm not sufficiently confident to make this an answer though. – Sam Harada Nov 15 '13 at 1:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.