/ iodine

DNS Tunneling with Iodine

Image Description

I recently set up DNS Tunneling on one of my VPSs. This technology is incredibly useful for bypassing captive portals, filters etc. as DNS is required for internet usage so egress on port 53 is almost always allowed on a network.

While sometimes these DNS requests are restricted to whitelisted servers or only for specific domains you will usually find that DNS is completely unrestricted and as always, if we control both ends of the pipe then we can tunnel data through it.

We could just set up an SSH server or similar on port 53, but in some cases the protocol will be filtered and your tunnel will fail. Tunneling over DNS then, seems like the best option.


To do this, we're going to use a tool called iodine. Iodine consists of a DNS daemon we run on our server that listens for incoming DNS requests and unwraps the tunneled data. We then have a client that we run on the, well, client, that handles the other side.

The client sets up the tunnel and exposes the server as a new tunneled IP. We can then use this normally, but for full tunneling we'll want to connect to it using SSH to set up a dynamic proxy. So technically we're going to set up an SSH tunnel over a DNS tunnel!

Registering your DNS server

The first step will be to register our server as a DNS server. To do this we'll need a domain. GoDaddy has some cheap domains and has a privacy option so that our personal details aren't exposed by whois domain lookups.

Once we have a domain we must enter an NS record for it in the domain control panel such as:

t1		IN	NS	ourdomain.com.		; note the dot!

If you already have a domain and want to use a different server for your iodine server, you can set up a subdomain first and register the IP of the iodine server, then point the NS record to this subdomain instead.

t1		IN	NS	t1ns.ourdomain.com.		
t1ns		IN	A	<iodine-server-ip>

This can take some time to propagate, but while it's doing so we can spend some time...

Setting up the daemon

The next step is to install iodine on the server. If you're using a debian-based distribution like me you can just do this using apt install iodine.

We can run the iodine daemon using the following command:

iodined -fcP secretpassword ourdomain.com


  • -f option tells it to run in the foreground
  • -c disables checking the client IP address on all incoming requests, which can avoid some issues
  • -P secretpassword details the shared secret between the client and the server for authentication
  • is the IP the server will be given on the client on the tun interface. The client will be given the next IP in the range.
  • ourdomain.com is the domain name of the DNS server we set up earlier.

Alternatively, if we want to set up iodine to run on start up you can enable the service using:

update-rc.d iodine enable


service iodine start

to start the service now. This will silently fail however until we set up the arguments to the daemon in the /etc/defaults/iodine file. In this file, we have to set

  • START_IODINED to true
  • IODINED_ARGS to -c ourdomain.com
  • IODINED_PASSWORD to secretpassword

Running the process as a service has the added benefit of running as the iodine user, which was added during its install.

Checking the config

Once everything is in place, we can check our config using the iodine check page.

If everything looks correct but it's still not working, check that our traffic isn't being caught by any firewalls etc on the server.

Running the client

On the client machine we then just have to run the iodine client. We can install iodine in the same manner as above and then run:

iodine -fP secretpassword ourdomain.com

and we should see some output followed by Connection setup complete, transmitting data. The server is then exposed locally on the tun interface with the ip Our DNS tunnel is complete!

Setting up the proxy

In order to have our browser or other tools use the tunnel, we have to set up a proxy. We're going to use SSH dynamic port fowarding to create a SOCKS proxy locally that will tunnel all traffic over SSH to our server, with SSH using the DNS tunnel.

Needless to say we'll need an SSH daemon running on our server. I'm going to assume that's already the case and if not there are plenty of guides already out there on how to do that.

We can then set up the proxy by issuing:

ssh -N -D 8080 [email protected]


  • -N instructs SSH not to start a shell, as we're just wanting to create the proxy
  • -D sets up the dynamic port forwarding, with the SOCKS proxy on port 8080
  • user is a user on our server
  • is our iodine server on the tun interface

Once this is done, we can just use the proxy in our browser. This can be done using, for example, the FoxyProxy extension in Firefox or Chrome. If all is successful, you should be able to check your IP in the browser and get back the IP of your server.


From here we're good to go! We can crack open a beer, sit back and enjoy our tunneled internets.