DNS EDNS0 Fragmentation: The Hidden Cause of “Works on Wi‑Fi, Fails on LTE”

Was this helpful?

You ship a perfectly boring change—new records, maybe DNSSEC, maybe a “harmless” extra TXT string for verification—and suddenly support tickets spike:
the site loads on office Wi‑Fi, but on LTE it spins, times out, or falls back to some captive-portal-looking error page.

Everyone blames the app. Someone blames the CDN. Somebody says “mobile networks are flaky” and goes back to lunch.
Meanwhile the real failure is upstream of your stack: DNS replies got big, EDNS0 advertised a bigger UDP payload, fragmentation happened,
and the cellular path quietly ate the fragments. Nothing looks down. Everything feels haunted.

What EDNS0 fragmentation really is (and why LTE is the perfect villain)

DNS started life with UDP replies capped at 512 bytes. That wasn’t a “nice-to-have”; it was survival.
Small packets mean less fragmentation, fewer retransmits, fewer surprises. Then the internet got ambitious:
more records per answer, more glue, IPv6, DNSSEC signatures, and a desire to not force TCP for everything.

EDNS0 (Extension Mechanisms for DNS) is the compromise. The client (resolver) says: “I can accept UDP replies up to N bytes.”
The server tries to fit. If it can’t, it sets the TC (truncated) bit and the client retries over TCP.
On paper, this is elegant. In production networks, “paper” is an endangered species.

The trap: when you advertise a large UDP size (commonly 1232, 1400, 4096), you invite large UDP responses.
Large UDP responses often exceed the path MTU and get fragmented at the IP layer.
Fragmentation means: one DNS reply becomes multiple IP packets that must all arrive and be reassembled correctly.
Lose one fragment and the whole DNS response evaporates.

Many cellular and “middlebox-heavy” networks are allergic to fragments. Some drop fragments by design.
Some mishandle them. Some reassemble badly. Some rate-limit them into oblivion.
Wi‑Fi paths—especially inside corporate networks or home broadband—tend to be more forgiving, or at least consistent.
LTE paths are a gauntlet of NATs, firewalls, traffic optimizers, and policy engines. That’s the point: LTE isn’t “worse”,
it’s just more complicated.

Your outage is not that DNS is down. Your outage is that DNS is sometimes incomplete.
Those are the worst outages because monitoring is always late to the party.

Joke #1: UDP fragmentation is like sending a porcelain mug in two envelopes—technically possible, emotionally irresponsible.

The mechanics in plain terms

  • Client sends a DNS query (UDP) with an EDNS0 OPT record indicating “I can receive X bytes.”
  • Server replies (UDP) trying to fit within X bytes.
  • If the reply still doesn’t fit, server sets TC=1 (truncated) and the client should retry over TCP.
  • If the reply fits X but exceeds path MTU, the IP layer fragments it.
  • If fragments are dropped, delayed, or filtered, the client sees a timeout—not necessarily TC.

Why “big UDP” is seductive

Operators love the idea of avoiding TCP for DNS: fewer connections, less state, lower latency under load.
Some resolvers and authoritative servers even default to “generous” EDNS sizes because it benchmarks well in clean labs.
Then real networks happen. Especially mobile. Especially roaming. Especially with VPN overlays.

Why it works on Wi‑Fi but fails on LTE

The simplest mental model: Wi‑Fi users often sit behind one NAT with stable MTU and fewer packet “helpers.”
LTE users are behind carrier-grade NAT, often multiple layers of policy enforcement, and sometimes quirky MTUs.
Add IPv6 transition mechanisms, tunnels, and “optimizers,” and fragments become suspect.

Common LTE path features that break fragmented UDP

  • Carrier-grade NAT (CGNAT) that has fragment-handling limitations or aggressive timeouts.
  • Firewall policies that drop non-initial fragments because they can’t be easily classified.
  • Traffic shaping that deprioritizes or rate-limits fragments (sometimes unintentionally).
  • Path MTU variability due to roaming or tunnelled backhauls.
  • IPv6/IPv4 translation where fragment handling differs between stacks or is buggy.

The “EDNS0 size vs. MTU” mismatch

