At 2:47 AM on a Tuesday, my on-call phone lit up with an alert we'd never seen before: one of our authoritative clusters was pushing 470 Gbps outbound. It wasn't a cache fill or a bad purge. Someone had turned our own DNS infrastructure into a weapon, bouncing 60-byte spoofed queries into 3,000-byte responses aimed at a single victim IP. If you run CDN DNS at any real scale, that call isn't a matter of if — it's when.
Why CDN Authoritative Servers Make Perfect Amplifiers
DNS amplification works because UDP doesn't validate source IPs, and DNS was never designed to. An attacker spoofs the victim's IP, sends a tiny query to your server, and you send a huge response to the victim. We call it a reflection attack for a reason — you're the mirror. CDN authoritative servers are particularly attractive because they're globally anycasted, massively over-provisioned, and designed to answer fast for everyone. That’s exactly what an attacker wants.
I learned this the hard way back in 2018 when we were rolling out DNSSEC across a major anycast footprint. We were proud of our 2-3ms global lookup times. Then a botnet found us. They weren't using the old-school ANY query trick — they'd moved to DNSSEC-signed names with large RRSIG records and EDNS0 buffer sizes set to 4096 bytes. A 48-byte query was generating a 3,240-byte answer. That's a 67x amplification factor, and when you've got 50 PoPs all happily responding, you've built a distributed cannon. Our DNS NS Delegation for CDN: Offloading Domain Resolution to Edge Networks architecture meant we had dozens of delegated name servers, which gave attackers more targets and more aggregate bandwidth to abuse.
The math is brutal. Most amplification doesn't come from one clever query, it comes from volume and response size. Query types like ANY, TXT, and DNSKEY with DNSSEC can easily return 10-50x the request size. Add EDNS0 and you can push that past 60x. The attacker doesn't need to compromise your servers; they just need to know one valid hostname in your zone. Unlike a direct flood, your servers look like they're behaving correctly — they're just answering queries. That makes basic DDoS mitigation based on traffic volume almost useless, because you can't just block UDP port 53 without taking yourself offline.
# Typical amplification observed in the wild - captured via tcpdump + dig
# Spoofed query (48 bytes on wire):
dig @ns1.cdn-example.net ANY victim-zone.com +edns=0 +bufsize=4096 +short
# Response (3240 bytes) - 67.5x amplification
;; MSG SIZE rcvd: 3240
;; Query: 1 Answer: 14 Authority: 3 Additional: 4
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 4096
# What we saw at the edge - 1 Mpps of these = ~25 Gbps per PoP
tcpdump -i eth0 -n 'udp port 53 and src net 192.0.2.0/24' -c 5
15:42:11.231 IP 198.51.100.23.54321 > 203.0.113.10.53: 12345 ANY? victim-zone.com. (48)
15:42:11.232 IP 203.0.113.10.53 > 198.51.100.23.54321: 12345 14/3/4 ANY (3240)
Response Rate Limiting That Doesn't Punish Real Users
When we first turned on Response Rate Limiting (RRL) in BIND, we broke things. Badly. We set a blanket 10 responses/second per IP block and immediately started dropping legitimate retries from large ISP resolvers and monitoring probes. I've seen this mistake repeated at three different CDNs now. Aggressive rate limiting feels safe, but if you treat a Google Public DNS node the same way you treat a spoofed /24, you'll create brownouts for real users that are harder to debug than the attack itself.
Effective DNS protection for amplification isn't about blocking everything — it's about shaping responses. Modern RRL uses a slip parameter, where instead of silently dropping excess responses, you occasionally send a truncated (TC=1) response. Legitimate resolvers will retry over TCP, which attackers using spoofed UDP can't do. That single distinction filters 99% of reflection attack traffic without hurting real resolution. You also want to filter at the query-type level. We stopped answering ANY queries entirely in 2019 — following the same path Cloudflare and others took — and now return a small HINFO or truncated response. For DNSSEC, we cap EDNS0 UDP payload sizes and strip unnecessary records for unauthenticated queries. Pair that with DNS Cookies (RFC 7873) for your known peering resolvers and you've got a lightweight way to validate clients before sending large answers. Our approach to DNS CNAME Flattening: Pointing Root Domains to CDN Without Breaking DNS Rules also helped here, since it reduced the number of large CNAME chain + DNSSEC responses we had to generate at the apex.
Don't rely on BIND or Knot alone, either. The best place to kill spoofed traffic is before it hits your daemon. We run XDP/eBPF filters on every authoritative node that drop obviously spoofed packets (like internal RFC1918 sources arriving on an external interface) and enforce per-/24 token buckets in kernel space. That keeps your DNS software from even seeing the junk. For legitimate but abusive patterns — like a single client hammering random subdomains — we use Response Policy Zones (RPZ) to sinkhole the query at the edge. The HTTP Working Group Specifications (https://httpwg.org/specs/) and web.dev Articles (https://web.dev/articles/) aren't directly DNS-focused, but their guidance on retry behavior and TCP fallback has been surprisingly useful for tuning how browsers and resolvers handle those truncated responses.
// named.conf - RRL config we use in production on authoritative nodes
// Tested on BIND 9.18+ - handles ~500k QPS per node without extra latency
options {
// Don't be an amplifier: cap responses and use slip
rate-limit {
responses-per-second 15; // per client IP prefix
slip 2; // every 2nd dropped query gets TC=1
window 5; // 5-second sliding window
qps-scale 250; // scale limits if total QPS > 250k
exempt-clients { trusted; }; // allow large ISP resolvers
};
// Minimize ANY amplification
minimal-any yes; // return single RR instead of full set
// Cap EDNS payload to limit max response size
edns-udp-size 1232; // DNS flag day recommendation
max-udp-size 1232;
};
// nftables - early drop before DNS daemon (run via XDP where possible)
table inet dns_filter {
chain input {
type filter hook input priority -100;
udp dport 53 ip saddr 10.0.0.0/8 drop
udp dport 53 ip saddr 192.168.0.0/16 drop
udp dport 53 limit rate over 100/second burst 50 packets drop
}
}
Tuning Mitigation Without Breaking Global Performance
You can't set RRL and walk away. Every CDN's traffic pattern is different, and what's safe in North America might be too strict in a region where a single carrier-grade NAT IP represents 50,000 users. We learned to tune per PoP. In Southeast Asia, we had to raise responses-per-second to 25 and extend the window to 10 seconds because one telco's resolver farm looked exactly like an attack — high QPS, low entropy query names, but all legitimate. Without per-region tuning and visibility into EDNS Client Subnet for CDN Geolocation: Routing Users to the Nearest Edge, we'd have throttled half a country. EDNS Client Subnet data was critical for telling us whether a spike from a /24 was 10k real users behind NAT or one spoofed bot.
The metrics that matter aren't just "blocked queries." You need to track false positives, TCP fallback rate, and p95 resolution latency during an attack. A good mitigation might drop 95% of spoofed traffic but if it adds 40ms to your p99 because legitimate clients are being forced to TCP, you've traded a DDoS for a performance outage. We export RRL slip counters, QPS per prefix, and response size histograms to Prometheus every 10 seconds. When slip rate goes above 5% for more than two minutes, we page. When TCP retry rate jumps without a corresponding attack signature, we know our limits are too tight. That feedback loop is what separates a rule that works in a lab from one that survives a real botnet.
Below is what we actually measured before and after rolling out the full stack — kernel filtering + RRL with slip + ANY filtering + 1232-byte cap — across 42 anycast PoPs handling ~8M QPS authoritative. The numbers aren't lab theory; they're from a sustained 600 Gbps reflection attack in Q1 last year. The biggest win wasn't raw bandwidth reduction, it was cutting the amplification factor while keeping legitimate error rates flat.
| Metric (per PoP avg) | Before Mitigation | After Mitigation | Change |
|---|---|---|---|
| Avg. Amplification Factor (ANY/DNSSEC) | 48.5x (3240 bytes resp.) | 4.2x (512 bytes capped/truncated) | -91% amplification |
| Outbound Attack Bandwidth | 14.2 Gbps | 0.9 Gbps | -93.7% reflected traffic |
| Legitimate Query Drop Rate | 0.02% (no RRL) | 0.18% (RRL slip active) | +0.16pp, TCP retry recovered |
| p95 DNS Resolution Latency | 8 ms | 11 ms (19 ms during slip) | +3 ms steady state |
| TCP Fallback Rate (legit resolvers) | 0.4% | 3.1% during attack | Expected, valid clients retried |
Putting It Into Practice: Filtering and Response Trimming at the Edge
Knowing what to rate-limit is one thing — actually deploying it across 200+ PoPs without blackholing real traffic is another. We've found the most resilient approach isn't a single silver bullet, but a layered stack at the authoritative edge: stateless packet filtering for obvious spoofing, then intelligent response handling for everything else. The first layer lives outside your DNS daemon entirely.
At the network edge, we drop ANY queries and oversized UDP responses before they ever hit the name server process. ANY is deprecated per RFC 8482 anyway, and legitimate use is near zero — yet it still accounts for 60-70% of amplification payloads we see, often returning 3,200+ bytes for a 45-byte query (a 70x factor). We also enforce a hard 512-byte truncation for UDP without EDNS0 and cap EDNS0 UDP payloads at 1,232 bytes. That alone cuts your worst-case amplification from 50x down to under 15x without impacting modern resolvers. For a deeper look at how authentication interacts with response size, check our guide on DNSSEC Signing for CDN Infrastructure: Authenticated DNS Without the Performance Hit — DNSSEC is notorious for making responses larger if you don't manage it.
Inside the DNS software, you want slip-based rate limiting, not hard drops. Here’s a production-tested Knot DNS pattern we run on authoritative PoPs handling 80k-120k qps each:
# /etc/knot/knot.conf - Authoritative edge mitigation
server:
udp-workers: 32
tcp-workers: 32
policy:
- id: rrl_slip
# 15 responses/sec per /24 (IPv4) or /56 (IPv6) before slipping
rate-limit: 15
rate-limit-slip: 2 # every 2nd dropped response gets a TC=1 slip
rate-limit-table-size: 1048576
template:
- id: default
storage: "/var/lib/knot"
# Crucial: Drop ANY, trim long responses, force TCP fallback
module: mod-rrl/default + mod-queryacl/default
mod-rrl:
- id: default
rate-limit: 15
slip: 2
whitelist: ["10.0.0.0/8", "trust-anchor-resolvers.conf"]
mod-queryacl:
- id: default
address: [0.0.0.0/0, ::/0]
action: deny
qtype: ANY # Refuse ANY outright, don't even slip it
Advanced Patterns and Troubleshooting When Legitimate Traffic Gets Caught
Basic RRL will save you from a 100 Gbps reflection flood, but sophisticated attackers have adapted. They'll rotate spoofed /24s slowly enough to stay under per-prefix limits, or they'll query for valid, large TXT records (like SPF or DKIM) that you can't just block like ANY. That's where entropy and behavior-based detection comes in. We run a lightweight eBPF monitor on each authoritative node that tracks query name entropy, QTYPE diversity, and NXDOMAIN ratio per /24. A real ISP resolver shows low entropy — it'll ask for 500 different customer domains with a Zipf distribution. An attack source shows high entropy: 10,000 queries for random12345.victim.com with identical QTYPEs. When entropy crosses ~7.5 bits and qps jumps 8-10x baseline in under 60 seconds, we automatically push a BGP Flowspec rule to that PoP to divert that prefix's UDP/53 traffic to a scrubbing path.
And here's where you'll get burned if you're not careful: false positives on large public resolvers. Google's 8.8.8.8 or Cloudflare's 1.1.1.1 can legitimately burst to 2,000-3,000 qps from a single PoP during a cache cold-start, and naive RRL will slip them, adding 80-120ms of TCP retry latency for thousands of users. We maintain a dynamic allowlist of known resolver ASNs (updated hourly via BGP feed) that gets a 5x higher RRL threshold (75 qps vs 15 qps) and is exempt from ANY blocks. Even then, we had an incident last quarter where we accidentally rate-limited a national ISP's recursor in Brazil — latency for their customers spiked to 1.4s. The fix was adding per-ASN monitoring and alerting if slip rate for any allowlisted ASN exceeds 5%. If you need to isolate and analyze that kind of malicious traffic instead of just dropping it, DNS Sinkholing at CDN Scale is a much safer pattern than outright blackholing.
If mitigation does cause resolution failures, don't just disable RRL and hope. Check three things in order: 1) Is your TCP capacity actually sufficient? A slip is useless if your TCP workers are saturated — we allocate 1 TCP worker per 2 UDP workers and keep TCP connection limits at 20k per node. 2) Are you seeing anycast churn? A withdrawn PoP can funnel its entire continent's traffic to the next-closest node, instantly tripling its qps and tripping local limits. Pair your RRL with DNS Failover Automation for CDN: Automatic Rerouting When Origins Go Down so health checks drain the PoP gracefully instead of hard-withdrawing the route. 3) Check your EDNS Client Subnet (ECS) logs — attackers often spoof ECS to bypass prefix limits, so you need to rate-limit on source IP, not ECS scope.
Frequently Asked Questions
Will enabling response rate limiting (RRL) break DNSSEC validation?
No, if you use slip (TC=1) instead of drop. A slipping RRL tells the legitimate resolver "retry over TCP," and TCP responses are not rate-limited the same way. Validating resolvers will follow the TC bit and get the full DNSSEC chain over TCP with maybe 40-60ms of added latency on the first query. What's dangerous is a hard-drop policy — that causes SERVFAIL and validation failures. Always set slip to 2 or at least 10, never to 0 (which means complete drop).
Should we just block ANY queries completely on authoritative servers?
Yes, for 99.9% of CDNs you should. RFC 8482 explicitly allows authoritative servers to return a single RRset or refuse ANY, and no modern application depends on it. Cloudflare and Akamai have blocked ANY for years without customer impact. If you have a legacy customer who insists they need it, serve them a minimal HINFO response instead of the full zone. The risk/reward is terrible otherwise — ANY is responsible for the largest amplification factors we see.
How do I know if my CDN is currently being used as an amplifier?
Look for three signals in your authoritative logs: 1) UDP query rate from a small set of /24s that's 10-50x higher than your p95, 2) Response size far exceeding query size (avg response > 800 bytes for a sustained period), and 3) A high ratio of ANY/TXT/DNSKEY queries. On the network side, if your outbound UDP/53 bandwidth is consistently 15-20x your inbound UDP/53 bandwidth, you're amplifying. Set an alert if outbound/inbound ratio exceeds 8:1 for more than 2 minutes.
Can’t we just rely on upstream BCP38 anti-spoofing instead of fixing it on our servers?
You should absolutely push your transit providers for BCP38/Source Address Validation, but you can't rely on it alone. Industry measurements still show 20-25% of ASNs don't filter spoofed packets, especially in regions where many attacks originate. BCP38 is an inbound filter on the attacker's network — RRL and response trimming are your outbound responsibility as the amplifier. You need both. Think of it like defense-in-depth: you control what you can control at your own edge.