Tinyproxy transparent iptables howto

Update: Part 2 for https posted in separate post!

So for a very long now I've had a nagging issue with proxies. My primary source of internet is through my college HTTP Proxy and this adds a couple of issues whenever I am dealing with applications that don’t have proxy support coded in them. I have this issue often both on my laptop as well as on my android tablet (Youtube streaming!). Its a very distressing situation and I've always wanted to set-up a transparent proxy solution which could re-direct the traffic out of such applications to a sort of secondary proxy server which can interpret the requests and forward them to my college proxy server . Recently I managed to get this working!

The main tool used for this was iptables. For those of you who haven't heard of iptables at a glance it is a flexible firewall which is now part of the Linux kernel by default. But iptables is actually much more powerful and flexible than just a simple firewall to block ports. iptables is capable of doing complicated re-routing of packets on several criteria. So much so that a lot of routers running linux (Yes quite a lot of them run Linux) use iptables to manage packets.


In my current setup I have a router which is connected to the IIIT LAN which has access to the proxy server. And laptop is connected to the router. I managed to install DD-WRT which is a Linux based firmware for routers. So I can now SSH to my router and mess with the iptables on it. The idea was to redirect all traffic on port 80 which goes through the router back to a server running on my laptop.

iptables has rules across 5 tables: filter, nat, mangle, raw, security. The default table is filter which as its name suggests is used to filter traffic and block certain traffic etc. The nat table which is what we are interested in has to do with actual routing of a tcp stream when a new connection is created. In each of these tables iptables has a standard set of chains like “PREROUTING”, “POSTROUTING” in nat, which corresponds to sub-categories of packets. In this case before routing, etc.

Here are the rules I used based off DD-WRT Wiki - Transparent Web Proxy

PROXY_IP = 192.168.128.2 # My Laptop's IP address
PROXY_PORT = 1234 # Port number to redirect traffic to
LAN_IP = `nvram get lan_ipaddr` # This gets the IP Address of the router
LAN_NET = $ LAN_IP / `nvram get lan_netmask` # 192.168.128.1/255.255.255.0
iptables -t nat -A PREROUTING -i br0 -s $ LAN_NET -d $ LAN_NET -p tcp --dport 80 -j ACCEPT
iptables -t nat -A PREROUTING -i br0 -p tcp --dport 80 -j DNAT --to $ PROXY_IP: $ PROXY_PORT
iptables -t nat -I POSTROUTING -o br0 -s $ LAN_NET -d $ PROXY_IP -p tcp -j SNAT --to $ LAN_IP
iptables -I FORWARD -i br0 -o br0 -s $ LAN_NET -d $ PROXY_IP -p tcp --dport $ PROXY_PORT -j ACCEPT
iptables -t nat -I PREROUTING -i br0 -d 192.168.36.0/24 -j ACCEPT
iptables -t nat -I PREROUTING -i br0 -d 10.0.0.0/13 -j ACCEPTSo lets see what these mean.

  • The first rule is a rule which makes sure that all internal traffic on port 80 (from the router’s subnet to the router’s subnet) are not affected and continue to get processed normally.
  • The next rule is what actually re-routes traffic on port 80 to the my laptop on port 1234. the jump target “-j DNAT” tells iptables to modify the destination address and port of the packet matched by the criteria specified
  • The 3rd rule modifies the source address of the packet so that it appears as if it is coming from the router. This is necessary as otherwise traffic from my laptop when redirected back to my laptop will not be accepted by my laptop as it may consider it as illegal routing. (I am not completely sure about this one, but it didn’t work for me without it)
  • The 4th rule ensures that actual traffic intended directly for the PROXY_PORT on my laptop continues to reach my laptop.
  • The last 2 rules ensure that traffic directed to the IIIT Network are not re-directed to my laptop as I don't need a proxy for them.

Note that iptables processes rules in chained fashion. so it stops with the first rule which matches. Each command has a ‘-A’ or a ‘-I’ flag, which stands for Append at the end of the chain and Insert at the front.

This setup now ensures that all the traffic gets re-routed to a secondary proxy server I will run on my laptop. Initially I was planning on writing my own proxy handler to modify the HTTP headers as I get them to be compatible with the proxy. But eventually I decided its simpler and safer to go with an existing proxy server. I went with tinyproxy over well established ones like squid simply due to the tiny footprint of tinyproxy. I simply had to add proxy.iiit.ac.in:8080 as an upstream proxy in tinyproxy’s configuration and voila, It's done!

A similar setup can more easily be done on a single system without the need for an external router. As we will simply have to re-direct outgoing traffic from the system on port 80 back to localhost. Although we now have transparent proxying this does not mean that every application will work. There's still the major restriction that only HTTP requests on port 80 are handled. In my case the IIIT proxy server blocks other ports and proxying might not work in those cases. Keep in mind that all information about the target host is lost in this method and only the fact that the HTTP request actually contains the host name allows us to use this.

Hope you find this useful! I certainly did now that I can finally watch youtube videos on my android tablet and more importantly download updates for Minecraft!

Edit1:

I came across a version of tinyproxy, pre-configured and built for the atheros architecture (the same as my router). You can find it at:
https://downloads.openwrt.org/snapshots/trunk/ar71xx/packages/packages/tinyproxy_1.8.3-2_ar71xx.ipk Make sure this is the version compatible for your router, before trying it. Here’s the installation commands I used (on the router)

mkdir / tmp / tinyproxy
cd / tmp / tinyproxy
wget http: //someserver/tinyproxy.ipk
# get the file here somehow, not proxy server won't work to get from original source
ipkg -d / tmp / tinyproxy tinyproxy.ipk
/ tmp / tinyproxy / usr / sbin / tinyproxy -c tinyproxy.conf #specify ur config file somewhere

After a bit of tweaking and adding this on the startup script, we have it setup to work automatically on reboot from the router alone.


Edit 2:
A lot of people where too lazy to come up with an iptables filter to work on a single laptop / computer. So here’s the iptable rules for the same:

#! / bin / bash
DEV = eth1
PROXY_IP = 127.0.0.1
PROXY_PORT = 1234
iptables -t nat -A OUTPUT -d 192.168.0.0/16,10.0.0.0/8,172.16.0.0/12,127.0.0.1 -j ACCEPT
iptables -t nat -A OUTPUT -p tcp --dport 80 -j DNAT --to $ PROXY_IP: $ PROXY_PORT



If you just want to get it working, without understanding any of it, I've made an all-in-one script just for you: D
You can get it here. It has tiny proxy included in it, and it automatically sets everything up including the iptables. Its currently configured for the IIIT proxy server, so you might want to change it depending on your proxy’s ip.