Suppose your resolver advertises EDNS0 UDP size 4096. Your authoritative server gladly responds with a 1800-byte UDP packet.
That 1800-byte IP payload doesn’t fit in a typical 1500-byte Ethernet MTU after headers. Fragmentation happens.
On Wi‑Fi, fragments arrive; on LTE, the second fragment disappears. The client sees a DNS timeout.

Now suppose you reduce the EDNS0 size to 1232. Many responses shrink below fragmentation thresholds.
Or the server truncates earlier, forcing TCP fallback. Either way, you stop relying on fragile fragments.
This is why 1232 has become a practical sweet spot: it’s conservative enough to avoid fragmentation on many paths,
including IPv6 where headers are larger and fragmentation rules differ.

Why you don’t always see TCP fallback

“But DNS should retry over TCP if UDP fails.” In theory, yes.
In reality:

  • Some clients are slow to fallback, making the user experience look like “hang then maybe load.”
  • Some middleboxes block DNS over TCP (port 53) or treat it as suspicious.
  • Some resolvers cache partial failures, amplifying pain for a few minutes.
  • Some authoritative setups don’t handle TCP at scale and time out under bursty fallback.

EDNS0 fragmentation bugs don’t just break UDP. They can stampede you into a TCP load pattern you didn’t size for.

Interesting facts and historical context (the kind that explains today’s weirdness)

  • DNS UDP’s original 512-byte limit wasn’t an arbitrary standard; it was built for an internet where fragmentation was a real operational hazard.
  • EDNS0 was standardized in the late 1990s to extend DNS without changing the core message format, using an OPT pseudo-record.
  • DNSSEC made “big answers” common by adding signatures (RRSIG), keys (DNSKEY), and denial-of-existence proofs (NSEC/NSEC3).
  • “Bigger is faster” became an ops myth as some resolvers defaulted to large EDNS0 buffers to reduce TCP fallback in benchmarks.
  • IPv6 changes fragmentation rules: routers don’t fragment; only endpoints do, making PMTU discovery and packet sizing more important.
  • Some old firewalls drop fragments by default because non-initial fragments don’t carry L4 headers, complicating filtering.
  • CDNs and multi-record answers increased response sizes: multiple A/AAAA records, ECS variations, and extra glue can bloat replies.
  • EDNS Client Subnet (ECS) can change answer size and caching behavior, occasionally pushing responses over fragmentation thresholds unexpectedly.
  • “DNS over TCP exists for a reason”: even early DNS specs included TCP as the reliable fallback, but many operators treated it as “rare.”

Failure signatures you can recognize in minutes

EDNS0 fragmentation issues have a particular smell. You see timeouts, but only on certain networks.
You see some record types fail (often DNSSEC-related, or TXT-heavy).
And you see “it works if I try twice” because retry paths differ.

Classic symptoms

  • Wi‑Fi works, LTE fails (or works on one carrier, fails on another).
  • AAAA lookups fail more than A because answers are larger or because IPv6 path MTU differs.
  • DNSSEC validation failures on specific domains, often intermittent and geography-dependent.
  • Large TXT records (SPF, DKIM, verification tokens) cause failures for only some users.
  • Authoritative servers look healthy; query volume is normal; but client-side logs show SERVFAIL or timeouts.
  • Packet captures show outbound responses with no corresponding inbound ACK/response because UDP doesn’t ACK; you infer loss by retries.

What you’re actually observing

You’re watching a transport problem masquerade as a name resolution problem. DNS is the payload; fragmentation is the knife.
Your resolver sends a query, your authoritative responds, and one fragment dies in transit. The response can’t be reassembled.
From the client perspective, it’s indistinguishable from “server didn’t answer.”

“paraphrased idea” from Richard Cook (safety/ops): systems fail in surprising ways because success requires many things to go right, failure needs one thing to go wrong.

Fast diagnosis playbook

Don’t start by debating DNS servers. Start by proving whether you’re losing fragments or forcing truncation.
The goal is to reduce the problem to a single sentence you can act on: “Large UDP answers die on the LTE path.”

First: confirm it’s size/transport, not “wrong records”

  1. Compare the same query over two networks (Wi‑Fi vs LTE) using the same resolver, if possible.
  2. Force smaller EDNS0 sizes and see if failures disappear.
  3. Force TCP and see if failures disappear (or if TCP is blocked).

Second: determine where the break is

  1. Client stub resolver vs recursive resolver: does querying the recursive directly work?
  2. Recursive vs authoritative: does the recursive fail only when talking to specific authorities?
  3. Edge devices: do you have a firewall, load balancer, or DDoS appliance in front of authoritative DNS?

