تخطَّ إلى المحتوى

Iodine

Iodine is a DNS tunneling tool that encapsulates IP traffic within DNS queries and responses, allowing you to tunnel network traffic through restrictive firewalls and captive portals that only permit DNS traffic. It establishes a PPP tunnel interface (dns0) over DNS, enabling full network access when direct connections are blocked.

Installation

Linux (Debian/Ubuntu)

sudo apt update
sudo apt install iodine

macOS

brew install iodine

Compile from Source

git clone https://github.com/yarrick/iodine.git
cd iodine
make
sudo make install

Verify installation:

iodine --version
iodined --version

Infrastructure Setup

Domain Requirements

  1. Delegated subdomain: Use a domain you control (e.g., tunnel.example.com)
  2. DNS nameserver: The delegated domain must point to your iodined server

DNS Configuration

Create NS record delegation at your domain registrar:

tunnel.example.com NS ns1.tunnel.example.com
ns1.tunnel.example.com A <your-server-ip>

This routes all DNS queries for *.tunnel.example.com to your iodined server listening on port 53.

Verification:

nslookup test.tunnel.example.com
# Should resolve to your server IP

Server Setup

Basic iodined Server

Start the DNS tunneling server:

sudo iodined -f -c -P "SecurePassword123" 10.0.0.1 tunnel.example.com

Server Options Reference

OptionDescription
-fRun in foreground (don’t daemonize)
-cDisable IP check of incoming packets (enables NAT clients)
-P passwordSet tunnel authentication password
-n auto|IPListen address (auto or specific IP, default: 0.0.0.0)
-l 0.0.0.0Explicitly bind to all interfaces
-p 53Listen port (default 53, requires root)
-u usernameDrop privileges to user after bind
-t /var/emptyChroot to directory
-d deviceUse specific TUN device
-m mtuSet tunnel MTU (default 1024)
-MUse lazy mode for faster transfers
-w downstreamFragment size downstream (default 3333)

Production Setup

sudo iodined -u iodine -t /var/empty \
  -c -P "ComplexPassword!" \
  -n auto \
  -m 1024 \
  10.0.0.1 tunnel.example.com

Verify server is running:

sudo netstat -tulnp | grep 53
ps aux | grep iodined

Client Setup

Basic Connection

sudo iodine -f -P "SecurePassword123" tunnel.example.com

Client Options Reference

OptionDescription
-fRun in foreground
-P passwordAuthentication password (must match server)
-rForce specific DNS resolver IP
-RBind to specific DNS port on client
-T record_typeDNS record type: NULL (default), TXT, SRV, MX, CNAME, A
-m mtuSet tunnel MTU (should match server)
-MEnable lazy mode (faster transfers)
-I intervalPing interval in seconds (default 4)
-L lazy_modeSet lazy mode strength (0-3)
-O encodingSet encoding: base32 (default), base64, base128, raw
-W window_sizeSet window size for flow control

Force Custom DNS Resolver

sudo iodine -f -r 8.8.8.8 -P "password" tunnel.example.com

Specify Record Type

sudo iodine -f -T TXT -P "password" tunnel.example.com

DNS Record Types

Bandwidth Comparison

TypeBandwidthNotes
NULL200-300 KB/sBest (most nameservers allow)
TXT150-200 KB/sGood fallback when NULL blocked
A50-80 KB/sLimited, some networks block
CNAME50-80 KB/sCan trigger warnings, avoid
MX100-150 KB/sReasonable fallback
SRV100-150 KB/sPossible but uncommon

Selection Strategy

  1. Try NULL first (fastest, widely supported)
  2. Fall back to TXT if NULL blocked
  3. Use A records as last resort (slowest)
# Try NULL (default)
sudo iodine -f tunnel.example.com

# Fall back to TXT
sudo iodine -f -T TXT tunnel.example.com

# Try A record
sudo iodine -f -T A tunnel.example.com

Tunnel Interface

Interface Configuration

Once connected, you’ll see:

ifconfig dns0
# Shows: 10.0.0.x/255.255.255.0 (tun interface)

Verify Connectivity

# Test tunnel is up
ping 10.0.0.1

# Test external connectivity
traceroute 8.8.8.8

Routing Through Tunnel

Configure which traffic flows through the tunnel:

# Route all traffic through tunnel
sudo route add default gw 10.0.0.1

# Route specific subnet
sudo route add 192.168.1.0/24 gw 10.0.0.1

# Route to specific host
sudo route add 10.20.30.40 gw 10.0.0.1

SOCKS Proxy Over Tunnel

Create a SOCKS proxy via SSH tunneling:

# Terminal 1: Establish iodine tunnel
sudo iodine -f -P "password" tunnel.example.com

# Terminal 2: SSH SOCKS proxy (once tunnel is up)
ssh -D 1080 user@10.0.0.1

# Terminal 3: Use SOCKS proxy
curl --socks5 127.0.0.1:1080 https://example.com

DNS Configuration on Tunnel

Set DNS for tunnel traffic:

# Temporary (single session)
echo "nameserver 10.0.0.1" | sudo tee -a /etc/resolv.conf

# Or use client option
sudo iodine -f -P "password" tunnel.example.com
# DNS automatically configured

Performance Tuning

MTU Optimization

Start conservative, then increase:

# Server (smaller MTU = more reliable)
sudo iodined -m 1024 10.0.0.1 tunnel.example.com

# Client (must match or be smaller than server)
sudo iodine -m 1024 tunnel.example.com

# Increase for faster speeds (if stable)
sudo iodined -m 2048 10.0.0.1 tunnel.example.com
sudo iodine -m 2048 tunnel.example.com

Fragment Size Control

# Server: reduce downstream fragment size for stability
sudo iodined -w 2000 10.0.0.1 tunnel.example.com

