Library / SDK
yarrick/iodine avatar
yarrick/iodine

iodine: Tunnel IPv4 Traffic Through DNS When Other Ports Are Blocked

Official git repo for iodine dns tunnel

7,988 stars598 forksCISC

At a glance

What is it?
iodine is a C program that encodes IPv4 data inside DNS queries, letting it pass through firewalls that block all TCP and UDP traffic except DNS. It requires a public server running iodined and control over a real DNS subdomain.
Who is it for?
iodine serves one narrow use case: getting data out of a network where only DNS queries are allowed. If any other path is open (TCP 80, TCP 443, UDP to your own server), a more direct tunneling method will be faster and simpler.
Can I use it commercially?
Yes. ISC is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository received new commits within the last day.
What is it written in?
Mainly C, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 29, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The Specific Problem iodine Solves

Most network firewalls block outbound TCP and UDP connections to arbitrary hosts and ports, allowing only traffic to approved services. DNS queries, however, are almost universally permitted: devices need to resolve hostnames to connect to any service, and blocking DNS outright breaks too much for administrators to consider it. iodine exploits this by encoding IPv4 data inside DNS query and response payloads.

The README states the use case plainly: iodine lets you tunnel IPv4 data through a DNS server, which can be useful in situations where internet access is firewalled but DNS queries are allowed. The canonical scenario is a captive portal or corporate network that requires authentication before granting internet access but allows DNS traffic to pass. A user can reach a server they control via DNS queries before authenticating.

This is a narrow and specific use case. iodine is not a general-purpose VPN, and it is not designed for speed or throughput. The overhead of encoding data in DNS packets and the round-trip latency through DNS servers makes it slow compared to direct connections. Its value is in enabling any connectivity at all when no other path exists.

Architecture: iodined Server and iodine Client

iodine consists of two programs. iodined runs on the server side, a machine with a public IP address that you control. iodine runs on the client side, the device inside the firewalled network.

The server opens a virtual network interface (a tun device) and listens for DNS queries on UDP port 53. When a client connects, the server assigns it an IP address inside the tunnel subnet and forwards data between the client and the rest of the network. The client creates its own tun interface with an address in the same subnet.

Data from the client is encoded into DNS query names. The DNS query travels through the network's resolver to the iodined server (because the server's domain is set up to receive queries for that subdomain). iodined decodes the query, processes the data, encodes the response in the DNS answer, and the cycle repeats. The encoding adds significant overhead per packet.

iodine can detect when raw UDP traffic to the server is actually allowed (not just DNS-port traffic), and will switch to raw UDP tunneling automatically for better performance. The -r flag forces DNS tunneling even when raw UDP would work, which is useful for testing.

The README notes that server and client must speak the same protocol, which in practice means running the same iodine version. Protocol compatibility between different versions is not guaranteed.

Building iodine and Testing on a Local Network

iodine has no configure script. Build the server and client binaries from the source root:

code
make

To install binaries and the man page:

code
make install

Unit tests require the check library (libcheck.github.io/check/). With it installed:

code
make test

SELinux and systemd support are optional and enabled automatically if the relevant header files are found in /usr/include.

The README describes a quick test within a LAN before setting up real DNS delegation. On the server machine, start iodined with an unused internal network address and a placeholder domain:

code
./iodined -f 10.0.0.1 test.com

Enter a password when prompted. On the client machine, connect using the server's local IP address:

code
./iodine -f -r 192.168.0.1 test.com

After the client connects, it receives the tunnel IP 10.0.0.2 and the server holds 10.0.0.1. Pinging across the tunnel confirms the setup is working before configuring real DNS.

Setting Up Real DNS Delegation for Production Use

To use iodine outside a local network, you need a real registered domain and the ability to edit its DNS zone. The setup requires delegating a subdomain to your iodined server via an NS record.

For a domain like mydomain.com, add two records to the zone file:

code
t1    IN  NS  t1ns.mydomain.com.    ; note the dot!
t1ns    IN  A  10.15.213.99

The NS record routes all queries for subdomains of t1.mydomain.com to the iodined server. The A record (t1ns) must be a hostname, not an IP address, in the NS line. For a server with a dynamic IP, point the NS record at a dynamic DNS hostname and omit the A record.

After reloading the nameserver, start iodined with the tunnel IP, the delegated subdomain, and a password. The README recommends the -c flag for production, which allows connections from clients using different source IP addresses (relevant for clients behind NAT):

code
./iodined -f -c -P secretpassword 192.168.99.1 t1.mydomain.com

The client connects using just the domain:

code
./iodine -f -P secretpassword t1.mydomain.com