Third: apply the least risky mitigation

  1. Lower advertised EDNS0 UDP size on recursive resolvers (often to 1232).
  2. Ensure TCP/53 works end-to-end (recursive to authoritative, and clients to recursive where applicable).
  3. Avoid oversized responses: trim TXT bloat, reduce unnecessary records, consider DNSSEC response shaping.

Practical tasks: commands, output, what it means, what you decide (12+)

Task 1: Measure answer size and see if it’s flirting with fragmentation

cr0x@server:~$ dig example.com A +dnssec +bufsize=4096 @8.8.8.8

; <<>> DiG 9.18.24 <<>> example.com A +dnssec +bufsize=4096 @8.8.8.8
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 14651
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;example.com.                   IN      A

;; ANSWER SECTION:
example.com.            3600    IN      A       93.184.216.34

;; Query time: 24 msec
;; SERVER: 8.8.8.8#53(8.8.8.8) (UDP)
;; MSG SIZE  rcvd: 97

What it means: MSG SIZE rcvd is tiny here, so fragmentation isn’t your issue for this query.
Decision: Test the domains/record types that fail (TXT, DNSKEY, large CNAME chains), not a toy A record.

Task 2: Test a known “big” record (TXT) with a large EDNS0 buffer

cr0x@server:~$ dig example.com TXT +bufsize=4096 @1.1.1.1

;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 53204
;; flags: qr rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;example.com.                   IN      TXT

;; ANSWER SECTION:
example.com.            3600    IN      TXT     "v=spf1 -all"
example.com.            3600    IN      TXT     "some-long-verification-token=..."
example.com.            3600    IN      TXT     "another-token=..."

;; Query time: 31 msec
;; MSG SIZE  rcvd: 1605

What it means: 1605 bytes over UDP likely fragments on many 1500-MTU paths.
Decision: Re-test with smaller EDNS0 sizes and with TCP to confirm size sensitivity.

Task 3: Force a conservative EDNS0 size to avoid fragmentation

cr0x@server:~$ dig example.com TXT +bufsize=1232 @1.1.1.1

;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 60421
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;example.com.                   IN      TXT

;; ANSWER SECTION:
example.com.            3600    IN      TXT     "v=spf1 -all"
example.com.            3600    IN      TXT     "some-long-verification-token=..."

;; Query time: 29 msec
;; MSG SIZE  rcvd: 812

What it means: The answer shrank (maybe fewer records fit, or the resolver adjusted).
Decision: If LTE starts working with 1232 but not with 4096, you’ve basically diagnosed fragmentation loss.

Task 4: Detect truncation (TC bit) and see whether TCP fallback should happen

cr0x@server:~$ dig example.com DNSKEY +dnssec +bufsize=512 @1.1.1.1

;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 3122
;; flags: qr rd ra tc; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: Message has been truncated
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
;; QUESTION SECTION:
;example.com.                   IN      DNSKEY

;; Query time: 35 msec
;; MSG SIZE  rcvd: 512

What it means: tc is set; UDP reply didn’t fit. A well-behaved resolver should retry over TCP.
Decision: If clients still fail, check whether TCP/53 is blocked or whether the authoritative mishandles TCP.

Task 5: Force TCP and see if the “LTE failure” disappears

cr0x@server:~$ dig example.com DNSKEY +dnssec +tcp @1.1.1.1

;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 61752
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
;; QUESTION SECTION:
;example.com.                   IN      DNSKEY

;; ANSWER SECTION:
example.com.            3600    IN      DNSKEY  257 3 13 ...
example.com.            3600    IN      DNSKEY  256 3 13 ...

;; Query time: 44 msec
;; SERVER: 1.1.1.1#53(1.1.1.1) (TCP)
;; MSG SIZE  rcvd: 1203

What it means: TCP works and returns a larger payload reliably.
Decision: If TCP works everywhere but UDP fails on LTE, mitigate by shrinking UDP sizes and ensuring TCP is allowed.

Task 6: Verify whether your recursive resolver is advertising an aggressive EDNS size

