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
Abschnitt betitelt „Installation“Linux (Debian/Ubuntu)
Abschnitt betitelt „Linux (Debian/Ubuntu)“sudo apt update
sudo apt install iodine
brew install iodine
Compile from Source
Abschnitt betitelt „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
Abschnitt betitelt „Infrastructure Setup“Domain Requirements
Abschnitt betitelt „Domain Requirements“- Delegated subdomain: Use a domain you control (e.g.,
tunnel.example.com) - DNS nameserver: The delegated domain must point to your iodined server
DNS Configuration
Abschnitt betitelt „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
Abschnitt betitelt „Server Setup“Basic iodined Server
Abschnitt betitelt „Basic iodined Server“Start the DNS tunneling server:
sudo iodined -f -c -P "SecurePassword123" 10.0.0.1 tunnel.example.com
Server Options Reference
Abschnitt betitelt „Server Options Reference“| Option | Description |
|---|---|
-f | Run in foreground (don’t daemonize) |
-c | Disable IP check of incoming packets (enables NAT clients) |
-P password | Set tunnel authentication password |
-n auto|IP | Listen address (auto or specific IP, default: 0.0.0.0) |
-l 0.0.0.0 | Explicitly bind to all interfaces |
-p 53 | Listen port (default 53, requires root) |
-u username | Drop privileges to user after bind |
-t /var/empty | Chroot to directory |
-d device | Use specific TUN device |
-m mtu | Set tunnel MTU (default 1024) |
-M | Use lazy mode for faster transfers |
-w downstream | Fragment size downstream (default 3333) |
Production Setup
Abschnitt betitelt „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
Abschnitt betitelt „Client Setup“Basic Connection
Abschnitt betitelt „Basic Connection“sudo iodine -f -P "SecurePassword123" tunnel.example.com
Client Options Reference
Abschnitt betitelt „Client Options Reference“| Option | Description |
|---|---|
-f | Run in foreground |
-P password | Authentication password (must match server) |
-r | Force specific DNS resolver IP |
-R | Bind to specific DNS port on client |
-T record_type | DNS record type: NULL (default), TXT, SRV, MX, CNAME, A |
-m mtu | Set tunnel MTU (should match server) |
-M | Enable lazy mode (faster transfers) |
-I interval | Ping interval in seconds (default 4) |
-L lazy_mode | Set lazy mode strength (0-3) |
-O encoding | Set encoding: base32 (default), base64, base128, raw |
-W window_size | Set window size for flow control |
Force Custom DNS Resolver
Abschnitt betitelt „Force Custom DNS Resolver“sudo iodine -f -r 8.8.8.8 -P "password" tunnel.example.com
Specify Record Type
Abschnitt betitelt „Specify Record Type“sudo iodine -f -T TXT -P "password" tunnel.example.com
DNS Record Types
Abschnitt betitelt „DNS Record Types“Bandwidth Comparison
Abschnitt betitelt „Bandwidth Comparison“| Type | Bandwidth | Notes |
|---|---|---|
| NULL | 200-300 KB/s | Best (most nameservers allow) |
| TXT | 150-200 KB/s | Good fallback when NULL blocked |
| A | 50-80 KB/s | Limited, some networks block |
| CNAME | 50-80 KB/s | Can trigger warnings, avoid |
| MX | 100-150 KB/s | Reasonable fallback |
| SRV | 100-150 KB/s | Possible but uncommon |
Selection Strategy
Abschnitt betitelt „Selection Strategy“- Try NULL first (fastest, widely supported)
- Fall back to TXT if NULL blocked
- 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
Abschnitt betitelt „Tunnel Interface“Interface Configuration
Abschnitt betitelt „Interface Configuration“Once connected, you’ll see:
ifconfig dns0
# Shows: 10.0.0.x/255.255.255.0 (tun interface)
Verify Connectivity
Abschnitt betitelt „Verify Connectivity“# Test tunnel is up
ping 10.0.0.1
# Test external connectivity
traceroute 8.8.8.8
Routing Through Tunnel
Abschnitt betitelt „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
Abschnitt betitelt „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
Abschnitt betitelt „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
Abschnitt betitelt „Performance Tuning“MTU Optimization
Abschnitt betitelt „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
Abschnitt betitelt „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)
Abschnitt betitelt „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
Abschnitt betitelt „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
Abschnitt betitelt „Captive Portal Bypass“Typical Workflow
Abschnitt betitelt „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
Abschnitt betitelt „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
Abschnitt betitelt „Routing Configuration“Split Tunneling (Selective Routes)
Abschnitt betitelt „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)
Abschnitt betitelt „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
Abschnitt betitelt „View Current Routes“route -n
ip route show
netstat -r
Troubleshooting
Abschnitt betitelt „Troubleshooting“Connection Fails
Abschnitt betitelt „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
Abschnitt betitelt „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
Abschnitt betitelt „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
Abschnitt betitelt „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
Abschnitt betitelt „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
Abschnitt betitelt „Best Practices“Security
Abschnitt betitelt „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
Abschnitt betitelt „Stability“- Start conservative: Begin with default MTU (1024), increase carefully
- Monitor packet loss: Check
pingoutput 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
Abschnitt betitelt „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
Related Tools
Abschnitt betitelt „Related Tools“| Tool | Purpose | Comparison |
|---|---|---|
| dnscat2 | DNS tunneling with C&C capabilities | Full shell over DNS, more features, complex setup |
| dns2tcp | TCP tunneling over DNS | Lighter weight, simpler than iodine, slower |
| Chisel | HTTP/HTTPS reverse proxy tunneling | Modern, SSH-like syntax, easier setup, not DNS-based |
| NSTX | DNS tunneling via SSH | Older, less maintained, similar to iodine |
| DNSExfil | DNS exfiltration only | One-way data extraction, not bidirectional |
When to Use Iodine
Abschnitt betitelt „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
Abschnitt betitelt „When to Use Alternatives“- Full shell needed: Use dnscat2 (more features)
- Modern infrastructure: Use Chisel (simpler, faster)
- Quick lightweight tunnel: Use dns2tcp (minimal overhead)