Skip to main content

Setting up a transparent pass-through proxy with iptables

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= # My Laptop's IP Adress
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` #
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 -j ACCEPT
iptables -t nat -I PREROUTING -i br0 -d -j ACCEPT
So 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 as an upstream proxy in tinyproxy’s configuration and voila , Its 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 : 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:

iptables -t nat -A OUTPUT -d,,, -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 a 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.


  1. MGM Resorts Casino & Hotel - Dr. Maryland
    MGM Resorts Casino & 청주 출장마사지 Hotel is located in the heart of the scenic Northeast, just 천안 출장샵 steps from 충주 출장샵 Horseshoe International 광양 출장샵 Airport. It 포천 출장마사지 is just 6.1 mi from


Post a Comment

Popular posts from this blog

Transparent Pass-through proxy with iptables – Part 2 (for HTTPS)

This is part 2 of my earlier post on how to set configure to use a http proxy transparently. This post deals with extending the same for transparent HTTPS proxying. Click Here for my earlier post which deals with HTTP proxying. For a quick-fix solution and list of files mentioned in this post skip to the bottom of the post. After setting up a transparent http proxy on my dd-wrt router to transparently proxy my HTTP requests I haven’t had any issues for more than a year and was happily able to use it. But up until recently my local network used to allow direct HTTPS connections to external IP addresses. Now my network has disabled that, which means I need to forcefully use the HTTP proxy in order to be able to make HTTPS connections. Surprisingly this caused many more problems than I had anticipated. Lots of applications on android which seemed to work fine after setting proxy settings started failing badly! Notably gmail, hangouts, facebook messenger all only worked very sporadical

Converting Your DD-WRT Router to a clock!

So the other night I suddenly woke up in the middle of the night. I was fumbling through my extremely messy desk, which was next to my pillow, to find my phone so that I could see the time. Alas my desk was far too messy to find my phone in the dark. I was far too lazy to take the effort of turning on the lights just to see the time. That was when my eyes glanced upon the ominous green blinking LEDs blinking fervently on my router docked on my wall. I wished I had an LED clock instead and boom it hit me! I have a linux-based DD-WRT router, that means I have full control over it :P. So that was how I began my quest on converting a piece of network equipment to a digital clock! TP-Link WR740N Router The next day, I set upon my quest to find out how I could control the blinking LEDs on my router. I noticed that my router had a total of 9 LEDs , and I figured that was more than sufficient to display the time in binary to a sufficient degree. My plan was originally to use 4 LEDs t

Welcome to my Site!

Hello! I am Anish Shankar. I love exploring new stuff & Technology interests me a lot. I am a Software Engineer at Google in the Bay Area, and have worked on a variety of Infrastructure projects. In the past I've participated in a lot of programming competitions and used to go by the handle "phinfinty". I've since retired from competitive programming, but the handle has stuck with me! I am a Linux enthusiast and love open source. I use Arch Linux currently for most of my personal work. This website is rarely updated and currently archival.

Some useful SSH configurations

Lately I was tired of having to repeatedly type my user name for my ssh connections. In my current setup I often ssh to two servers inside the IIIT (my college) network. merely typing ssh would try to use the username as my local computer’s login user name. So I was trying to get a workaround for this. A simple approach would be to rename my local computer’s user name to the IIIT server user name , but now that would be very lame. So I figured there must be some simple configuration available and looked up man ssh_config which gave an extremely detailed list of all the possible configuration options. Finally my configuration file looked like this : Host * mirage web User iiit_login_user Host * ControlMaster auto ControlPath /home/phinfinity/.ssh/%r@%h:%p GSSAPIAuthentication no The first line specifies the categories for which the configuration below are to be used. Here I have specified the configuration to be applied for 3 possible categories “*.ii