cr0x@server:~$ dig whoami.akamai.net TXT +bufsize=4096 @10.0.0.53

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;whoami.akamai.net.            IN      TXT
;; ANSWER SECTION:
whoami.akamai.net.     20      IN      TXT     "198.51.100.17"
;; MSG SIZE  rcvd: 128

What it means: Your resolver (10.0.0.53) is willing to receive 4096-byte UDP answers from upstream authorities.
Decision: Consider lowering that to 1232 unless you have a proven reason not to.

Task 7: Check truncation and retries in Unbound logs

cr0x@server:~$ sudo journalctl -u unbound --since "1 hour ago" | egrep -i "trunc|tc|timeout" | tail -n 8
[12234:0] info: response was truncated, retrying with TCP
[12234:0] info: tcp connected to 203.0.113.53 port 53
[12234:0] info: tcp returned answer for example.com. DNSKEY IN
[12234:0] info: resolving example.com. TXT IN: query response was truncated
[12234:0] info: tcp error: connection timed out
[12234:0] info: validation failure <example.com. DNSKEY IN>: no DNSKEY rrset

What it means: You’re seeing truncation and TCP fallback attempts; one TCP connection timed out.
Decision: Investigate TCP/53 reachability to specific authorities and any middleboxes between recursive and internet.

Task 8: Confirm TCP/53 is reachable from recursive to authoritative

cr0x@server:~$ nc -vz 203.0.113.53 53
Connection to 203.0.113.53 53 port [tcp/domain] succeeded!

What it means: TCP/53 is reachable to that server from this host.
Decision: If this fails for some authorities, fix firewall/egress policy or use a resolver that can reach TCP reliably.

Task 9: Capture fragments on the recursive resolver and prove they’re happening

cr0x@server:~$ sudo tcpdump -ni eth0 'udp port 53 and (ip[6:2] & 0x1fff != 0)' -c 5
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
14:03:21.112233 IP 198.51.100.10.53 > 10.0.0.53.49321: UDP, length 1472
14:03:21.112240 IP 198.51.100.10 > 10.0.0.53: ip-proto-17
14:03:21.112245 IP 198.51.100.10 > 10.0.0.53: ip-proto-17
5 packets captured

What it means: The filter matched fragmented UDP (non-zero fragment offset or MF flag). You’re seeing fragments.
Decision: If clients on LTE fail and you observe fragmentation on the path, reduce EDNS sizes and prefer TCP fallback.

Task 10: Check PMTU-related ICMP behavior (a common silent accomplice)

cr0x@server:~$ ping -M do -s 1472 8.8.8.8 -c 3
PING 8.8.8.8 (8.8.8.8) 1472(1500) bytes of data.
ping: local error: message too long, mtu=1492
ping: local error: message too long, mtu=1492
ping: local error: message too long, mtu=1492

--- 8.8.8.8 ping statistics ---
3 packets transmitted, 0 received, +3 errors, 100% packet loss

What it means: You have an MTU of 1492 somewhere (PPPoE is a usual suspect), so “safe” payloads are smaller.
Decision: Treat 1232 as a baseline and be suspicious of anything that routinely pushes UDP DNS answers above ~1200 bytes.

Task 11: Inspect iptables/nftables rules that might drop fragments

cr0x@server:~$ sudo iptables -S | egrep -i "fragment|frag|DROP" | head
-A INPUT -f -j DROP
-A FORWARD -f -j DROP

What it means: “-f” matches fragments; you’re dropping them. That’s not “security,” that’s self-sabotage for UDP protocols.
Decision: Stop dropping fragments blindly on DNS-facing paths; instead reduce fragmentation by lowering EDNS size and allowing TCP.

Task 12: Validate that your authoritative DNS answers over TCP (some don’t, until you ask)

cr0x@server:~$ dig yourzone.example DNSKEY +tcp @ns1.yourauth.example

;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 40422
;; flags: qr aa rd; QUERY: 1, ANSWER: 4, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available
;; SERVER: 192.0.2.53#53(192.0.2.53) (TCP)
;; MSG SIZE  rcvd: 1890

What it means: TCP works and returns a large response.
Decision: If TCP fails here, fix authoritative TCP support before you “tune EDNS” anywhere else.

Task 13: In BIND, check current EDNS and TCP settings (authoritative or recursive)

cr0x@server:~$ sudo named-checkconf -p | egrep -i "edns|tcp|max-udp-size|clients-per-query|tcp-clients" | head -n 20
tcp-clients 100;
clients-per-query 10;
max-udp-size 4096;

