DNS Tunneling made easy
Yesterday I came across a technique to tunnel any traffic through the DNS protocol: All the packages you send are base32 encoded and prepended as the hostname of a DNS lookup request. A specially prepared DNS server will then forward your packages and reply with TXT answers.
What is it good for? It's an interesting way to hide your traffic. Cory Doctorow wrote about it in Little Brother for example. But it can also be used to sneak into certain public hotspots which are protected by HTTP redirections only. Those hotspots will allow web traffic to some few restricted websites (or some login page) only, but often allow all DNS traffic. It should also work to circumvent restrictive company firewalls.
I googled for implementations and came across two.
One is NSTX which makes use of the tun device support in Linux. This seems to be an excellent choice when you plan to use DNS tunneling on a regular basis.
Those scripts can be combined with SSH to tunnel arbitrary traffic and there's an excellent documentation how to do that at dnstunnel.de.
However I found those scripts to be a bit messy and some things simply didn't work. They also contained code that was unrelated to DNS tunneling traffic.
I spent some hours to clean up the OzimanDNS scripts by doing the following things:
- fixed code indention
- fixed most warnings with
- fixed bugs (like non working listen option in the daemon, or the messed up resolver settings in the client)
- cleaned usage notices
- renamed some option switches (was needed to avoid name collisions)
- removed all unneeded code (like storing data in the DNS server) – less code, less potential flaws
- added privilege dropping after opening port 53
- added init scripts
You can download the whole thing here: dnstunnel.tgz
Read on for a quick guide how to use it.
Setting up a DNS Tunnel Web-Proxy
The goal is to use SSH's builtin Socks proxy to be used with Firefox to tunnel all traffic through DNS requests only.
Here's what you need:
- The tarball above
- Control over a DNS server
- A server to set up the daemon
- It can not already run an external DNS service
- You need to have root access
- Perl, a bunch of Perl modules, screen, SSH
- Some Unix and DNS knowledge helps as well
For making DNS tunneling work we'll setup our own DNS server that has to be authoritative for a given (sub)domain. Let's assume we have our own root server running at
www.example.com using the IP
18.104.22.168. That box also will run our tunnel daemon. Our new subdomain for DNS tunneling should be
This means we have to setup DNS delegation for that subdomain on the nameserver that is responsible for
example.com. In Bind this can be done using something like this:
tunnel.example.com. IN NS www.example.com. www.example.com. IN A 22.214.171.124
All DNS requests for
*.tunnel.example.com will now go to the IP
On to the server at
www.example.com. Here you should install a few needed software packages first. The following should suffice on Debian:
#> apt-get install screen libnet-dns-perl libmime-base32-perl
Then download dnstunnel.tgz and unpack it to
/opt/ – creating
Edit the config at the top of the
dnstunneld.wrapper' script. Eg. if you're running a caching DNS on the local interface you may want to bind the tunnel server to the external interface explicitly. You also may want to specify the user and group the daemon will run as. Run
dnstunneld without arguments to get a list of possible options.
Here's an example:
DNSHOST="tunnel.example.org" REPLYIP="127.0.0.1" OPTIONS="-l 126.96.36.199 -u nobody -g nogroup"
Now link the init script and start the server
#> ln -s /opt/dnstunnel/dnstunneld.init /etc/init.d/dnstunneld #> /etc/init.d/dnstunneld start
A DNS lookup for
foo.tunnel.example.com should now return
On the laptop, we need
libmime-base32-perl again. Then copy the
dnstunnelc script somewhere in your PATH. I suggest
To test the connection let's try to login via SSH using the tunnel client as proxy:
$> ssh -C -o ProxyCommand="dnstunnelc -v sshdns.tunnel.example.com" you@localhost
sshdns bit? The tunnel daemon will only answer with tunnel replies when this is set. You can change the name on the server with the
-f option. The secrecy of the DNS name is the only “authentication” for the tunnel it self, so choose wisely.
Of course the access to the box behind the tunnel is protected by the usual SSH mechanisms. Notice the use of
localhost refers to the tunnel server of course, because when SSH arrives at the end of the tunnel it is
Now if everything works, you can use SSH to open a Socks proxy:
$> ssh -D 8000 -N -C -o ProxyCommand="dnstunnelc sshdns.tunnel.example.com" you@localhost
Refer to my Conference WiFi Security article on how to set it up with Firefox.
dnstunnelc script without any arguments to learn about a few more options. It has some interesting mechanisms to spread your DNS requests over many DNS servers.
PS: Circumventing access restrictions with this method might be illegal depending on where and what for you use it. Use it at your own risk.