Redirect local traffic to proxy port with iptables

I have a Ubuntu 12.04 host that has a squid proxy on it running on port 8080. I want to proxy all the web traffic from the host through squid using iptables. Is the correct method:

iptables -t nat -I OUTPUT -p tcp -d 127.0.0.1 --dport 80 -j REDIRECT --to-ports 8080

This is not working. When I browse to a page it appears normally, even when the proxy is disabled. Any suggestions appreciated.


Solution 1:

iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080

In your rule, IPTables will only redirect traffic destined for localhost to the proxy. This rule will redirect any traffic destined for port 80. In your rule, change -d to -s and it shall work.

Solution 2:

tl;dr Your command is very close. You need to remove the -d 127.0.0.1 fragment and ensure you run your proxy process as a different user and exclude that user from the filter with -m owner ! --uid-owner <other-username> so the proxy doesn't have its traffic redirected to itself.

More detail

I found that most of the suggestions for configuring iptables for transparent proxy make the assumption that the proxy machine is on a separate host from the clients. I want to proxy traffic that originates from my machine (and I also run the proxy on the same machine).

The way I read your questions makes me think you want the same thing.

This blog post mentions the fix:

localhost too

If you want to run the client on the same machine as the server (you’re in a coffee shop on your laptop; have a pastry for me), we can’t use the PREROUTING table, because it only applies to packets coming from outside. What we can do is modify the destination port on packets OUTPUT by our client process. The catch is that it will also affect packets output by mitmproxy, and we’ll get into a routing loop.

There are probably several ways to solve this, but the one that worked for me was running mitmproxy as root, and making the iptables rule not apply to root-owned processes.

sudo iptables -t nat -A OUTPUT -p tcp -m owner ! --uid-owner root --dport 443 -j REDIRECT --to-port 8080
  • -m owner: Load the owner module.
  • ! –uid-owner root: Rule does not apply to root-owned processes

Remember that in this case you’ll run mitmproxy as root. This will also log all your https web browser traffic. Add -m multiport and replace --dport with --dports to intercept multiple ports (or just repeat the line with a different port).

And this mitmproxy forum thread has a solution so you don't have to run as root. You create a separate user specifically to run mitmproxy and then exclude that user's uid in the iptables filter.

I found that the thread linked in the comment by @keerthi isn't quite right because that is about forwarding a single port on localhost, whereas I think you want to forward all traffic.