What it means: max-udp-size 4096 invites fragmentation on real paths.
Decision: Consider lowering max-udp-size (or equivalent) and ensure tcp-clients is sized for fallback bursts.

Task 14: In Unbound, confirm EDNS buffer size and tune it safely

cr0x@server:~$ sudo unbound-checkconf | egrep -i "edns-buffer-size|so-rcvbuf|so-sndbuf|tcp-upstream|do-tcp" || true
edns-buffer-size: 4096

What it means: Unbound is advertising 4096 upstream. That’s often too optimistic in mobile-heavy environments.
Decision: Set edns-buffer-size to 1232, then monitor TCP query rate and latency.

Task 15: Prove that changing EDNS size changes behavior against the same authoritative

cr0x@server:~$ dig bigdns.example TXT +bufsize=4096 @ns.bigauth.example
;; Query time: 1200 msec
;; connection timed out; no servers could be reached
cr0x@server:~$ dig bigdns.example TXT +bufsize=1232 @ns.bigauth.example
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 2211
;; flags: qr aa; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; Query time: 48 msec
;; MSG SIZE  rcvd: 1198

What it means: Same server, same record; only EDNS size changed. One times out; one succeeds.
Decision: This is your smoking gun: fragmentation or middlebox intolerance on the path.

Three corporate mini-stories from the trench

Mini-story 1: The incident caused by a wrong assumption

A company I’ll call “Northwind Billing” had a tidy setup: Anycast authoritative DNS behind a DDoS scrubbing provider,
plus a popular public recursive fallback for internal diagnostics. They enabled DNSSEC for their main zone during a routine compliance push.
The rollout was quiet for desktop users. Mobile signups, however, fell off a cliff.

The first assumption was painfully human: “Mobile users have bad reception.” The second assumption was worse: “DNS is stable plumbing.”
Support reported a consistent pattern: home broadband and office Wi‑Fi worked; LTE often failed at the first page load.
Engineering chased API logs, then CDN cache misses, then TLS handshake telemetry. Everything was normal because nothing was reaching the app.

The breakthrough came from a packet capture taken on an LTE hotspot during a failure window.
The DNS reply containing DNSKEY/RRSIG was large, fragmented, and the second fragment never arrived.
No TC bit was set because the answer fit within the resolver’s advertised EDNS0 buffer; it just didn’t fit the path.
The recursive retried; the user’s phone gave up first. DNS was “up.” It was also unusable.

Fixing it was not glamorous. They reduced EDNS0 buffer size on their recursive fleet to 1232, confirmed TCP/53 was allowed,
and monitored the resulting increase in TCP queries. The failure rate dropped immediately.
The “wrong assumption” wasn’t technical. It was managerial: treating mobile DNS failures as “random” instead of “path-dependent.”

Mini-story 2: The optimization that backfired

“Bluejay Media” ran a high-volume recursive resolver service for their apps. Latency was a vanity metric there: every millisecond got argued about.
Someone noticed that TCP fallback was happening more than expected during peak. The optimization was straightforward:
raise EDNS0 advertised size so more answers fit in UDP, fewer TCP handshakes, lower median latency. Benchmarks looked great.

Two weeks later, they started receiving carrier-specific complaints: one major mobile network had intermittent login issues.
Not everyone. Not every region. Just enough to be a nightmare.
Their dashboards showed mild increases in DNS timeouts, but not enough to trigger alerts. App teams saw authentication failures.
Security saw nothing. Network saw nothing. Everyone saw someone else’s problem.

The backfire was classic: increasing EDNS0 size shifted the system from “TC triggers TCP” to “UDP fragments must survive.”
On that carrier, fragments were rate-limited aggressively during congestion. Under load, the resolver sprayed fragmented responses into a shredder.
Retries increased traffic. Traffic increased congestion. Congestion increased drops. It wasn’t an outage; it was a feedback loop.

They rolled back EDNS0 size and—this is the part people skip—kept the rollback.
Then they sized TCP properly, including connection limits, kernel tuning, and observability on TCP fallback rates.
The optimization that “improved medians” was a reliability regression hiding in the tail latency and in specific networks.

Mini-story 3: The boring but correct practice that saved the day

