← Back to posts
comparison guide self-hosted · · 11 min read

iodine vs dnscat2: Self-Hosted DNS Tunnel Comparison 2026

Compare iodine and dnscat2 — the top self-hosted DNS tunnel tools for remote access, firewall bypass, and covert network communication. Complete setup guides with Docker configs.

OS
Editorial Team

When standard network ports are blocked by restrictive firewalls or corporate proxy policies, DNS queries often remain the one channel left open. DNS tunneling exploits this reality by encoding arbitrary network traffic inside DNS queries and responses. This guide compares the two most established open-source DNS tunnel implementations — iodine and dnscat2 — and helps you choose the right tool for your environment.

Why Self-Host a DNS Tunnel

DNS tunneling serves several legitimate operational purposes for network administrators and infrastructure engineers:

  • Remote server access during outages — When primary VPN or SSH connectivity fails due to network issues, a DNS tunnel provides a reliable fallback channel for emergency administration.
  • Firewall bypass in restrictive environments — Some hosting providers or institutional networks block outbound SSH, HTTPS, or custom ports but allow DNS. A DNS tunnel can bridge the gap when no other option exists.
  • Penetration testing and security auditing — Security teams use DNS tunnels during authorized engagements to test whether an organization’s network perimeter properly inspects and filters DNS traffic.
  • Disaster recovery communication — When all other network infrastructure is compromised, DNS-based communication can serve as an out-of-band channel for coordination and data retrieval.

For related reading on complementary networking tools, see our guides on self-hosted tunnel alternatives to ngrok and WireGuard-based VPN solutions.

How DNS Tunneling Works

DNS tunneling operates by encoding data payloads inside DNS query names and responses. The process works as follows:

  1. Client encodes data — The client splits outgoing data into chunks and encodes them as DNS subdomain labels (e.g., aGVsbG8.dns-tunnel.example.com).
  2. DNS resolver forwards — The local DNS resolver receives the query and forwards it through the standard DNS hierarchy to the authoritative nameserver for dns-tunnel.example.com.
  3. Server decodes and responds — Your authoritative DNS server (running the DNS tunnel software) receives the query, decodes the data, and encodes its response inside the DNS answer record.
  4. Bidirectional channel — This exchange repeats continuously, creating a bidirectional data channel that traverses any network allowing DNS resolution.

Because DNS is UDP-based by default (with TCP fallback for large responses), DNS tunnels can achieve reasonable throughput — typically 100 Kbps to 2 Mbps depending on encoding and network conditions.

Feature Comparison: iodine vs dnscat2

Featureiodinednscat2
Primary purposeGeneral-purpose IPv4 tunnelCommand-and-control channel
LanguageC (client and server)C (client), Ruby (server)
EncryptionOptional password-basedBuilt-in (encrypted by default)
ProtocolCustom UDP-basedCustom with DNS fallback
Max throughput~2 Mbps (raw mode)~500 Kbps (conservative)
TCP tunnelingFull TUN/TAP (all protocols)Limited (shell + file transfer)
Docker supportCommunity imagesCommunity images
GitHub stars7,8213,873
Last updateSeptember 2025March 2024
Multi-clientYes (multiple simultaneous clients)Yes (multiple sessions)
Direct modeNo (requires authoritative DNS)Yes (direct UDP/TCP to server)
Cross-platform clientLinux, macOS, Windows, Android, iOSLinux, macOS, Windows
LicenseISCBSD

iodine: General-Purpose DNS Tunnel

iodine is the most widely known DNS tunnel implementation. Written entirely in C, it creates a full TUN/TAP virtual network interface, allowing you to route all IPv4 traffic through the DNS channel — not just shell sessions.

Key Features

Full network tunneling. iodine creates a virtual network interface on both client and server. Once connected, the client can reach any server-side network resource — web servers, databases, internal APIs — as if directly connected to the remote network.

Adaptive encoding. iodine automatically selects the optimal DNS record type (TXT, NULL, SRV, CNAME, MX) based on what the upstream DNS resolver allows. It dynamically adjusts chunk sizes to maximize throughput within the constraints of each DNS server along the path.

Compression. Built-in zlib compression reduces data volume before encoding, improving effective throughput by 30-50% on compressible traffic.

Lightweight server. The iodine server (iodined) is a single compiled binary with minimal dependencies. It runs on any Linux system and requires no runtime environment.

Installation

From source (server and client):

1
2
3
4
git clone https://github.com/yarrick/iodine.git
cd iodine
make
sudo make install

Ubuntu/Debian:

1
sudo apt install iodine

Alpine Linux:

1
sudo apk add iodine

Docker Deployment

Here is a production-oriented Docker Compose configuration for the iodine server:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
version: "3.8"

