
What is DNS tunneling and how do attackers use it?
DNS tunneling is a technique that hides other data inside DNS queries and responses. Instead of using DNS only to look up names, a program encodes information into the subdomain part of a query, sends it to a domain controlled by whoever runs the tunnel, and receives data back inside the DNS answer. Because almost every network allows DNS traffic out so that devices can resolve names, attackers use tunneling to sneak data past firewalls, to control malware on infected machines, and to steal information without opening an obvious outbound connection.
DNS tunneling isn't a flaw in any particular DNS server. It's an abuse of the fact that DNS is trusted, rarely inspected and allowed almost everywhere. In this article you'll learn how a DNS tunnel works at a high level, why attackers choose it, what legitimate services look similar, and, most importantly, how to detect it in your logs and stop it with resolver and firewall controls.
Why DNS Is Attractive to Attackers
Most networks lock down outbound traffic in some way. A firewall might only allow web traffic through a proxy, or block unknown ports altogether. DNS, however, almost always gets through, because if it doesn't, nothing works.
Several properties make DNS a convenient hiding place:
- It's allowed everywhere. Even tightly controlled networks, guest Wi-Fi and captive portals usually let DNS queries reach a resolver.
- It's relayed for you. A device doesn't need to talk to the attacker's server directly. It asks the internal resolver, and the resolver forwards the query across the internet to the authoritative nameserver for the attacker's domain.
- It's rarely inspected. Many organisations log web traffic in detail but don't look at DNS queries at all.
- It blends in. A busy network makes millions of lookups a day, so a few thousand extra queries are easy to miss without the right analysis.
How DNS Tunneling Works
A DNS tunnel has two ends: a piece of software on the inside of the network, and an authoritative nameserver on the outside that the tunnel operator controls.
- The operator registers a domain, for example
example.org, and delegates a subdomain such ast.example.orgto a nameserver they run. - Software on the inside encodes data into DNS-safe text, usually Base32 or a similar encoding, because DNS labels can only contain a limited set of characters.
- It sends that data as a query. The encoded text becomes the subdomain, so a query looks something like
mfrggzdfmztwq2lk.0012.t.example.org. - The internal resolver forwards the query. It doesn't know or care that the name is unusual. It follows the delegation to the operator's nameserver.
- The operator's nameserver decodes the query and reads the data inside it.
- It replies with data of its own, packed into the answer, often in a TXT, NULL or CNAME record, or encoded into a series of A or AAAA addresses.
- The software on the inside decodes the reply, and the cycle repeats.
Because each DNS name is limited to 253 characters and each label to 63, every query carries only a small amount of data. A tunnel therefore needs many queries to move anything meaningful, and that volume is one of the most useful signals for detection.
Why Caching Doesn't Get in the Way
Resolvers cache answers, which would normally stop repeated queries from leaving the network. Tunnels avoid this by making every query unique, usually with a counter or random value in the name. Each new name is a cache miss, so the resolver has to ask the operator's nameserver every time.
How Attackers Use DNS Tunneling
DNS tunneling shows up in several types of attack.
Command and Control
Malware on a compromised machine needs a way to receive instructions. Polling a DNS name every few minutes and reading commands from the reply is quiet and works even on networks that block direct internet access. Several well-documented threat groups and malware families have used DNS for command and control, and the SolarWinds SUNBURST backdoor famously encoded information about victims into subdomains of its command domain.
Data Exfiltration
An attacker who has access to sensitive data can leak it slowly, a few dozen bytes per query, to a domain they control. It's slow, but it can bypass data loss prevention tools that only watch web uploads and email.
Bypassing Network Restrictions
Some tools use DNS tunneling to get general internet access through captive portals or paywalled Wi-Fi that allow DNS before login. This is less harmful than an attack on your organisation, but it's still a sign that a device on your network is evading your policies.
Legitimate Traffic That Looks Like Tunneling
Not every long or random-looking DNS name is malicious. Some legitimate products use DNS in similar ways, and you'll need to allow them so your detection doesn't drown in false positives:
- Security and antivirus products that look up file hashes or URL reputation by encoding them into DNS queries.
- Email security lookups, such as DNS-based blocklists (DNSBLs), which put reversed IP addresses or hashes in front of a list's domain.
- Content delivery networks and cloud services that generate unique hostnames per customer, session or device.
- Telemetry and analytics tools that use DNS as a lightweight signalling channel.
The difference is usually that legitimate services belong to vendors you recognise, and you can list their domains. Treat a domain you've never heard of, registered recently, receiving thousands of unique high-entropy subdomains from a single machine, very differently from a known vendor domain.
Signs of DNS Tunneling
No single signal proves a tunnel exists, but several together are a strong indicator.
| Signal | Why it matters |
|---|---|
| Many unique subdomains under one domain | Tunnels make every query unique to avoid caching |
| Long query names, often close to the 253-character limit | Each query carries as much data as possible |
| Random-looking labels (high character entropy) | Encoded data doesn't look like human-chosen names |
| A high share of TXT, NULL or other unusual record types | These can carry the most data in a reply |
| Steady, high query volume from one device to one domain | Moving data needs many queries |
| Recently registered or unknown domains | Tunnel operators often use fresh, disposable domains |
| Queries sent directly to external DNS servers | Malware may bypass your resolver to avoid logging |
Measuring Randomness with Entropy
Shannon entropy is a simple way to score how random a string looks. Ordinary hostnames like www or mail have low entropy, while Base32 or Base64 data has high entropy, usually above about 3.5 bits per character for labels of any length. Entropy alone produces false positives on CDN and cloud hostnames, so it works best combined with the other signals.
How to Detect DNS Tunneling
Detection starts with having DNS logs at all. If your devices use an internal resolver, that resolver is the best place to record every query.
Step 1: Log Queries on Your Resolver
In Unbound, enable query logging in unbound.conf:
server:
log-queries: yes
use-syslog: no
logfile: "/var/log/unbound/unbound.log"
Reload Unbound and you'll see a line for each query:
[1728550000] unbound[812:0] info: 10.0.0.23 mfrggzdfmztwq2lk.0012.t.example.org. TXT IN
On a busy network, query logging generates a lot of data. Ship it to your log platform rather than keeping it on the resolver, and use dnstap if your resolver supports it, as it's more efficient than text logging.
BIND, Windows DNS Server and most commercial DNS security products have equivalent query logging options. Zeek's dns.log is another good source if you capture network traffic.
Step 2: Convert the Log to a Simple Format
The following awk command pulls the client address, query name and record type out of Unbound's log lines:
awk '/ info: [0-9a-f.:]+ / {print $(NF-3), $(NF-2), $(NF-1)}' /var/log/unbound/unbound.log > queries.log
Each line of queries.log now looks like this:
10.0.0.23 mfrggzdfmztwq2lk.0012.t.example.org. TXT
10.0.0.9 www.example.com. A
Step 3: Score Each Domain
This Python script groups queries by domain and flags any domain that matches at least two of the signals described earlier. It uses only the standard library:
#!/usr/bin/env python3
"""Flag domains in a DNS query log that look like DNS tunneling.
Input: a text file with one query per line: "<client_ip> <qname> <qtype>"
"""
import math
import sys
from collections import Counter, defaultdict
def entropy(text):
if not text:
return 0.0
counts = Counter(text)
total = len(text)
return -sum((n / total) * math.log2(n / total) for n in counts.values())
def base_domain(qname):
# Simple heuristic: the last two labels. Use the tldextract package
# in production so names like example.co.uk are handled correctly.
labels = qname.rstrip(".").lower().split(".")
return ".".join(labels[-2:])
def main(path):
stats = defaultdict(lambda: {"queries": 0, "subdomains": set(),
"qtypes": Counter(), "clients": set(),
"max_len": 0, "entropy_sum": 0.0})
with open(path) as log:
for line in log:
parts = line.split()
if len(parts) != 3:
continue
client, qname, qtype = parts
domain = base_domain(qname)
sub = qname.rstrip(".").lower()[: -len(domain)].rstrip(".")
s = stats[domain]
s["queries"] += 1
s["subdomains"].add(sub)
s["qtypes"][qtype.upper()] += 1
s["clients"].add(client)
s["max_len"] = max(s["max_len"], len(qname))
s["entropy_sum"] += entropy(sub.replace(".", ""))
print(f"{'domain':<24}{'queries':>8}{'unique':>8}{'maxlen':>8}"
f"{'entropy':>9}{'txt%':>6} reasons")
for domain, s in sorted(stats.items(), key=lambda kv: -len(kv[1]["subdomains"])):
unique = len(s["subdomains"])
avg_entropy = s["entropy_sum"] / s["queries"]
txt_share = (s["qtypes"]["TXT"] + s["qtypes"]["NULL"]) / s["queries"]
reasons = []
if unique >= 50:
reasons.append("many unique subdomains")
if s["max_len"] >= 100:
reasons.append("very long names")
if avg_entropy >= 3.5:
reasons.append("random-looking labels")
if txt_share >= 0.5:
reasons.append("mostly TXT/NULL")
if len(reasons) >= 2:
print(f"{domain:<24}{s['queries']:>8}{unique:>8}{s['max_len']:>8}"
f"{avg_entropy:>9.2f}{txt_share * 100:>5.0f}% {', '.join(reasons)}")
if __name__ == "__main__":
main(sys.argv[1])
Run it against your log:
python3 dns_tunnel_report.py queries.log
On a sample log containing normal web and mail lookups, 80 CDN-style hostnames and one simulated tunnel, only the tunnel domain is flagged:
domain queries unique maxlen entropy txt% reasons
example.org 200 200 76 4.64 100% many unique subdomains, random-looking labels, mostly TXT/NULL
The CDN-style domain with 81 unique hostnames isn't flagged, because it only matches one signal. That's the point of requiring more than one: a single threshold on its own produces too many false positives.
Treat the thresholds as a starting point. Run the script against a week of normal traffic, add known vendor domains to an allow list, and tune the numbers until the output is short enough to review. For continuous monitoring, the same logic can be built as a scheduled search in your SIEM.
Step 4: Investigate What You Find
When a domain is flagged:
- Identify the client. Find which device sent the queries and who uses it.
- Look up the domain. Check its registration date, its nameservers and whether threat intelligence feeds know it.
- Check the timing. Regular queries at fixed intervals suggest automated command and control, while bursts suggest data transfer.
- Inspect the device. Look for unknown processes, scheduled tasks or recently installed software, and follow your incident response process if it's compromised.
How to Prevent DNS Tunneling
Detection tells you a tunnel exists. Prevention makes tunnels harder to set up in the first place.
Force All DNS Through Your Own Resolvers
If devices can send DNS queries straight to any server on the internet, they can avoid your logging and filtering completely. Allow outbound DNS only from your resolvers, and block it from everything else. This nftables example allows DNS from the resolver at 10.0.0.53 and drops it from all other internal hosts:
table inet egress_dns {
chain forward {
type filter hook forward priority 0; policy accept;
ip saddr 10.0.0.53 udp dport 53 accept
ip saddr 10.0.0.53 tcp dport 53 accept
udp dport 53 drop
tcp dport { 53, 853 } drop
}
}
Port 853 is DNS over TLS. DNS over HTTPS runs on port 443 and can't be blocked by port, so you'll need to block known public DoH endpoints at your proxy or firewall, use browser and operating system policies to turn off built-in DoH, or point devices at your own DoH-capable resolver.
Block Known Bad Domains with RPZ
A Response Policy Zone (RPZ) lets your resolver refuse to resolve specific domains. When you find a tunnel domain, block it and all its subdomains. In BIND, add the policy zone to named.conf:
options {
response-policy { zone "rpz.local"; };
};
zone "rpz.local" {
type primary;
file "/etc/bind/db.rpz.local";
allow-query { none; };
};
Then list the domains to block in /etc/bind/db.rpz.local:
$TTL 300
@ IN SOA localhost. hostmaster.localhost. ( 1 3600 600 86400 300 )
IN NS localhost.
t.example.org CNAME .
*.t.example.org CNAME .
A CNAME . entry tells the resolver to answer NXDOMAIN. Check and reload the configuration:
sudo named-checkconf
sudo named-checkzone rpz.local /etc/bind/db.rpz.local
sudo rndc reload
Commercial threat intelligence feeds publish RPZ data, so you can block known malicious domains automatically rather than one at a time.
Use a DNS Security Service
Protective DNS services and DNS firewalls analyse queries as they happen and block domains that show tunneling patterns, newly registered domains, and domains linked to known malware. If you don't have the time to build and tune your own detection, pointing your resolvers at one of these services, or forwarding to one, is a practical option.
Reduce What a Tunnel Can Do
- Limit which devices can resolve external names at all. Servers that only talk to internal systems often don't need internet DNS.
- Rate limit queries per client on your resolver, so a single machine can't send thousands of unique queries a minute unnoticed.
- Alert on unusual record types such as NULL, which ordinary clients rarely request.
- Keep endpoints protected with up-to-date software and endpoint detection tools, since a tunnel needs software running on the inside to work.
FAQ: DNS Tunneling
The technique itself isn't illegal, and it's sometimes used in authorised security testing. Using it to steal data, control malware or bypass the security of a network you aren't authorised to use is illegal in most countries.
No. DNSSEC proves that DNS answers are genuine, and a tunnel operator can sign their own zone just like anyone else. DNSSEC protects against forged answers, not against someone misusing a domain they control.
It can. If a device sends encrypted DNS directly to a public resolver, your network can't see the queries. That's why you should force devices to use your own resolvers and block or control access to public DoH services.
Slowly compared with a normal connection, because each query carries only a small amount of data. That's enough for command and control or for leaking documents and credentials over hours or days, but the volume of queries it creates is what makes it detectable.
A firewall that only checks ports can't, because tunnel traffic is ordinary DNS on port 53 sent through your own resolver. You need DNS-aware controls such as query logging, RPZ blocking or a DNS security service that inspects query names and patterns.
Block the domain on your resolvers, isolate the device that was sending the queries, and follow your incident response process. Assume that whatever data the device could access may have been exposed until you've confirmed otherwise.
Conclusion
DNS tunneling works because DNS is trusted, allowed everywhere and relayed by your own resolvers on the attacker's behalf. By hiding data in query names and answers, malware can receive commands and leak information without opening any connection a traditional firewall would notice.
The defence is to treat DNS as traffic worth watching. Make every device use resolvers you control, log the queries, look for domains with many unique, long, random-looking subdomains and unusual record types, and block what you find with RPZ or a DNS security service. With those controls in place, a DNS tunnel stops being invisible and becomes one of the easier things to spot in your logs.