“Kestrel Finance” had an internal rule: every authoritative DNS service must support TCP well, and every change to DNS zones runs a
“large-answer check” in CI. The rule existed because one of their senior SREs was personally offended by packet loss as a concept.
It sounded like overkill—until it wasn’t.

A vendor asked them to add multiple TXT verification records and a long SPF include chain for a new email service.
The change request looked harmless. CI flagged it: the TXT response exceeded 1400 bytes with DNSSEC on.
The pipeline didn’t block it outright; it required an explicit waiver with a mitigation plan.

The mitigation plan was boring: split TXT records where possible, remove stale tokens, and ensure the recursive resolvers advertised 1232.
They also verified TCP/53 reachability from all egress points used by their recursive fleet.
The change shipped with zero drama, because they had already rehearsed the failure mode and designed around it.

The saving grace wasn’t a clever trick. It was institutionalized paranoia: test the ugly path (large answers) before users do,
and treat TCP as a first-class citizen rather than an embarrassing fallback.

Common mistakes: symptoms → root cause → fix

1) “Only mobile users fail, desktops fine” → fragmented UDP dropped on cellular path → shrink EDNS and confirm TCP

  • Symptom: DNS timeouts mostly on LTE; Wi‑Fi stable.
  • Root cause: Large UDP answers fragment; fragments dropped by CGNAT/firewalls.
  • Fix: Set EDNS buffer to 1232 on recursives; verify TCP/53 works; monitor TCP query rate.

2) “DNSSEC randomly fails validation” → missing fragments cause incomplete DNSKEY/RRSIG → reduce UDP size, improve TCP, avoid bloat

  • Symptom: SERVFAIL from validating resolvers; intermittent, carrier- or region-dependent.
  • Root cause: DNSSEC responses are larger; fragments lost; validation fails.
  • Fix: Lower EDNS size; ensure authoritative answers over TCP; reduce record-set size where feasible.

3) “We increased EDNS to reduce TCP and it got worse” → optimization created fragment dependency → revert EDNS, scale TCP properly

  • Symptom: fewer TC responses but more timeouts and retries.
  • Root cause: fewer truncations means fewer TCP fallbacks; large UDP now fragments and dies.
  • Fix: Prefer predictable TCP fallback over fragile fragmentation; capacity-plan TCP clients and state.

4) “UDP works, TCP fails” → middlebox blocks TCP/53 → allow TCP or use DoT/DoH to your recursives

  • Symptom: dig works without +tcp, fails with +tcp, or TCP times out to authorities.
  • Root cause: firewalls/proxies block or throttle TCP/53.
  • Fix: Fix policy; ensure stateful devices allow TCP/53; if you control clients, consider encrypted DNS to a trusted recursive.

5) “It fails only for some domains” → large RRsets, long TXT, many A/AAAA, ECS variations → trim and measure answer sizes

  • Symptom: only certain vendors or zones fail.
  • Root cause: response size crosses fragmentation thresholds due to RRset size.
  • Fix: remove stale TXT; avoid unnecessary multi-record answers; validate with dig +bufsize tests.

6) “We drop fragments for security” → you broke UDP protocols → stop doing that (and fix the underlying reason)

  • Symptom: random UDP timeouts; DNS worse when answers large.
  • Root cause: firewall rules drop fragments (-f), especially on forward paths.
  • Fix: Remove blanket fragment drops on DNS paths; use sane EDNS sizing and TCP fallback.

Joke #2: Middleboxes that “optimize” fragments are like interns who rewrite your runbooks—confident, fast, and catastrophically creative.

Checklists / step-by-step plan

Step-by-step: stop the outage first, then fix it properly

  1. Reproduce on a failing path: use a real LTE connection, not an office VPN pretending to be mobile.
  2. Run three digs for the failing name:
    • default (whatever your resolver does)
    • +bufsize=1232
    • +tcp
  3. If +tcp fixes it, treat this as a UDP fragmentation/truncation problem until proven otherwise.
  4. Lower EDNS buffer size on recursive resolvers to 1232 (or similarly conservative) and roll out progressively.
  5. Confirm TCP/53 reachability from recursives to the internet and from clients to recursives (depending on architecture).
  6. Watch for TCP stampedes:
    • TCP connection counts
    • SYN backlog and listen queues
    • resolver latency and timeouts
  7. Trim oversized DNS answers:
    • remove old TXT verification tokens
    • simplify SPF where possible
    • avoid unnecessary multi-value RRsets
  8. Document and test: add a “large-answer regression test” for critical zones, especially with DNSSEC.