services:
  iodine-server:
    image: ghcr.io/toni11/iodine:latest
    container_name: iodine-server
    cap_add:
      - NET_ADMIN
    devices:
      - /dev/net/tun:/dev/net/tun
    ports:
      - "53:53/udp"
      - "53:53/tcp"
    environment:
      - IODINE_PASSWORD=YourStrongPassword123
      - IODINE_DOMAIN=t1.example.com
      - IODINE_SERVER_IP=192.168.99.1
      - IODINE_EXTRA_ARGS=-c -f
    restart: unless-stopped
    networks:
      - tunnel-net

networks:
  tunnel-net:
    driver: bridge

Server Configuration

The most important setup step is configuring your domain’s DNS to delegate a subdomain to your iodine server. If you run BIND:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
$TTL 300
@       IN  SOA ns1.example.com. admin.example.com. (
            2026042401 ; serial
            3600       ; refresh
            900        ; retry
            604800     ; expire
            86400      ; minimum
        )

; NS record pointing to your iodine server
t1      IN  NS  t1ns.example.com.
t1ns    IN  A   203.0.113.50   ; Your server's public IP

Start the server:

1
iodined -f -c -P YourStrongPassword123 192.168.99.1 t1.example.com

The -c flag enables open mode (accepts connections from any client IP), and -f keeps it in the foreground. For production, remove -f and use a process manager.

Client Connection

1
iodine -f -P YourStrongPassword123 t1.example.com

Once connected, the client receives IP 192.168.99.2 and can reach the server at 192.168.99.1. Route additional traffic through the tunnel:

1
2
# Add a route to reach the server's internal network
sudo ip route add 10.0.0.0/8 via 192.168.99.1

Performance Tuning

1
2
3
4
5
6
# Test different MTU sizes for your network
iodine -f -P pass -m 1130 t1.example.com   # conservative
iodine -f -P pass -m 2200 t1.example.com   # aggressive

# Use raw mode for maximum throughput (requires direct UDP)
iodine -f -P pass -r t1.example.com

Typical throughput on a residential connection ranges from 200 Kbps to 1.5 Mbps. Enterprise networks with fast DNS resolvers may achieve up to 2 Mbps.

dnscat2: Command-and-Control DNS Tunnel

dnscat2 takes a different approach. Instead of creating a full network tunnel, it establishes encrypted command channels optimized for interactive shell access and file transfer over DNS.

Key Features

Encrypted by default. Unlike iodine (where encryption is optional), dnscat2 encrypts all traffic between client and server using a pre-shared public key. This prevents passive observers from reading tunneled data even if they can decode the DNS queries.

Multi-session management. The dnscat2 server provides an interactive console where you can manage multiple connected clients, switch between sessions, spawn new shells, and transfer files — all through a single server instance.

Direct mode. dnscat2 can connect directly to the server on UDP port 53 without requiring an authoritative DNS server. This simplifies deployment when you don’t control a domain’s DNS records, though it’s more easily detected since all queries go to a single IP.

Ruby-based server. The server component runs on Ruby with gem dependencies, making it more flexible but also more resource-intensive than iodine’s C binary.

Installation

Server (Ruby required):

1
2
3
4
git clone https://github.com/iagox86/dnscat2.git
cd dnscat2/server
sudo gem install bundler
bundle install

Client (C, cross-compile for target platforms):

1
2
3
cd dnscat2/client
make
# Client binary is in client/dnscat

Ubuntu/Debian (server):

1
2
3
4
5
sudo apt install ruby ruby-dev ruby-bundler
git clone https://github.com/iagox86/dnscat2.git
cd dnscat2/server
sudo gem install bundler
bundle install

Docker Deployment

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
version: "3.8"

services:
  dnscat2-server:
    image: ghcr.io/lukebaggett/dnscat2-server:latest
    container_name: dnscat2-server
    ports:
      - "53:53/udp"
      - "53:53/tcp"
      - "2222:2222/tcp"   # Management console
    environment:
      - DOMAIN=tunnel.example.com
      - DNS_SECRET=YourSecretKey123
    command: >
      ruby ./dnscat2.rb
      tunnel.example.com
      --dns host=0.0.0.0,port=53
      --secret=YourSecretKey123
      --security=open
    restart: unless-stopped

networks:
  default:
    driver: bridge

Server Configuration

DNS delegation is similar to iodine — you need an NS record pointing to your server:

1
2
tunnel  IN  NS  dnsserver.example.com.
dnsserver  IN  A  203.0.113.50

Start the server:

1
2
cd dnscat2/server
ruby dnscat2.rb --dns host=0.0.0.0,port=53 --secret=YourSecretKey123 tunnel.example.com

The --security=open flag allows any client to connect without pre-authentication. For production use, configure specific client IDs.

Client Connection

1
./dnscat --dns server=203.0.113.50 --secret=YourSecretKey123 tunnel.example.com

Or using direct mode (no authoritative DNS required):

1
./dnscat --dns direct=203.0.113.50:53 --secret=YourSecretKey123

Server Console

Once clients connect, you get an interactive management console:

1
2
3
4
5
6
7
8
9
dnscat2> windows
0 :: main [controller]
1 :: cmd.exe (session1) [active]

dnscat2> session -i 1
Session 1 established. Type Ctrl+Z to background.

