Loading learning content...
Fragmentation is only half the story. For IP to work, the destination host must be able to take fragments that may arrive out of order, be delayed, or even be duplicated—and reconstruct the original datagram perfectly. This process of reassembly is deceptively complex, involving careful state management, timeout handling, and validation against malicious or malformed fragments.
Reassembly is exclusively a destination-host responsibility. Intermediate routers never attempt to reassemble fragments—they simply forward (or further fragment if necessary). This end-to-end design principle keeps routers fast and simple while placing complexity at endpoints that can better manage the state.
By the end of this page, you will understand reassembly from the inside out: how destination hosts identify and group fragments, the data structures used for reassembly, handling of out-of-order arrival, timeout mechanisms, error conditions, performance considerations, and the security challenges that have made reassembly a frequent target of attacks.
The first challenge in reassembly is grouping fragments that belong together. Multiple fragmented datagrams may be in transit simultaneously from different sources or even from the same source to different destinations. The destination must correctly associate each incoming fragment with its original datagram.
Why all four fields are necessary:
Consider each field's contribution:
Reassembly buffer lookup:
When a fragment arrives:
key = hash(src_ip, dst_ip, protocol, identification)
buffer = reassembly_table.lookup(key)
if buffer exists:
add_fragment_to_buffer(buffer, fragment)
else:
create_new_buffer(key)
add_fragment_to_buffer(new_buffer, fragment)
With only 65,536 possible Identification values, high-traffic hosts can exhaust IDs quickly. On a 1 Gbps link sending 1000-byte datagrams, IDs recycle every 524 milliseconds. If old fragments are still in transit when IDs recycle, incorrect reassembly can occur. RFC 6864 addresses this by clarifying when unique IDs are required and recommending techniques like per-destination ID counters.
Each datagram undergoing reassembly requires dedicated buffer space. The buffer must track which bytes have been received, handle out-of-order arrival, and detect when reassembly is complete.
Hole tracking algorithms:
Two common approaches track which bytes are missing:
1. Bit Vector Approach:
2. Hole Descriptor List:
Completion detection:
Reassembly is complete when:
A host under attack could receive millions of fragment streams, each requiring buffer allocation. Operating systems limit reassembly memory through maximum buffer counts, per-source limits, and aggressive timeout policies. Without these limits, fragment attacks become trivial denial-of-service vectors.
Let's trace through the complete reassembly of a fragmented datagram to understand each decision point.
Detailed algorithm:
123456789101112131415161718192021222324252627282930313233343536373839404142434445
def process_fragment(fragment): # Step 1: Extract reassembly key key = (fragment.src_ip, fragment.dst_ip, fragment.protocol, fragment.identification) # Step 2: Find or create reassembly buffer buffer = reassembly_table.get(key) if not buffer: buffer = create_reassembly_buffer(key) buffer.timer = start_timer(REASSEMBLY_TIMEOUT) # Typically 30-60 seconds reassembly_table[key] = buffer # Step 3: Calculate byte range for this fragment start_byte = fragment.offset * 8 end_byte = start_byte + len(fragment.data) # Step 4: Validate fragment if end_byte > MAX_IP_DATAGRAM_SIZE: drop_and_log("Fragment exceeds maximum datagram size") return # Step 5: Check for overlapping data (security!) if buffer.has_data_in_range(start_byte, end_byte): # Policy decision: drop entire datagram or use first data handle_overlap(buffer, fragment) return # Step 6: Store fragment data buffer.store_data(fragment.data, start_byte) buffer.update_hole_list(start_byte, end_byte) # Step 7: If first fragment, save header if fragment.offset == 0: buffer.first_fragment_header = fragment.ip_header # Step 8: If last fragment, record total size if fragment.more_fragments == 0: buffer.total_size = end_byte # Step 9: Check if reassembly is complete if buffer.total_size and buffer.is_complete(): # All bytes received! complete_datagram = reassemble(buffer) deliver_to_protocol(complete_datagram) cleanup_buffer(key)The last fragment (MF=0) might arrive first, providing total_size before any data. Middle fragments might arrive before the first fragment. A robust implementation handles all arrival orders correctly—the only requirement is that ALL fragments eventually arrive before timeout.
Reassembly cannot wait indefinitely. Networks lose packets, and incomplete fragment streams must be cleaned up to free resources. Timeout and error handling are critical for robust operation.
ICMP Time Exceeded message:
When reassembly times out and the first fragment was received, the host sends:
This informs the source that its datagram could not be delivered, allowing upper layers to take action (e.g., TCP retransmission at smaller size).
| Error Condition | Detection | Action |
|---|---|---|
| Timeout | Timer expires before completion | Discard fragments, send ICMP if possible, free buffer |
| Overlapping fragments | New fragment data range overlaps existing | Policy-dependent: drop new, drop all, or first-wins |
| Total size exceeded | Last fragment indicates > 65,535 bytes | Discard all fragments immediately |
| Inconsistent total size | Different 'last' fragments disagree on size | Discard all fragments as corrupted |
| Memory exhaustion | No buffer space for new fragmentstream | Drop incoming fragment, possibly oldest buffers |
| Invalid offset alignment | Non-last fragment data not 8-byte aligned | Implementation-dependent; may accept or reject |
Short timeouts conserve memory but may drop legitimate traffic on high-latency paths. Long timeouts are vulnerable to resource exhaustion attacks. Most systems allow tuning: Linux's net.ipv4.ipfrag_time defaults to 30 seconds. In high-security environments, consider 15-20 seconds.
When fragments claim to contain overlapping byte ranges, the implementation must decide how to handle the conflicting data. This is a significant security consideration, as overlap attacks have been used to evade detection.
The overlap attack problem:
Attackers exploit different overlap policies:
If the firewall uses first-wins policy but the target uses last-wins, the firewall sees benign data while the target receives the malicious payload.
Modern solution: Drop on overlap
RFC 1858 and RFC 3128 recommend dropping the entire datagram if ANY overlap is detected:
Most modern operating systems now implement drop-on-overlap as the default policy.
123456789101112131415161718192021222324252627282930
def check_overlap(buffer, new_start, new_end): """ Check if new fragment overlaps with existing data. Modern security practice: return True if ANY overlap exists. """ for (existing_start, existing_end) in buffer.received_ranges: # Check all overlap conditions if new_start < existing_end and new_end > existing_start: # Overlap detected! log_security_event("Fragment overlap detected", buffer.key, new_start, new_end, existing_start, existing_end) return True return False def handle_overlap_secure(buffer, fragment): """ Secure handling: drop entire datagram on overlap. """ log_alert("Dropping datagram due to fragment overlap", buffer.key) # Generate ICMP error if we have first fragment if buffer.first_fragment_header: send_icmp_param_problem(buffer.first_fragment_header) # Destroy buffer and free resources destroy_reassembly_buffer(buffer) # Update statistics stats.overlapping_fragments_dropped += 1Overlapping fragments are a red flag for attack activity. In security-conscious environments, not only should overlapping datagrams be dropped, but the source IP should be logged and potentially blocked. Legitimate traffic simply does not produce overlapping fragments.
Reassembly consumes system resources: memory for buffers, CPU for processing, and data structure overhead. Understanding performance implications helps in system design and capacity planning.
| Parameter | Default | Description |
|---|---|---|
| ipfrag_high_thresh | 4 MB | Max memory for all reassembly buffers; new fragments dropped when exceeded |
| ipfrag_low_thresh | 3 MB | When high threshold hit, purge down to this level |
| ipfrag_time | 30 seconds | Reassembly timeout period |
| ipfrag_max_dist | 64 | Maximum packet reordering distance (optimization) |
| ipfrag_secret_interval | 600 seconds | How often to regenerate hash secret (security) |
123456789101112131415
# View current fragment settingssysctl -a | grep ipfrag # Common output:net.ipv4.ipfrag_high_thresh = 4194304net.ipv4.ipfrag_low_thresh = 3145728net.ipv4.ipfrag_time = 30net.ipv4.ipfrag_max_dist = 64 # Monitor fragment statisticscat /proc/net/snmp | grep Ip# Relevant fields: ReasmTimeout, ReasmReqds, ReasmOKs, ReasmFails # Detailed fragment statscat /proc/net/ip_conntrack_stats # If conntrack enabledThe best performing reassembly is no reassembly at all. Design networks and applications to avoid fragmentation: use Path MTU Discovery, configure appropriate MSS, and ensure MTU consistency across your network. Reassembly should be an exception, not the norm.
Reassembly has been a rich target for attacks over the decades. Understanding these attack patterns is essential for security engineering and helps appreciate why modern implementations include various protections.
Modern Defenses:
Operating systems and security devices now implement multiple layers of protection:
Don't rely solely on host reassembly defenses. Implement fragment protection at multiple layers: edge firewalls should drop/rate-limit fragments, IPS systems should detect fragment attacks, and hosts should have hardened reassembly implementations. Layered defense provides resilience against novel attack variants.
Reassembly completes the fragmentation lifecycle, transforming a collection of fragments back into the original datagram. This process, while conceptually simple, involves significant complexity in implementation, error handling, and security considerations.
Module Complete:
You have now mastered IP fragmentation comprehensively:
This knowledge forms a crucial foundation for understanding IP networking, troubleshooting connectivity issues, and designing secure, high-performance networks.
Congratulations! You have achieved comprehensive mastery of IP fragmentation—from the architectural reasons it exists, through the header fields that control it, to the complex process of reassembling fragments at the destination. You can now analyze fragmentation scenarios, diagnose MTU problems, understand security implications, and design networks that minimize fragmentation for optimal performance.