iodined (8) - Linux Manuals

iodined: tunnel IPv4 over DNS


iodined - tunnel IPv4 over DNS


iodined [-v]

iodined [-h]

iodined [-c] [-s] [-f] [-D] [-u user ] [-t chrootdir ] [-d device ] [-m mtu ] [-l listen_ip ] [-p port ] [-n ( auto | external_ip ) ] [-b dnsport ] [-P password ] [-z context ] [-F pidfile ] [-i max_idle_time ] tunnel_ip [ /netmask ] topdomain


iodined lets you tunnel IPv4 data through a DNS server. This can be useful in situations where Internet access is firewalled, but DNS queries are allowed. It needs a TUN/TAP device to operate. The bandwidth is asymmetrical, with a measured maximum of 680 kbit/s upstream and 2.3 Mbit/s downstream in a wired LAN test network. Realistic sustained throughput on a Wifi network using a carrier-grade DNS cache has been measured at some 50 kbit/s upstream and over 200 kbit/s downstream. iodine is the client application, iodined is the server.

Note: server and client are required to speak the exact same protocol. In most cases, this means running the same iodine[d] version. Unfortunately, implementing backward and forward protocol compatibility is usually not feasible.


Common Options:

Print version info and exit.
Print usage info and exit.
Keep running in foreground.
-u user
Drop privileges and run as user 'user' after setting up tunnel.
-t chrootdir
Chroot to 'chrootdir' after setting up tunnel.
-d device
Use the TUN device 'device' instead of the normal one, which is dnsX on Linux and otherwise tunX.
-P password
Use 'password' to authenticate. If not used, stdin will be used as input. Only the first 32 characters will be used.
-z context
Apply SELinux 'context' after initialization.
-F pidfile
Create 'pidfile' and write process id in it.

Server Options:

Disable checking the client IP address on all incoming requests. By default, requests originating from non-matching IP addresses will be rejected, however this will cause problems when requests are routed via a cluster of DNS servers.
Don't try to configure IP address or MTU. This should only be used if you have already configured the device that will be used.
Increase debug level. Level 1 prints info about each RX/TX packet. Implies the -f option. On level 2 (-DD) or higher, DNS queries will be printed literally. When using Base128 upstream encoding, this is best viewed as ISO Latin-1 text instead of (illegal) UTF-8. This is easily done with : "LC_ALL=C luit iodined -DD ..." (see luit(1)).
-m mtu
Set 'mtu' as mtu size for the tun device. This will be sent to the client on login, and the client will use the same mtu for its tun device. Default 1130. Note that the DNS traffic will be automatically fragmented when needed.
-l listen_ip
Make the server listen only on 'listen_ip' for incoming requests. By default, incoming requests are accepted from all interfaces.
-p port
Make the server listen on 'port' instead of 53 for traffic. If 'listen_ip' does not include localhost, this 'port' can be the same as 'dnsport'. Note: You must make sure the dns requests are forwarded to this port yourself.
-n auto|external_ip
The IP address to return in NS responses. Default is to return the address used as destination in the query. If external_ip is 'auto', iodined will use web service to retrieve the external IP of the host and use that for NS responses.
-b dnsport
If this port is specified, all incoming requests not inside the tunnel domain will be forwarded to this port on localhost, to be handled by a real dns. If 'listen_ip' does not include localhost, this 'dnsport' can be the same as 'port'. Note: The forwarding is not fully transparent, and not advised for use in production environments.
-i max_idle_time
Make the server stop itself after max_idle_time seconds if no traffic have been received. This should be combined with systemd or upstart on demand activation for being effective.

Client Arguments:

The nameserver to use to relay the dns traffic. This can be any relaying nameserver or the server running iodined if reachable. This field can be given as an IPv4/IPv6 address or as a hostname. This argument is optional, and if not specified a nameserver will be read from the /etc/resolv.conf file.
The dns traffic will be sent as queries for subdomains under 'topdomain'. This is normally a subdomain to a domain you own. Use a short domain name to get better throughput. If nameserver is the iodined server, then the topdomain can be chosen freely. This argument must be the same on both the client and the server.

Server Arguments:

This is the server's ip address on the tun interface. The client will be given the next ip number in the range. It is recommended to use the or ranges. The default netmask is /27, can be overridden by specifying it here. Using a smaller network will limit the number of concurrent users.
The dns traffic is expected to arrive as queries for subdomains under 'topdomain'. This is normally a subdomain to a domain you own. Use a short domain name to get better throughput. This argument must be the same on both the client and the server. Queries for domains other than 'topdomain' will be forwarded when the -b option is given, otherwise they will be dropped.


See the README file for both a quick test scenario, and a detailed description of real-world deployment.


Login is a relatively secure challenge-response MD5 hash, with the password never passing the wire. However, all other data is NOT encrypted in any way. The DNS traffic is also vulnerable to replay, injection and man-in-the-middle attacks, especially when iodined is used with the -c option. Use of ssh or vpn tunneling is strongly recommended. On both server and client, use iptables, pf or other firewalls to block all traffic coming in from the tun interfaces, except to the used ssh or vpn ports.



If the environment variable IODINED_PASS is set, iodined will use the value it is set to as password instead of asking for one. The -P option still has precedence.


File bugs at


Erik Ekman <yarrick [at]> and Bjorn Andersson <flex [at]>. Major contributions by Anne Bezemer.


The README file in the source distribution contains some more elaborate information.