The README also notes that if iodined coexists with another DNS server on the same machine, you can forward the subdomain from your existing DNS server to iodined running on a different port using the -p flag. This forwarding is described as not completely transparent, so the README advises against it in production environments.

Security Limitations and Detection Risk

The README is explicit: tunneled data traffic is not encrypted at all and can be read and changed by external parties relatively easily. An observer who captures the DNS traffic can decode the iodine session and read its contents. For anything sensitive, the README recommends running a VPN through the DNS tunnel (double tunneling) or using SSH with port forwarding.

DNS tunneling is also detectable. Firewalls and network monitoring systems that inspect DNS query patterns can identify iodine traffic: the query names are long, contain encoded data, and appear at a much higher rate than typical hostname lookups. Some captive portals and enterprise firewalls specifically block known DNS tunneling patterns. iodine does not obfuscate its traffic to appear as legitimate DNS.

The README also notes a limitation on the data inside the tunnel: it is IPv4 only. IPv6 traffic cannot be carried through an iodine tunnel, even though the server can listen on IPv6 for incoming connections and the client can use IPv6 nameservers.

Performance is constrained by the DNS round-trip model. Each data transfer requires a DNS query and response cycle, which adds latency on top of the actual network round-trip time. The DNS packet size limits how much data can be encoded per query.

When SSH Tunneling Is the Better Choice

SSH with dynamic port forwarding (ssh -D) creates a SOCKS proxy that routes arbitrary TCP connections through an SSH connection to a remote server. This is a widely used and well-understood approach to bypassing network restrictions. The difference from iodine is the transport: SSH tunneling requires an outbound TCP connection to the SSH server's port (typically port 22, though this can be changed). If TCP port 22 is open outbound, SSH tunneling is faster, simpler to set up, and encrypts traffic by default.

iodine is the relevant tool when TCP port 22, TCP port 80, and TCP port 443 are all blocked, and only DNS traffic is permitted. This situation is less common than firewalls that block only some ports. In enterprise captive portal scenarios, TCP 80 and 443 are often the first ports blocked but DNS is left open, which is iodine's exact target.

For routing all traffic through the DNS tunnel (not just the tunneled subnet), the README documents the approach: add a host route for the nameserver over the wired interface, then replace the default gateway with the iodined server's tunnel IP and configure the server for NAT. This is more complex than the equivalent configuration with a VPN, and still requires layering encryption on top.

Platform Support, License, and Maintenance

The last push to the iodine repository was on 2026-09-20. The repository has no GitHub releases, consistent with its C build model where users compile from source.

The README documents Windows and Android support through separate README files: README-win32.txt and README-android.txt are present in the repository for platform-specific build notes. The primary platforms mentioned in the README are Linux, OpenBSD, FreeBSD, NetBSD, and macOS. The Windows port requires a separate build process documented in the Windows-specific README.

The project is licensed under the ISC license, a permissive two-clause license similar to the BSD 2-clause license. It permits use, modification, and distribution with attribution. There are no restrictions on commercial use.

The repository structure is simple: src/ holds the C source, tests/ holds unit tests, man/ holds the man page, and doc/ holds additional documentation. The build system is a plain Makefile with no external build tool dependency.

Editorial conclusion

iodine serves one narrow use case: getting data out of a network where only DNS queries are allowed. If any other path is open (TCP 80, TCP 443, UDP to your own server), a more direct tunneling method will be faster and simpler. The setup requires a public server, DNS subdomain delegation, and manual NS record configuration. The tool is explicit that the tunnel is unencrypted, so layering SSH or a VPN on top is not optional for anything sensitive. The last push was on 2026-09-20. The ISC license permits unrestricted use.

Frequently asked questions

Does iodine encrypt the data it tunnels?

No. The README states explicitly that tunneled data traffic is not encrypted at all and can be read and changed by external parties. For security, the README recommends running a VPN or SSH connection through the DNS tunnel rather than relying on iodine itself for confidentiality.

What does iodine require on the server side?

iodine requires a server with a public IP address running iodined, and control over a registered domain for DNS delegation. You must create an NS record pointing a subdomain to your server and a corresponding A record, then start iodined with the tunnel subnet IP address and the delegated subdomain.

Does iodine support IPv6 inside the tunnel?

The data inside the tunnel is IPv4 only. The server can listen on both IPv4 and IPv6 for incoming DNS connections, and the client can use IPv6 nameservers, but IPv6 traffic cannot be carried through the iodine tunnel itself.

Official sources

  1. Issues
  2. License: ISC
  3. Project website
  4. README
  5. yarrick/iodine on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/yarrick-iodine.svg)](https://hysenlabs.com/projects/yarrick-iodine)