IP报文分片与重组原理及实现分析
引用:
- ppp/net/packet/IPFragment.h
- ppp/net/packet/IPFragment.cpp
1. IP分片原理
当IP数据包大小超过MTU(最大传输单元)时,路由器/主机将其分割为多个片段传输,每个片段包含:
- IP头信息(除分片相关字段外与原始包一致)
- 分片控制字段:
- 标志位(Flags):
MF
(More Fragments):表示后续还有分片DF
(Don’t Fragment):禁止分片
- 分片偏移(Fragment Offset):以8字节为单位标识片段位置
- 标志位(Flags):
原始IP包结构:
+-----------------+-----------------------+
| IP头(20-60字节) | 数据载荷 |
+-----------------+-----------------------+分片后:
分片1:+-----------------+---------+ (MF=1, Offset=0)
分片2:+-----------------+---------+ (MF=1, Offset=N)
...
分片N:+-----------------+---------+ (MF=0, Offset=M)
2. 关键类关系图
3. 分片生成流程(Output)
4. 分片重组流程(Input)
5. 关键数据结构
分片缓存表(SubpackageTable):
struct Subpackage {UInt64 FinalizeTime; // 超时时间戳vector<IPFramePtr> Frames; // 有序分片列表
};unordered_map<Int128, Subpackage::Ptr> IPV4_SUBPACKAGES_;
分片Key生成算法:
Int128 key = (Int128)Source | (Destination << 32) | (Id << 64);
6. 分片重组验证逻辑
bool fullFragementOffset = true;
int nextOffset = 0;for (分片 in 有序列表) {if (分片.Offset != nextOffset) { fullFragementOffset = false;break;}nextOffset += 分片.Payload长度;
}if (fullFragementOffset && 末片.MF==0) {// 执行重组
}
7. 分片超时管理
8. 分片/重组性能优化
-
内存管理:
- 使用
BufferswapAllocator
减少内存碎片 - 分片数据共享原始缓冲区(wrap_shared_pointer)
- 使用
-
算法优化:
- 分片插入使用二分查找(O(log n))
- 重组检查使用增量偏移计算
-
安全防护:
- 分片超时强制清理(默认1秒)
- 分片偏移范围校验
9. 协议处理差异
协议 | 封装方式 | 校验机制 |
---|---|---|
ICMP | 直接封装在IP载荷中 | 标准IP校验和 |
UDP | 伪头部参与校验和计算 | 包含源/目的IP的校验和 |
TCP | (未展示) 需要序列号重组 | 复杂流重组逻辑 |
10. 关键代码实现
分片生成核心逻辑:
int IPFrame::Subpackages(vector<IPFramePtr>& out, const IPFramePtr& packet) {while (剩余数据 > MTU) {auto fragment = make_shared<IPFrame>();fragment->Flags = IPFlags::IP_MF; // 设置MF标志fragment->SetFragmentOffset(current_offset);// ... 数据切割 ...out.push_back(fragment);}// 处理最后分片(清除MF标志)
}
重组缓冲区构建:
MemoryStream ms(buffer, total_size);
for (auto& frame : subpackage->Frames) {ms.Write(frame->Payload->Buffer, frame->Payload->Length);
}
总结
该实现完整覆盖了IP分片/重组核心功能:
- 分片生成:按MTU切割数据,动态设置MF/Offset
- 分片重组:基于五元组Key缓存,有序验证连续性
- 资源管理:智能指针自动释放+超时清理
- 协议支持:统一处理ICMP/UDP等上层协议
改进建议:
- 增加分片重叠处理(RFC815)
- 实现分片攻击防护(如偏移量验证)
- 支持IPv6分片扩展头