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