Lazy Mode (Faster Transfers)

Reduces ping overhead, increases speed:

# Server
sudo iodined -M 10.0.0.1 tunnel.example.com

# Client
sudo iodine -M tunnel.example.com

Encoding Selection

Choose encoding to optimize for network conditions:

# base32 (default, most compatible)
sudo iodine -O base32 tunnel.example.com

# base64 (faster, may be filtered)
sudo iodine -O base64 tunnel.example.com

# base128 (fastest, least compatible)
sudo iodine -O base128 tunnel.example.com

Captive Portal Bypass

Typical Workflow

# 1. Connect to WiFi (will show captive portal)
# Don't authenticate if you want pure DNS tunnel

# 2. Start iodine tunnel
sudo iodine -f -P "password" tunnel.example.com

# 3. Once connected, traffic routes through DNS tunnel
# You have full network access regardless of captive portal

# 4. Verify connectivity
ping 8.8.8.8
curl https://example.com

Handling Aggressive Filtering

Some networks block DNS on non-standard ports or filter record types:

# Try different DNS resolvers
sudo iodine -r 1.1.1.1 tunnel.example.com
sudo iodine -r 8.8.8.8 tunnel.example.com

# Try different record types
sudo iodine -T TXT tunnel.example.com
sudo iodine -T A tunnel.example.com

# Combine strategies
sudo iodine -r 1.1.1.1 -T TXT tunnel.example.com

Routing Configuration

Split Tunneling (Selective Routes)

Route only specific traffic through tunnel:

# Assume tunnel is up: 10.0.0.1

# Route corporate network through tunnel
sudo route add 10.20.0.0/16 gw 10.0.0.1

# Route specific server
sudo route add 10.30.40.50 gw 10.0.0.1

# All other traffic uses normal route (local ISP)

Full Tunnel (All Traffic)

Route all traffic through tunnel (careful with latency):

# Save default route first
ip route show > /tmp/routes.bak

# Replace default route
sudo route del default
sudo route add default gw 10.0.0.1

# Restore later
sudo route del default
cat /tmp/routes.bak | while read line; do sudo route add $line; done

View Current Routes

route -n
ip route show
netstat -r

Troubleshooting

Connection Fails

# 1. Verify DNS resolution
nslookup test.tunnel.example.com
dig @ns1.example.com test.tunnel.example.com

# 2. Check server is listening
sudo netstat -tulnp | grep 53
sudo ss -tulnp | grep 53

# 3. Check firewall
sudo iptables -L -n | grep 53
sudo firewall-cmd --list-all

# 4. Enable firewall port
sudo ufw allow 53/udp
sudo firewall-cmd --permanent --add-port=53/udp

Slow Tunnel

# 1. Test with lazy mode
sudo iodine -M -f tunnel.example.com

# 2. Increase MTU
sudo iodine -m 2048 tunnel.example.com

# 3. Try different encoding
sudo iodine -O base64 tunnel.example.com

# 4. Check latency
ping -c 5 10.0.0.1

Password Authentication Issues

# Verify server password
sudo ps aux | grep iodined
# Look for -P flag

# Ensure exact match on client
sudo iodine -P "ExactSamePassword" tunnel.example.com

# Check for special characters
# Use quotes to preserve spaces/special chars

TUN/TAP Device Errors

# Check device exists
ls -la /dev/net/tun

# Create if missing
sudo mkdir -p /dev/net
sudo mknod /dev/net/tun c 10 200
sudo chmod 600 /dev/net/tun

No DNS Resolution in Tunnel

# Manually set DNS
echo "nameserver 10.0.0.1" | sudo tee /etc/resolv.conf

# Or use resolvconf
echo "nameserver 10.0.0.1" | sudo resolvconf -a tun0

# Verify
cat /etc/resolv.conf

Best Practices

Security

  • Use strong passwords: At least 16 characters, mix of complexity
  • Restrict server access: Firewall port 53 to authorized IPs only
  • Run as unprivileged user: Use -u iodine -t /var/empty
  • Use HTTPS tunneling: Encrypt data within the tunnel
  • Rotate credentials: Change password regularly in production

Stability

  • Start conservative: Begin with default MTU (1024), increase carefully
  • Monitor packet loss: Check ping output for drops
  • Use lazy mode judiciously: Faster but less reliable on poor connections
  • Match MTU on client and server: Prevents fragmentation
  • Test in staging: Verify before production deployment

Operational

  • Monitor DNS logs: Track tunnel usage at the DNS level
  • Set up alerts: Monitor connection drops and errors
  • Document configuration: Keep record of MTU, encoding, record type settings
  • Have fallbacks: Prepare alternative tunneling methods (dnscat2, dns2tcp)
  • Test regularly: Verify tunnel works from different networks
ToolPurposeComparison
dnscat2DNS tunneling with C&C capabilitiesFull shell over DNS, more features, complex setup
dns2tcpTCP tunneling over DNSLighter weight, simpler than iodine, slower
ChiselHTTP/HTTPS reverse proxy tunnelingModern, SSH-like syntax, easier setup, not DNS-based
NSTXDNS tunneling via SSHOlder, less maintained, similar to iodine
DNSExfilDNS exfiltration onlyOne-way data extraction, not bidirectional

When to Use Iodine

  • Firewall bypass: When only DNS port 53 is open
  • Captive portal evasion: Hotel/airport WiFi restrictions
  • Low-bandwidth pivoting: Need minimal bandwidth for command execution
  • Reliable covert channel: More stable than ICMP or other methods

When to Use Alternatives

  • Full shell needed: Use dnscat2 (more features)
  • Modern infrastructure: Use Chisel (simpler, faster)
  • Quick lightweight tunnel: Use dns2tcp (minimal overhead)