iodine tunnels IPv4 over DNS. The client creates a virtual network interface (on Linux, dns0 by default), sends packets as encoded hostnames and receives replies in a record type negotiated with the server. Unlike a message-oriented DNS C2 channel, iodine aims for throughput, so its record-type mix and query shape stand apart from ordinary resolver traffic.
Signals at a Glance
| Signal | Where | ATT&CK |
|---|---|---|
| iodine or iodined process, or -f -P with a domain argument | auditd, Sysmon for Linux, EDR | T1572 |
| New tun/tap interface such as dns0 on a host with no VPN role | auditd, EDR, interface inventory | T1572 |
| Heavy NULL-type DNS queries and responses | Zeek dns.log, resolver logs | T1071.004 |
| Encoded long hostnames under one operator-controlled zone | DNS logs | T1572 |
| Handshake probes cycling through record types before steady traffic | DNS logs | T1572 |
NULL Records and Query Shape
During setup iodine probes which record types the path will pass, and it then favours the largest: NULL when permitted, then PRIVATE, TXT, SRV, MX and CNAME as fallbacks. A NULL query (type 10) is almost never seen in ordinary traffic, so even a small count from one client is a strong signal. Zeek records the type name directly:
# Zeek - find clients using NULL queries and the zones they target
zeek-cut id.orig_h query qtype_name < dns.log \
| awk '$3=="NULL" {c[$1" "$2]++} END {for (k in c) print c[k], k}' \
| sort -rn | head -50
# Splunk equivalent
index=zeek sourcetype=bro_dns qtype_name IN ("NULL","PRIVATE","TXT")
| stats count AS q, dc(query) AS unique_names BY id.orig_h, qtype_name
| where q > 200
| sort - unique_names
# tune/validate: TXT has many legitimate uses (SPF, verification); NULL and
# PRIVATE are the high-confidence types.
Process and Interface Artifacts
The client needs privilege to create a tun device. That produces interface and process events that are easy to detect on servers and workstations that have no VPN role. The server side, iodined, needs the operator to control an NS delegation, which is an infrastructure signal you can look for in passive DNS:
title: iodine DNS Tunnel Client or Server
logsource:
category: process_creation
product: linux
detection:
selection_img:
Image|endswith:
- '/iodine'
- '/iodined'
selection_cli:
CommandLine|contains|all:
- ' -f '
- ' -P '
condition: selection_img or selection_cli
level: high
# tune/validate: operators rename binaries; add an auditd rule on tun device
# creation (ioctl TUNSETIFF) and an inventory check for unexpected dns0 or tun interfaces.
- Enumerate interfaces across Linux servers and alert on a new
dns0or unexpected tun/tap device. - Compare outbound DNS volume per host with its peers; iodine moves megabytes through the resolver.
- Look in passive DNS for NS delegations that point at a freshly registered domain with an IP-address nameserver.
- Block direct outbound DNS from endpoints and require resolvers with query logging.
Use the iodine project documentation for protocol behaviour, Zeek dns.log, SigmaHQ Linux tunneling-tool rules, Elastic DNS tunneling content and Splunk ESCU DNS analytics. Always baseline your own environment — renamed binaries and alternate record types change the surface, so combine host, interface and wire signals.
Build Detections That Fire
Mjolnir Security helps blue teams turn threat intelligence into high-fidelity detections across endpoint, network, identity and cloud telemetry.
- Detection Engineering We build and tune detections mapped to ATT&CK from your own telemetry.
- Threat Hunting as a Service Hypothesis-driven hunts for the behaviours on this page.
- 24/7 Incident Response Containment when a detection fires. Call +1 833 403 5875.
Stay ahead of emerging threats. Get notified when we publish new intelligence reports and advisories.
Subscribe to Alerts