Frontend Labs
⋯

15. IP fragmentation and reassembly in detail

15.1 The mechanism (IPv4)

If a packet larger than the egress MTU must be sent and DF=0, the router (or the source) splits it:

Original: ID=4711, len=4000 (3980 payload), DF=0
MTU=1500 -> payload chunks must be multiples of 8, <= 1480

Frag 1: ID=4711, offset=0,    MF=1, payload bytes 0-1479     (len 1500)
Frag 2: ID=4711, offset=185,  MF=1, payload bytes 1480-2959  (185*8 = 1480)
Frag 3: ID=4711, offset=370,  MF=0, payload bytes 2960-3979  (len 1040)
  • All fragments share the Identification, source, destination, protocol.
  • Offset is in 8-byte units → every fragment except the last has a payload length divisible by 8.
  • MF=1 on all but the last.
  • Only the first fragment has the TCP/UDP header → stateless firewalls and load balancers that key on L4 ports can't classify fragments 2..N.
  • Reassembly happens only at the final destination, which holds fragments in a buffer with a timer (net.ipv4.ipfrag_time, default 30 s). Miss one → ICMP 11/1, whole packet discarded, upper layer must resend everything.

15.2 IPv6 differs

Routers never fragment IPv6. Only the source may, using a Fragment extension header. If the source doesn't do PMTUD and sends too big → the packet is dropped with ICMPv6 Packet Too Big. Minimum IPv6 MTU is 1280; a source can always fall back to that.

15.3 Why fragmentation is considered harmful

  1. Loss amplification: losing 1 of 3 fragments wastes the other 2 and forces a full resend. Effective loss rate triples.
  2. Firewall/LB evasion & confusion: overlapping/tiny fragments were classic IDS-evasion attacks (teardrop, ping of death). Many networks now drop all fragments.
  3. Stateful device load: reassembly needs memory and CPU; a flood of first-fragment-missing packets is a DoS (fragment flood).
  4. Offload defeat: NIC segmentation/checksum offloads assume unfragmented packets.
  5. PMTUD black holes (Ch. 8) when the ICMP is filtered.

15.4 What to do instead

  • Let TCP discover MSS/PMTU and never fragment (it always sets DF).
  • For UDP apps that send large messages (DNS over UDP, QUIC, VPN, RTP):
    • Keep datagrams ≤ ~1200 bytes to survive almost any path (QUIC uses 1200, DNS recommends EDNS buffer ≤ 1232).
    • Or do application-level PLPMTUD.
  • On tunnels: MSS clamp for TCP; set a conservative tunnel MTU for UDP.
  • DNS specifically: large UDP responses (DNSSEC) fragment → get dropped → clients retry over TCP/53. Ensure TCP/53 is allowed (a very common misconfig).

15.5 War story

A resolver behind a firewall failed to validate DNSSEC for certain zones. dig +dnssec over UDP returned truncated or timed out; over TCP it worked. The firewall dropped IP fragments, and the 2500-byte DNSKEY response fragmented at 1500. Fixes applied: allow TCP/53, set the resolver's EDNS UDP buffer to 1232, and stop dropping fragments to the resolver. Lesson: "DNSSEC is broken" is often "IP fragments are being dropped" plus "TCP/53 is blocked."

Try it yourself

# Force fragmentation and watch it
ping -s 4000 -c1 <peer>                 # 4000-byte ICMP -> multiple fragments
sudo tcpdump -i any -n 'ip[6:2] & 0x3fff != 0'   # capture only IPv4 fragments
sysctl net.ipv4.ipfrag_time net.ipv4.ipfrag_high_thresh
dig +dnssec +tcp DNSKEY org             # force DNS over TCP

Generated from real-life-example.md · 8 Oct 2026 16:36