Iodine DNS Tunnel on Port 53
Iodine tunnels your network activity as DNS requests on port 53. This can be useful when all other ports are blocked or censored. The name Iodine was suggested by the initial letters of “IP over DNS.” By a happy coincidence, the element Iodine has atomic number 53, which just so happens to be the port number for DNS.
To construct an Iodine tunnel, you will need:
- A domain name (which we will give as
example.com
in our examples) - A server with a public IP address (which we will give as
xx.xx.xx.xx
in our examples) - A client PC
In this tutorial, the server and client both run Debian 10. The same procedures will work for recent versions of Ubuntu.
1. Create DNS Records
1.1. Select DNS Service
Almost all domain name registrars provide a DNS service, but not all registrars let you create type NS
records. If you cannot add NS
records add your registrar, you may need to switch your DNS service from your domain name registrar to Cloudflare.
1.2. Choose Subdomain
You are going to delegate the DNS service for one subdomain to your Iodine service. I suggest using a short name for the subdomain, so that as much space as possible is available for the tunneled data.
In our examples, we will use x
as the subdomain we delegate to Iodine.
1.3. Create DNS Records
At your DNS service (whether at your domain name registrar or elsewhere):
- Create an
A
record pointing fromnsx.example.com
to your server IP address ofxx.xx.xx.xx
- Create an
NS
record pointing from subdomainx
to hostnsx.example.com.
(which ends with a dot in most DNS systems)
1.4. Check DNS Records
You will need to wait for your DNS changes to propagate. How long this takes depends on your DNS service. You can check that your DNS A
record for your
server resolves by going to your PC and issuing these commands:
sudo apt install dnsutils
dig +short nsx.example.com
2. Set Up Server
2.1. Open Firewall
SSH into your server.
We will open the firewall for port 53/udp
and 53/tcp
. The Iodine documentation implies that Iodine only actually uses 53/udp
,
but we will open both. The actual DNS protocol requires 53/tcp
to be available as a backup in case 53/udp
fails.
We also need to open the firewall for SSH input from the virtual network, for which we use IP addresses 10.10.0.0/24
in the examples in this
article.
Firewalls may be implemented with nftables, iptables, ufw, firewalld, or security groups. We will give the example of using nftables with a policy of drop on Debian 10. Here the commands would be:
nft add rule inet filter input udp dport 53 counter accept
nft add rule inet filter input tcp dport 53 counter accept
nft add rule inet filter input tcp dport 22 ip saddr 10.10.0.0/24 counter accept
nft list ruleset > /etc/nftables.conf
If you are not using nftables, then make the equivalent changes for your firewall.
2.2. Obtain Source
Download the source code for Iodine like this:
apt install git -y
git clone https://github.com/yarrick/iodine.git
2.3. Compile and Install
Compile Iodine on your server like this:
apt install build-essential pkg-config zlib1g-dev man-db -y
cd iodine
make
make install
After the install, the two binaries are installed to /usr/local/sbin/
:
iodine
for the clientiodined
for the server
You can view documentation for Iodine by issuing the command:
man iodine
2.4. Generate Password
The maximum password length for Iodine is 32 characters. Generate a strong password of length 32 like with this command:
openssl rand -base64 24
The 24 byte length is equivalent to 32 base-64 characters. You will obtain a result that looks like this:
VjhNxS2kuNO5P3QpqOpsHQSJ8Kh/zq6S
2.5. Create Systemd Service File
We will make Iodine run as a service. Create the systemd service file for iodined
:
vi /usr/lib/systemd/system/iodined.service
Insert contents to run the Iodine server binary like this:
[Unit]
Description=Iodine Server
After=network.target
[Service]
Type=simple
ExecStart=/usr/local/sbin/iodined -f -c -P VjhNxS2kuNO5P3QpqOpsHQSJ8Kh/zq6S 10.10.0.1 x.example.com
Restart=on-failure
[Install]
WantedBy=multi-user.target
- Replace
VjhNxS2kuNO5P3QpqOpsHQSJ8Kh/zq6S
by your actual password - Replace
10.10.0.1
by a different private address if you are using this range for something else - Replace
x.example.com
by your actual subdomain name
Save the file.
2.6. Start Iodine
Enable and start the Iodine service, so that it starts after every reboot:
systemctl enable iodined
systemctl start iodined
2.7. Carry Out Initial Checks
Check that the service is active (running) like this:
systemctl status iodined
Check that the dns0
virtual interface exists like this:
ip a
Check that Iodine is listening on port 53 like this:
ss -tulpn | grep 53
3. Set Up Client
3.1. Obtain Source
Download the source for Iodine like this:
sudo apt install git -y
git clone https://github.com/yarrick/iodine.git
3.2. Compile and Install
Compile Iodine on your client like this:
sudo apt install build-essential pkg-config zlib1g-dev man-db -y
cd iodine
make
sudo make install
3.3. Run
Check that the Iodine binaries are in your path:
echo $PATH
The results should include /usr/local/sbin
.
Install ifconfig:
sudo apt install net-tools -y
Run the Iodine client from the command line like this:
sudo iodine -P VjhNxS2kuNO5P3QpqOpsHQSJ8Kh/zq6S x.example.com
- Replace
VjhNxS2kuNO5P3QpqOpsHQSJ8Kh/zq6S
by your actual password - Replace
x.example.com
by your actual subdomain name
You will see output like this:
Opened dns0
Opened IPv4 UDP socket
Sending DNS queries for x.example.com to 192.168.1.254
Autodetecting DNS query type (use -T to override).
Using DNS type NULL queries
Version ok, both using protocol v 0x00000502. You are user #0
Setting IP of dns0 to 10.10.0.2
Setting MTU of dns0 to 1130
Server tunnel IP is 10.10.0.1
Requesting server address to attempt raw UDP mode (skip with -r)
Server is at xx.xx.xx.xx, trying raw login: (skip with -r) ....failed
Using EDNS0 extension
Switching upstream to codec Base128
Server switched upstream to codec Base128
No alternative downstream codec available, using default (Raw)
Switching to lazy mode for low-latency
Server switched to lazy mode
Autoprobing max downstream fragment size... (skip with -m fragsize)
768 ok.. 1152 ok.. ...1344 not ok.. ...1248 not ok.. ...1200 not ok.. 1176 ok.. 1188 ok.. will use 1188-2=1186
Setting downstream fragment size to max 1186...
Connection setup complete, transmitting data.
Detaching from terminal...
3.4. Carry Out Initial Checks
Check that the dns0
virtual interface exists like this:
ip a
Check that you can reach your server through the tunnel like this:
ping 10.10.0.1
You will need to replace 10.10.0.1
by whatever IP address you chose for your server, if it was different from 10.10.0.1
.
Stop ping from running by pressing Ctrl+c.
3.5. Set Up SSH Proxy Tunnel
Iodine tunnels traffic over DNS unencrypted. Therefore we will set up an SSH tunnel within the DNS tunnel.
On the command line, SSH into your server through the DNS tunnel, with dynamic forwarding of port 1080 through the SSH tunnel:
ssh -D 1080 root@10.10.0.1
3.6. Proxy Firefox
On your PC, open Firefox. From the hamburger menu, select Preferences > General. Scroll down to Network Settings. Click the Settings button.
- Select Manual proxy configuration
- Enter SOCKS Host
127.0.0.1
- Enter Port
1080
- Select SOCKS v5
- Check the box for Proxy DNS when using SOCKS v5
- Click OK
3.7. Test End to End
Check the end-to-end functionality to confirm that Iodine, SSH, and Firefox are all configured correctly. Visit IP Chicken. You should see the IP address of the server, not your local client.
4. Get Help and Report Issues
- Iodine has a detailed README on GitHub
- There is a mailing list for Iodine users
- For genuine issues, you can post on the GitHub Issues section for Iodine
Updated 2020-09