1. 从一次诡异的网络丢包说起为什么需要报文分片几年前我负责维护一个内部文件传输服务用户反馈从某个特定机房下载大文件时速度奇慢无比而且经常中断。用常规的ping和traceroute工具检查链路延迟和路由都正常。抓包分析后发现了一个有趣的现象在传输路径的某个中间节点出现了大量重复的、标志位异常的ICMP报文指向同一个目标IP。这让我立刻警觉起来——问题很可能出在IP层的报文分片与重组上。我们传输的文件通常会被封装成1500字节左右的以太网帧这是MTU的典型值。但当数据包需要穿越一个MTU更小的网络链路比如某些PPPoE或隧道环境时一个“大个子”IP数据报就必须被“切”成几个“小个子”分片才能继续旅行。接收方则需要根据分片携带的“身份信息”和“顺序信息”把所有分片重新拼装回原始的数据报。这个过程如果出了问题轻则重传、降速重则直接导致连接失败。而IP头部中负责管理这一切“切割”与“拼装”工作的正是那看似不起眼的16位标识、3位标志和13位片偏移字段。很多人对它们的理解停留在概念层面一旦在实际网络排障中遇到往往不知从何下手。今天我们就彻底拆解这三个字段不仅讲清楚协议规定更结合抓包实例和排障经验让你下次遇到类似问题时能一眼看穿本质。2. 庖丁解牛IP报头中的分片三剑客要理解分片我们必须先回到IP数据报的标准格式。在IPv4报头的20字节固定部分中有以下几个字段与分片直接相关总长度 (Total Length)16位指整个IP数据报头部数据的总字节数。这是决定是否需要分片的第一个判官。标识 (Identification)16位关键字段之一。标志 (Flags)3位控制分片行为的核心开关。片偏移 (Fragment Offset)13位决定分片顺序的导航员。其中后三个字段是分片机制的“铁三角”我们重点剖析。2.1 16位标识字段同一个数据报的“身份证号”这个字段占16位取值范围是0~65535。它的核心作用非常简单标识属于同一个原始IP数据报的所有分片。生成规则发送主机在构造每一个需要传输的IP数据报时都会为其分配一个唯一的标识值。通常每发一个数据报这个值就递增1循环使用。重要的是如果这个原始数据报被分片那么它产生的所有分片其IP头部的“标识”字段值都必须与原始数据报的标识值完全相同。重组依据接收方在收到一堆分片时会依据“源IP地址”、“目的IP地址”、“协议号”和“标识”字段这四个元素来判断哪些分片是“一家人”应该被拼接到一起。你可以把它想象成物流公司运送一套拆散的家具每个包裹箱上都贴着同一个唯一的“订单号”仓库人员凭这个订单号就知道哪些箱子该拼成一套。注意这个标识符只在源主机和目的主机之间有意义。网络中的路由器在转发时不会修改它但路由器自己如果产生了新的IP数据报比如发送ICMP差错报文它会为自己生成的数据报分配新的标识符与它转发的数据报标识符无关。2.2 3位标志字段控制分片行为的“开关”标志字段虽然只有3位但每一位都至关重要。在协议标准中目前只使用了高两位最低位保留未用。位位置 (从高位到低位)名称含义与作用位 2 (最高位)保留位 (Reserved Bit)必须设置为0。位 1不分片位 (DF, Don‘t Fragment)值为1时表示“禁止分片”。如果数据报长度超过了路径上某段链路的MTU路由器将丢弃该数据报并通常向源端发送一个“ICMP目的地不可达需要分片但设置了DF位”的差错报文。值为0时表示“允许分片”。位 0 (最低位)更多分片位 (MF, More Fragments)值为1时表示“这不是最后一个分片后面还有兄弟”。值为0时表示“这是原始数据报的最后一个分片或者该数据报根本没有被分片”。DF位的实战意义 DF位常用于路径MTU发现PMTUD过程。例如TCP协议在建立连接后为了获得最高效率会尝试发送一个设置了DF位的、大小等于本地MTU的数据包。如果路径上某处MTU更小该数据包会被丢弃并返回ICMP差错报文源主机从而得知当前路径的MTU上限并调整后续发送的数据包大小避免被中间设备分片。因为分片和重组会消耗路由器/主机的CPU资源并增加丢包导致整个数据报失效的风险一个分片丢失整个原始数据报都要重传。MF位的实战意义 MF位是接收方进行重组的关键信号。接收方会持续收集MF1的分片直到收到一个MF0的分片才知道原始数据报的所有分片已经收集完毕可以开始重组。如果一直收不到MF0的分片接收方在等待超时后会丢弃所有已收到的该数据报的分片。2.3 13位片偏移字段分片的“拼图索引”片偏移字段占13位它指明了当前分片所携带的数据在原始未分片IP数据报的数据部分中的起始位置。单位它的单位不是字节而是8字节64位块。也就是说片偏移值乘以8才是实际的字节偏移量。例如片偏移为100则表示该分片的数据从原始数据报数据部分的第800字节开始。计算与作用由于每个分片除了最后一个的数据部分长度必须是8字节的整数倍以满足偏移量的计算路由器在分片时会进行相应的填充。接收方根据每个分片的“标识”找到同伴再根据“片偏移”字段像拼图一样将它们按顺序排列起来。范围13位最大能表示81912^13 - 1乘以8就是65528字节。这意味着一个IP数据报的数据部分最大不能超过65528字节加上20字节IP头总长度不超过65535字节这与16位“总长度”字段的限制是一致的。3. 一次完整的分片与重组过程推演让我们通过一个具体例子把理论串联起来。假设主机A要发送一个总长度为4000字节的IP数据报IP头20字节数据部分3980字节穿越一个MTU为1500字节的网络链路。步骤1判断是否需要分片路径MTU为1500字节减去标准的20字节IP头每个分片能承载的数据最多为1480字节。原始数据报数据部分3980字节 1480字节因此必须分片。步骤2计算分片数量与大小我们需要将3980字节的数据切成若干块每块除最后一块必须是8字节的整数倍且尽量接近1480字节。第一个分片承载0~1479字节的数据1480字节。因为1480 ÷ 8 185是整数符合要求。第二个分片承载1480~2959字节的数据1480字节。第三个分片承载2960~3979字节的数据1020字节。1020 ÷ 8 127.5不是整数这里有个关键最后一个分片的数据长度不需要是8字节的整数倍。片偏移的计算只关心起始位置结束位置由“总长度”字段决定。步骤3为各分片填充IP头部字段假设原始数据报的标识为0xabcd。分片1标识0xabcd(与原始相同)标志MF1 (后面还有分片) DF0 (允许分片)片偏移0 (起始位置为0)总长度1480(数据) 20(头) 1500分片2标识0xabcd标志MF1 DF0片偏移185 (1480 / 8 185)总长度1500分片3标识0xabcd标志MF0 (这是最后一个) DF0片偏移370 (2960 / 8 370)总长度1020(数据) 20(头) 1040步骤4接收方重组主机B收到三个分片后根据源IP、目的IP、协议和标识0xabcd识别出它们属于同一个原始数据报。检查标志位发现分片1和2的MF1知道还有后续收到分片3时MF0知道分片已到齐。根据片偏移0, 185, 370将三个分片的数据部分按顺序拼接偏移0的数据放在最前接着是偏移185的最后是偏移370的。重组完成后将完整的3980字节数据交给上层协议处理。4. 抓包实战用Wireshark透视分片报文理论再扎实不如看一眼真实的数据包。我们使用Wireshark来观察分片报文。你可以通过ping -l 4000 目标IP命令Windows或ping -s 4000 目标IP命令Linux数据部分4000加上8字节ICMP头20字节IP头总IP长度4028来制造一个需要分片的大ICMP请求报文。在Wireshark中抓取这些报文你会看到类似下面的显示No. Time Source Destination Protocol Length Info 1 0.000000 192.168.1.10 192.168.1.1 ICMP 1514 Echo (ping) request (fragmented) 2 0.000010 192.168.1.10 192.168.1.1 IPv4 1514 Fragmented IP protocol (protoICMP 1, off185, ID0x1234) 3 0.000020 192.168.1.10 192.168.1.1 IPv4 1046 Fragmented IP protocol (protoICMP 1, off370, ID0x1234)Info列解读Wireshark很智能地将分片归类显示。第一行通常显示为“Echo request (fragmented)”并附带第一个分片的详情。点击第二、三个报文你会发现Wireshark的协议解析器不再显示“ICMP”而是显示“Fragmented IP protocol”因为它无法解析不完整的传输层信息。关键字段查看在IP层详情展开中重点关注Identification: 0x1234 (4660)三个分片的这个值相同。Flags: 0x2000, More fragments对应二进制010即DF0 MF1。Fragment offset: 185表示偏移量。对于最后一个分片Flags会显示0x0000或0x0000, Don‘t fragment这里Wireshark显示可能有歧义实际上MF0DF0Fragment offset为370。一个重要的过滤技巧在Wireshark过滤栏输入ip.flags.mf 1可以过滤出所有“还有更多分片”的报文这在排查因丢失最后一个分片MF0而导致重组失败的问题时非常有用。5. 避坑指南分片机制引发的典型网络问题与排查思路理解了原理我们就能诊断和解决很多实际问题。文章开头提到的丢包问题最终定位就是由于路径上的一台老旧防火墙错误地处理了分片报文导致重组混乱。5.1 问题一PMTUD黑洞与连接卡顿现象某些TCP连接如HTTPS在建立后发送少量数据正常但一旦开始传输大块数据连接就会卡住或重置。根因这是经典的“PMTUD黑洞”问题。发送方开启了PMTUD发出DF置位的探测包但路径上的某个设备如错误配置的防火墙丢弃了需要分片的大包却没有按照协议规定返回“ICMP Destination Unreachable (Fragmentation Needed)”报文。发送方收不到这个反馈就认为路径MTU足够大继续发送大包结果这些包都在那个设备处被静默丢弃导致连接超时中断。排查在客户端使用ping -f -l size 目标命令Windows或ping -M do -s size 目标命令Linux测试。-f或-M do表示设置DF位。逐渐增加size值从1500开始试直到ping不通。如果某个尺寸突然不通且没有收到“需要分片但DF位已设置”的ICMP回复很可能遇到了PMTUD黑洞。解决方案通常需要调整网络设备防火墙的配置允许相关的ICMP差错报文通过或者在不支持PMTUD的网络中在终端主机上手动设置一个较小的MTU。5.2 问题二分片丢失与重组超时现象UDP-based的应用如DNS、视频流、定制协议在大数据传输时丢包率异常高但小数据包正常。根因一个数据报被分成N个分片传输。只要其中任意一个分片丢失整个原始数据报就无法重组。接收方等待一段时间通常是30秒或60秒后会丢弃所有已收到的属于该数据报的其他分片。对于无连接的UDP这直接导致数据丢失对于TCP会触发超时重传但重传的是整个TCP段可能再次被分片效率低下。排查在收发两端同时抓包。在发送端观察一个大包是否被分成了多个小包发出。在接收端使用Wireshark过滤器ip.flags.mf 1观察是否持续收到MF1的分片却迟迟收不到对应的MF0的最后一个分片。或者检查是否有大量相同标识符的分片到来却没有对应的上层协议如UDP报文被解析出来。对比两端抓包找出在路径中丢失的具体是哪个分片。解决思路是优化网络路径质量或者在应用层尽量避免发送超过路径MTU的数据包这正是TCP的MSS协商和UDP应用需要注意的地方。5.3 问题三分片重叠攻击与安全设备策略现象网络入侵检测系统IDS或防火墙频繁告警或某些服务访问不稳定。根因分片机制可能被用于躲避安全设备的检测或发动攻击。例如重叠分片攻击者故意构造片偏移有重叠的分片。不同的操作系统对重叠分片的处理策略不同“先到先得”或“后到优先”这可能被用来绕过基于完整数据包内容进行模式匹配的IDS。极小的分片构造一个极小的分片将TCP报头如端口号、标志位拆分到第二个分片中。一些简单的包过滤防火墙如果只检查第一个分片就可能错误地放行后续有害的分片。排查与应对现代的安全设备下一代防火墙、IPS大多具备“分片重组”功能即在设备内部先将分片重组为完整数据报再进行安全策略检查。确保此功能已开启。在网络设备上可以考虑设置分片包的处理策略例如直接丢弃所有分片包对某些服务影响大或限制分片速率。对于关键服务器在操作系统层面可以调整内核参数强化对异常分片如偏移为0但MF0的分片的处理。6. 现代网络中的最佳实践与思考随着网络基础设施的升级和协议的演进报文分片在今天更多地被视为一种“备用机制”或“需要警惕的潜在问题点”。应用层规避是上策最根本的解决方法是让端系统发送的数据包不超过路径MTU。TCP通过MSS最大报文段长度协商自动完成这一点。对于UDP应用程序员需要有意识地控制发送数据块的大小通常建议将应用层数据包控制在路径MTU - IP头 - 传输层头以内例如以太网环境下UDP数据最好小于1500-20-81472字节。PMTUD的启用与备用方案确保PMTUD在网络中能正常工作ICMP差错报文不被全盘屏蔽。对于可能存在的PMTUD黑洞操作系统有备用机制如TCP的“MSS Clamping”或在连接失败后自动回退到较小的MTU值。虚拟化与隧道网络中的MTU问题在VXLAN、GRE、IPsec等隧道网络中原始数据包外面会被加上新的报文头这很容易导致“隧道内”的数据包大小超过底层物理网络的MTU。这就需要仔细计算和设置隧道接口的MTU或者启用隧道协议的分片功能。处理这类问题必须清晰地画出“报文封装图”逐层计算头部开销。回过头看最初的那个文件传输故障根本原因就是传输路径上经过了一个MTU配置不匹配的隧道而中间某个节点的防火墙对分片重组处理有缺陷导致重组失败进而引发上层协议超时和重传。在调整了防火墙策略并明确了路径MTU后问题得以解决。所以深入理解IP分片这三个字段不仅仅是掌握一个协议细节更是获得了一把钥匙它能帮你打开网络世界的一扇暗门门后连接着性能优化、问题排查和网络安全这些至关重要的领域。下次再看到Wireshark里那些“Fragmented IP protocol”的报文时希望你能够会心一笑清楚地知道它们从何而来因何而生又将去往何处。