Operational checklist: what “good” looks like

  • Recursive resolvers advertise conservative EDNS UDP sizes to upstream authorities (commonly 1232).
  • Authoritative DNS supports TCP reliably and at scale.
  • Firewalls and load balancers do not drop fragments blindly on DNS paths.
  • Monitoring includes: TC-bit rate, TCP fallback rate, UDP timeout rate, SERVFAIL rate, and per-carrier client error telemetry (if you have it).
  • Change management includes answer-size checks for TXT, DNSKEY, and worst-case chains (CNAME+DNSSEC is a classic answer-bloater).

FAQ

1) Is EDNS0 itself “bad”?

No. EDNS0 is necessary. The bad part is pretending that large UDP payloads are reliably deliverable across modern networks,
especially mobile, especially through middleboxes.

2) What EDNS0 UDP size should I use?

If you want a practical default in 2025, 1232 is a conservative choice that often avoids fragmentation on common IPv6 and IPv4 paths.
If you operate in controlled networks, you can experiment higher, but you need proof from production paths, not lab benches.

3) Why does lowering EDNS0 size sometimes make answers “smaller” instead of truncated?

Some resolvers adjust behavior: they may avoid adding certain optional records, prefer different servers, or receive different cached variants.
But the key outcome is what matters operationally: fewer fragmented UDP replies and more predictable fallback patterns.

4) If fragmentation is the problem, why not just “fix MTU”?

You often can’t. The failing path might be a carrier network, a roaming path, or a user’s VPN tunnel.
You can control your resolver behavior and authoritative behavior; you usually can’t control every MTU between a phone and the internet.

5) Doesn’t TCP for DNS increase latency and load?

It can. But unreliable UDP with retries and timeouts is worse—especially for user experience.
The right strategy is: keep UDP answers small enough to avoid fragmentation, and make TCP robust for the cases that truly need it.

6) Can DNSSEC be deployed safely without breaking mobile?

Yes. But you must plan for larger answers, verify TCP support, keep RRsets tidy, and avoid advertising huge EDNS sizes that turn “large” into “fragmented.”

7) Why does it fail only on one carrier or only in one country?

Because middleboxes differ. Fragment handling policies differ. MTUs differ. Even congestion-management differs.
DNS fragmentation issues are path-dependent by nature; variability is a feature of the failure mode.

8) Is DoH/DoT a fix for EDNS0 fragmentation?

For clients, encrypted DNS to a recursive can help because it rides over TCP (or QUIC) and avoids UDP fragments on the client-to-recursive leg.
It doesn’t automatically fix recursive-to-authoritative behavior; you still need conservative EDNS sizing and TCP reachability upstream.

9) How do I know if my firewall is dropping fragments?

Look for explicit fragment-drop rules (iptables “-f”), inspect counters, and capture traffic. If large UDP answers correlate with timeouts,
assume fragment handling is involved until you disprove it.

10) What should I alert on to catch this early?

Track TCP fallback rate changes, SERVFAIL rates for validating resolvers, UDP timeout rates, and query latency percentiles.
Pair that with client telemetry by network type (Wi‑Fi vs cellular) if you have an app.

Conclusion: next steps that stop the bleeding

EDNS0 fragmentation problems are the kind of outage you don’t see from the server room. The servers answer. The graphs look polite.
Users still can’t log in because one fragment out of two didn’t make it through a carrier’s maze.

What to do, in order:

  1. Prove it quickly with dig: compare +bufsize=4096 vs +bufsize=1232 vs +tcp on Wi‑Fi and LTE.
  2. Make UDP smaller: tune EDNS buffer sizes conservatively on recursives.
  3. Make TCP boring and reliable: allow it, scale it, and monitor it.
  4. Trim the DNS bloat: treat TXT sprawl and oversized RRsets like debt with interest.
  5. Add a regression check for answer sizes, especially when DNSSEC is involved.

Do those, and “works on Wi‑Fi, fails on LTE” goes back to being a meme instead of a pager.

← Previous
WordPress wp-admin Won’t Open: The Real Reasons and Fixes
Next →
Modern Login and Register Forms That Don’t Betray You in Production

Leave a comment