C:\> whoami
nt authority\system

The console supports creating new shell sessions, uploading/downloading files, and managing multiple connected clients simultaneously.

Performance and Throughput Comparison

Metriciodinednscat2
Peak throughput1.5–2 Mbps300–500 Kbps
Latency (ping through tunnel)50–200 ms100–400 ms
CPU usage (server)Low (~2%)Moderate (~8%)
Memory usage (server)~5 MB~50 MB (Ruby runtime)
Best use caseFull network accessInteractive shell + file transfer
TCP overheadMinimal (raw IP tunnel)Higher (application-layer tunnel)

iodine consistently outperforms dnscat2 in raw throughput because it operates at the network layer (TUN/TAP) with efficient binary encoding. dnscat2 trades throughput for security and interactive features — every byte is encrypted and processed through the Ruby runtime.

Security Considerations

Encryption. dnscat2 encrypts all traffic by default using a Diffie-Hellman key exchange. iodine offers optional password authentication but does not encrypt tunneled data. If confidentiality matters, run iodine inside an SSH tunnel or use dnscat2.

Detection. Both tools generate unusually high volumes of DNS queries with long subdomain labels. Modern DNS security solutions (DNS-layer firewalls, anomaly detection systems) can flag this traffic. For authorized testing, establish baseline patterns and coordinate with network operations.

Access control. Both tools support password/secret-based authentication. dnscat2 additionally supports public-key client authentication. Neither tool provides built-in rate limiting — deploy a DNS firewall in front of the server for production use.

For organizations building comprehensive DNS security infrastructure, combining a DNS tunnel with DNS-over-HTTPS resolvers and DNS filtering tools creates layered defense and controlled access.

Which One Should You Choose?

Choose iodine if:

  • You need full network-layer tunneling (access any IP/service on the remote network)
  • Maximum throughput is important
  • You want a minimal server footprint (single C binary, ~5 MB memory)
  • You’re comfortable managing DNS delegation records
  • You plan to route general traffic (HTTP, database connections, etc.) through the tunnel

Choose dnscat2 if:

  • You primarily need interactive shell access to remote systems
  • Built-in encryption is a requirement
  • You need to manage multiple connected clients from a single console
  • Direct mode (no DNS delegation) is acceptable for your use case
  • File transfer through the tunnel is a regular requirement

For most remote administration scenarios, dnscat2 provides the better operator experience with its encrypted sessions and multi-client console. For full network access where you need to reach internal services beyond just a shell, iodine is the clear choice.

FAQ

DNS tunneling is a networking technique — its legality depends on how you use it. Using DNS tunnels on networks you own or have explicit authorization to access is perfectly legal. Using them to bypass network restrictions on networks you don’t own (corporate networks, school networks, etc.) without permission may violate terms of service or local laws. Always ensure you have proper authorization.

Can DNS tunnels replace a VPN?

DNS tunnels can serve as a fallback when standard VPN connections fail, but they should not replace a VPN for regular use. DNS tunnels have significantly lower throughput (typically 1-2 Mbps maximum vs. 50-500 Mbps for WireGuard/OpenVPN), higher latency, and are more easily detected. Use them as an emergency access channel, not a primary connection.

How do I detect DNS tunneling on my network?

Look for: unusually long DNS query names (50+ characters in subdomains), high query volume from a single client (hundreds of queries per minute), queries for uncommon record types (TXT, NULL, SRV), and consistent query patterns to the same domain. DNS security tools like Pi-hole, Unbound, or dedicated DNS firewalls can monitor and alert on these patterns.

Does dnscat2 work over IPv6?

The dnscat2 client and server support IPv6 DNS queries, but the tunneled data itself is protocol-agnostic. The iodine project has limited IPv6 support through its TUN/TAP interface, but it primarily tunnels IPv4 traffic. For full IPv6 tunneling needs, consider dedicated IPv6-capable VPN solutions.

What DNS record types do these tools use?

iodine automatically selects the best available record type (TXT, NULL, SRV, CNAME, or MX) based on what the upstream DNS resolver permits. dnscat2 primarily uses TXT records for data transport. Both tools fall back to standard A/AAAA record queries when needed, though with reduced throughput.

Can I run iodine or dnscat2 alongside an existing DNS server?

Yes, but you cannot have two processes listening on port 53 simultaneously. Run your existing DNS server (BIND, Unbound, etc.) on a different port and use the DNS tunnel’s built-in forwarding, or configure your DNS server to forward queries for the tunnel subdomain to the tunnel software running on a separate port. The recommended approach is to run the DNS tunnel on port 53 and configure your primary DNS server to listen on a different port (e.g., 5353).

What is the maximum number of concurrent clients?

Both tools support multiple simultaneous client connections. iodine handles each client as a separate tunnel interface with its own IP address within the virtual network. dnscat2 manages multiple clients through its session console. Practical limits depend on server resources and DNS query capacity — expect 10-50 concurrent clients before DNS amplification becomes a concern.

Advertise here
Advertise here