Loading content...
When a jigsaw puzzle is manufactured, each piece is numbered on the back so workers can verify completeness and locate any missing pieces. IP fragmentation uses an analogous system: the Fragment Offset field tells the destination exactly where each fragment's data belongs in the original datagram.\n\nWithout Fragment Offset, reassembly would be impossible—fragments could arrive out of order, be delayed by different routing paths, or even be duplicated. The offset provides the essential positioning information that transforms a jumble of fragments back into the original packet.
By the end of this page, you will master the Fragment Offset field completely: how it's calculated, why it uses 8-byte units, how it enables reassembly, and how to trace through fragmentation scenarios step-by-step. You'll be able to analyze packet captures and calculate fragment boundaries with confidence.
The Fragment Offset field occupies bits 19-31 (counting from 0) of the IPv4 header—a 13-bit field within the 32-bit word that also contains the Flags field.
Using 8-byte units instead of bytes serves two purposes: (1) It extends the range—13 bits can address 65,528 bytes instead of just 8,191 bytes, covering the maximum 65,535-byte IP datagram. (2) It forces fragment boundaries to 8-byte alignments, simplifying reassembly buffer management and ensuring fragments can be placed in memory without complex partial-byte handling.
Let's trace through a complete fragmentation example to understand how Fragment Offset values are determined.\n\nScenario:\n- Original IP datagram: 4000 bytes total (20-byte header + 3980 bytes data)\n- MTU limit: 1500 bytes\n- Maximum data per fragment: 1500 - 20 = 1480 bytes\n- 1480 must be divisible by 8 ✓ (1480 ÷ 8 = 185)
| Fragment | Data Bytes | Byte Range | Offset Value | Offset (bytes) | MF Flag |
|---|---|---|---|---|---|
| 1 | 1480 | 0 - 1479 | 0 | 0 | 1 (more) |
| 2 | 1480 | 1480 - 2959 | 185 | 1480 | 1 (more) |
| 3 | 1020 | 2960 - 3979 | 370 | 2960 | 0 (last) |
Step-by-step calculation:\n\nFragment 1:\n- Carries bytes 0-1479 of original data (1480 bytes)\n- Fragment Offset = 0 / 8 = 0\n- More Fragments (MF) = 1 (there are more fragments)\n- Total fragment size: 1480 + 20 = 1500 bytes\n\nFragment 2:\n- Carries bytes 1480-2959 of original data (1480 bytes)\n- Fragment Offset = 1480 / 8 = 185\n- More Fragments (MF) = 1 (still more to come)\n- Total fragment size: 1480 + 20 = 1500 bytes\n\nFragment 3:\n- Carries bytes 2960-3979 of original data (1020 bytes)\n- Fragment Offset = 2960 / 8 = 370\n- More Fragments (MF) = 0 (this is the last fragment)\n- Total fragment size: 1020 + 20 = 1040 bytes
Fragment Offset = (Starting byte position in original data) ÷ 8\n\nFor any fragment N (0-indexed): Offset = (N × MaxPayload) ÷ 8\n\nWhere MaxPayload = MTU - IP_Header_Size, rounded down to multiple of 8.
The requirement that Fragment Offset is measured in 8-byte units has critical implications for fragmentation behavior.
Example: MTU that doesn't align naturally\n\nSuppose MTU = 1006 bytes (an odd historical value):\n- Available for data: 1006 - 20 = 986 bytes\n- 986 ÷ 8 = 123.25 (not a whole number)\n- Must round down: 123 × 8 = 984 bytes per fragment\n- Each fragment (except last): 984 bytes of data + 20 bytes header = 1004 bytes\n- 2 bytes of MTU 'wasted' per fragment due to alignment
Forgetting to align fragment data sizes to 8-byte boundaries is a common implementation error. This causes reassembly bugs: fragments appear to overlap (if too much data included) or leave gaps (if too little). The receiving host must reject such malformed fragments.
Fragment Offset alone isn't sufficient for reassembly—fragments from different original datagrams could have the same offsets. The Identification field links fragments belonging to the same original datagram.
Reassembly key = (Source IP, Destination IP, Protocol, Identification)\n\nThe receiving host uses this 4-tuple to group fragments:\n\n1. Fragment arrives with given 4-tuple\n2. Host checks for existing reassembly buffer with same 4-tuple\n3. If found: add fragment to buffer based on Fragment Offset\n4. If not found: create new reassembly buffer\n5. When all fragments received (no gaps, last fragment identified): reassemble and deliver\n\nTimeout consideration:\n\nIf not all fragments arrive within a timeout period (typically 15-60 seconds), the partial datagram is discarded. This prevents zombie reassembly buffers from consuming memory indefinitely.
| Source IP | Dest IP | Protocol | ID | Offset | MF | Interpretation |
|---|---|---|---|---|---|---|
| 192.168.1.1 | 10.0.0.1 | TCP (6) | 12345 | 0 | 1 | Datagram A, Fragment 1 |
| 192.168.1.2 | 10.0.0.1 | TCP (6) | 12345 | 0 | 1 | Datagram B, Fragment 1 (different source) |
| 192.168.1.1 | 10.0.0.1 | TCP (6) | 12345 | 185 | 0 | Datagram A, Fragment 2 |
| 192.168.1.2 | 10.0.0.1 | TCP (6) | 12345 | 185 | 0 | Datagram B, Fragment 2 |
With only 16 bits, Identification values recycle every 65,536 datagrams. On high-speed links, this can happen within seconds. If old fragments are still in transit when IDs recycle, misassembly can occur. Modern hosts use randomized Identification values rather than sequential counters to mitigate this, and RFC 6864 clarified when the field must be unique.
Understanding Fragment Offset is essential for analyzing network captures. Let's examine how this appears in real tools.
1234567891011121314151617181920212223242526
Internet Protocol Version 4, Src: 192.168.1.100, Dst: 10.0.0.50 0100 .... = Version: 4 .... 0101 = Header Length: 20 bytes (5) Total Length: 1500 Identification: 0x1a2b (6699) Flags: 0x2000, More fragments 0... .... .... .... = Reserved bit: Not set .0.. .... .... .... = Don't fragment: Not set ..1. .... .... .... = More fragments: Set Fragment offset: 0 Time to live: 64 Protocol: TCP (6) [Reassembled IPv4 in frame: 45] # Second fragment: Identification: 0x1a2b (6699) <- Same as first Flags: 0x2000, More fragments Fragment offset: 185 <- 185 × 8 = 1480 bytes [This is fragment 2 of 3] # Last fragment: Identification: 0x1a2b (6699) <- Same as first Flags: 0x0000 ..0. .... .... .... = More fragments: Not set Fragment offset: 370 <- 370 × 8 = 2960 bytes [This is the last fragment]Reading fragment information:\n\n- Identification: Unique ID linking all fragments (6699 in example)\n- Fragment offset: Position in 8-byte units (Wireshark shows raw value; multiply by 8 for bytes)\n- Flags [+]: The '+' in tcpdump indicates More Fragments flag is set\n- frag notation: Shows ID, fragment length, offset in bytes, and '+' if more fragments\n\nWireshark reassembly:\n\nWireshark automatically reassembles fragments and shows:\n- [Reassembled IPv4 in frame: X] - tells you which captured frame contains the complete reassembled datagram\n- [This is fragment N of M] - fragment position\n- The complete datagram appears on the last fragment
ip.frag_offset > 0 shows non-first fragments\nip.flags.mf == 1 shows fragments with More Fragments set\nip.frag_offset > 0 or ip.flags.mf == 1 shows all fragment-related traffic\n\nThese filters help quickly identify fragmentation in captures.
A fragment can itself be fragmented if it encounters a smaller MTU downstream. This creates complex scenarios where Fragment Offset values must be carefully computed.
Scenario: Cascade fragmentation\n\nOriginal datagram: 4000 bytes (20 header + 3980 data)\nRouter R1 (MTU 1500): Fragments into 3 pieces\nRouter R2 (MTU 500): Must further fragment each piece
| Fragment | Data | Original Byte Range | Offset | MF |
|---|---|---|---|---|
| A | 1480 bytes | 0-1479 | 0 | 1 |
| B | 1480 bytes | 1480-2959 | 185 | 1 |
| C | 1020 bytes | 2960-3979 | 370 | 0 |
| Original Frag | Sub-Fragment | Data | Byte Range (in original) | New Offset | MF |
|---|---|---|---|---|---|
| A (offset 0) | A1 | 480 bytes | 0-479 | 0 | 1 |
| A (offset 0) | A2 | 480 bytes | 480-959 | 60 | 1 |
| A (offset 0) | A3 | 480 bytes | 960-1439 | 120 | 1 |
| A (offset 0) | A4 | 40 bytes | 1440-1479 | 180 | 1 |
| B (offset 185) | B1 | 480 bytes | 1480-1959 | 185 | 1 |
| B (offset 185) | B2 | 480 bytes | 1960-2439 | 245 | 1 |
| B (offset 185) | B3 | 480 bytes | 2440-2919 | 305 | 1 |
| B (offset 185) | B4 | 40 bytes | 2920-2959 | 365 | 1 |
| C (offset 370) | C1 | 480 bytes | 2960-3439 | 370 | 1 |
| C (offset 370) | C2 | 480 bytes | 3440-3919 | 430 | 1 |
| C (offset 370) | C3 | 60 bytes | 3920-3979 | 490 | 0 |
Key observations:\n\n1. Offset addition: When fragment B (offset 185 = 1480 bytes) is further fragmented, its sub-fragments have offsets relative to the ORIGINAL datagram: 1480, 1960, 2440, 2920 bytes.\n\n2. MF flag propagation: The last sub-fragment of fragment A has MF=1 because fragment A was not the last original fragment. Only C3 (last sub-fragment of last fragment) has MF=0.\n\n3. Destination sees all 11 fragments: The receiving host doesn't know about the cascade; it just sees 11 fragments with offsets ranging from 0 to 490 (× 8 = 3920 bytes).\n\n4. Same Identification: All 11 fragments share the same Identification value, enabling reassembly.
With 11 fragments instead of 3, the probability of complete delivery drops significantly. If 1% packet loss per hop, probability of losing at least one fragment over 5 hops increases dramatically. This is why Path MTU Discovery and DF bit are preferred over relying on fragmentation.
Understanding edge cases in Fragment Offset handling is important for both network security and implementation correctness.
Reassembly validation checks:\n\nCompliant IP stacks must validate:\n\n1. No fragment exceeds maximum datagram size:\n - offset × 8 + fragment_data_length ≤ 65,515 (65,535 - 20)\n\n2. Last fragment consistency:\n - If MF=0, this determines total datagram size\n - All fragments must fit within this total\n\n3. No overlaps:\n - Fragment byte ranges must not conflict\n - Modern policy: drop entire datagram on overlap\n\n4. Complete coverage:\n - No gaps between offset 0 and end of last fragment\n - All positions must have data before reassembly
12345678910111213141516171819202122232425262728293031323334
def validate_fragment(frag, reassembly_buffer): """Validate incoming fragment for security and correctness""" # Calculate byte range start_byte = frag.offset * 8 end_byte = start_byte + frag.data_length # Check 1: Maximum datagram size if end_byte > 65515: drop_fragment("exceeds maximum datagram size") return False # Check 2: Overlap detection for existing in reassembly_buffer.fragments: if ranges_overlap(start_byte, end_byte, existing.start, existing.end): drop_entire_datagram("overlapping fragments") return False # Check 3: If last fragment, verify total size consistent if not frag.more_fragments: expected_total = end_byte if reassembly_buffer.expected_total and \ reassembly_buffer.expected_total != expected_total: drop_entire_datagram("inconsistent last fragment") return False reassembly_buffer.expected_total = expected_total # Check 4: First fragment minimum size (security) if frag.offset == 0 and frag.data_length < 68: # May not contain full TCP/UDP header log_warning("suspicious small first fragment") return TrueFragment handling has been a rich source of security vulnerabilities. Teardrop, Bonk, Boink, and numerous other attacks exploited faulty reassembly logic. Modern networking stacks apply strict validation, but unusual fragment patterns should always raise suspicion in security monitoring.
You now have comprehensive knowledge of the Fragment Offset field—the essential mechanism that enables IP datagram reassembly. Let's consolidate with key formulas and takeaways.
byte_position = fragment_offset × 8max_data = floor((MTU - IP_header_size) / 8) × 8offset = (N × max_data) / 8ceil(total_data / max_data)N × (max_data + header) + (last_frag_data + header)(N - 1) × IP_header_sizeWhat's Next:\n\nWe've examined what the Fragment Offset field does. Next, we'll explore the MF (More Fragments) and DF (Don't Fragment) flags—the control bits that determine whether fragmentation should occur and how to identify the final fragment in a sequence.
You now understand Fragment Offset deeply—from the header field structure through calculation procedures, alignment constraints, nested fragmentation, and edge cases. This knowledge is essential for packet analysis, network troubleshooting, and understanding fragmentation-related security issues.