在Wireshark里翻包的时候,有一种情况特别容易让刚上手的同学懵圈:数据包列表里明明显示的是UDP,双击进去却发现负载部分只有几个字节,Frame层还挂着一行灰色小字——[Packet size limited during capture: 512 bytes captured (1200 bytes original)]。对,这就是TRUNC,一句话解释就是:这个UDP包在抓包那一刻就被“腰斩”了。
这篇文章要聊的,正是这个看起来像报错、其实属于“证据不完整”的TRUNC标志。它离我们并不远:用tcpdump远程抓包忘了设snaplen默认值、在服务器上用短快照长度抓UDP流量、排查音视频卡顿的时候看到RTP包被截断……都可能是它出场的时候。我会从TRUNC的识别方法讲起,分析UDP数据包被截断的三种典型原因,再走一遍一次UDP打流丢包问题的完整排查过程,最后给出抓包参数的设置建议和补救思路。适合正在做网络抓包分析、搞UDP传输调优、或者第一次在Wireshark里看到“Packet size limited during capture”的读者。
1. 认识TRUNC:数据包被“截断”后Wireshark会告诉你什么
1.1 捕获长度与原始长度:从一列数字里读出断裂痕迹
要理解TRUNC,先分清两个概念:frame.cap_len(捕获长度)和frame.len(线上原始长度)。正常抓包时,这两个值应该相等;一旦frame.len>frame.cap_len,就说明包在写入pcap文件之前就被砍掉了一截。
打开任意一个包含截断包的pcap文件,你会看到两种明显信号:
- 在包列表的Info列里,Wireshark会直接追加提示文字,最常见的就是
[Packet size limited during capture]。 - 在Packet Details面板的Frame层,会有一行类似
[Packet size limited during capture: 512 bytes captured (1200 bytes original)]的说明,括号里前半部分是捕获长度,后半部分是原始长度。
很多人在这个位置会犯一个低级错误:只看Length列,发现是512,就以为这个UDP包本身就只有512字节,结果把后面所有分析都带偏了。所以我拿到一个陌生抓包文件,第一件事是先把frame.cap_len和frame.len这两列都调出来,快速扫一遍有没有明显差值。
1.2 为什么说TRUNC是“不完整证据”而非“包错误”
TRUNC和FCS错误、Checksum错误完全不是一回事。CRC错误说明线路传输过程中有比特翻转,CheckSum错误说明数据内容可能被修改;而TRUNC只代表“你没有抓到完整数据”,并不一定代表网络本身有问题。它更像是你拿到一张被剪掉半边的地图,能判断出大概位置,但按地图上的距离导航就会翻车。
具体到UDP包上,被截断后你通常还能看到完整的以太网头、IP头和UDP头,因为这些内容都排在包的最前面。但UDP负载里的业务数据、应用层协议字段(比如RTP的时间戳和负载类型、NTP的参考时间戳、DNS的资源记录),甚至某些情况下UDP头之后的扩展字段,都可能缺失。分析这类包的时候,最怕的就是拿着残缺信息去推演完整逻辑——比如看到RTP包序号没有连续就断言丢包,结果发现只是抓包截断造成的假象。
2. 谁在制造TRUNC:UDP数据包被截断的三种典型成因
2.1 抓包工具的snaplen:人为设定的“腰带”
snaplen(snapshot length,快照长度)是抓包时最重要的参数之一,它规定了每个数据包最多从线路上拷贝多少字节到缓冲区。如果这个值设置得太小,超过的部分就会被直接丢弃,产生TRUNC。
Wireshark图形界面里,Capture Options窗口有一个“Limit each packet to”输入框,默认是65535字节;命令行工具tcpdump则用-s参数控制。常见翻车方式:
# 只想抓包头做快速验证,结果把负载全丢了 tcpdump -i eth0 udp port 1234 -s 96 -w ntp_debug.pcap # 或者干脆不写-s,用某些老版本默认的68字节 tcpdump -i eth0 udp port 1234 -w test.pcap-s 96意味着每个包只保留前96字节,已经超过了以太网头+IP头+UDP头总共42字节(或者VLAN场景54字节),所以包头字段基本都在,但任何超过这个长度的UDP负载都会被截断。我见过把snaplen设成128抓SIP信令,结果SDP消息体被砍得七零八落,最后还要用“分片重组”的歪招去补数据——非常被动。
2.2 IP分片重组失败:UDP包“装不进”一个帧
第二种TRUNC成因不太容易一眼看出来,它和IP分片有关。UDP本身没有自动分段能力,如果应用层一次性发送的UDP数据报超过了链路MTU(典型以太网是1500字节),IP层就会把它拆成多个分片传输。抓包文件里会看到多个IP分片报文,Wireshark会尝试将它们重组为完整的UDP数据报。
如果某个分片因为网络拥堵、丢包、乱序等原因没有被抓到,或者抓包点位于两台设备中间导致只看到一部分分片,Wireshark就无法完成重组,此时UDP层会显示一个“Reassembly error”,同时在Expert Info里出现类似:
New fragment overlaps old fragment (strings at offset)这种状况和snaplen截断不同,它不是被动地砍长度,而是因为分片不齐导致重组后的数据报缺了一块。比如一个原始UDP载荷为3000字节的包,在以太网上被拆成3个分片,但你只抓到了前两个,重组结果可能就是第一个分片+第二个分片,然后标记为“截断”。从效果上看,用户同样会看到UDP长度不匹配、数据不完整,但根因完全是另一套。
2.3 巨型帧、GRO/LRO与“超长包”的怪现象
第三种成因在现代服务器上越来越常见:网卡开启了LRO(Large Receive Offload)或GRO(Generic Receive Offload),内核驱动会把多个连续的数据包在网卡层面聚合成一个“超级大包”,再提交给抓包工具。于是Wireshark里会出现一个长度明显超过MTU的怪物包,比如Length显示2896、4500甚至更大。
这种聚合后的超大包,如果超过了抓包设置的快照长度,也会被截断。更麻烦的是,即使snaplen足够大,很多分析工具对超过65535字节的包也会表现异常,因为IP头里的Total Length字段是16位,最大就65535,UDP头里的Length字段同理。GRO产生的超长包实际是多个包的payload拼接,协议解析会错乱,看起来就像“UDP装不下了”。
要验证是不是offload造成的,可以对比同一台机器上关闭GRO/LRO前后的抓包结果。Linux下可以用:
ethtool -K eth0 gro off ethtool -K eth0 lro offWindows网卡则在设备管理器-高级属性里把“Large Send Offload”“Receive Side Scaling”等选项禁用后重试。
3. 在Wireshark中快速识别与定位TRUNC数据包
3.1 用显示过滤器和自定义列筛出所有截断包
面对一个大pcap文件,不可能靠肉眼一包包翻。Wireshark里识别TRUNC最直接的过滤器是:
frame.len > frame.cap_len这个条件对所有的截断包都成立,不管是snaplen截断还是分片重组失败。如果你只关心UDP流,可以叠加协议条件:
udp && frame.len > frame.cap_len实际项目里我还会做两层保险:第一层,在列配置里新增两列,分别绑定frame.cap_len和frame.len,这样包列表里一眼就能看到长度差值;第二层,自定义一个颜色规则,把frame.len > frame.cap_len设为浅黄色背景,配合Expert Information一起看。这样即使是上千个包的流量文件,也能快速把“问题包”单独拉出来。
提示:过滤器的写法是
frame.cap_len,不是frame.caplen,中间有下划线。如果提示Unknown field,说明你的Wireshark版本可能比较旧,可以在“Display Filter Expression”里搜“capture length”确认字段名。
3.2 读懂Expert Info里的截断提示
Wireshark的Expert Info(Analyze -> Expert Info)是定位奇怪包的好帮手。对于TRUNC,不同成因会出现在不同分组里:
| 成因 | Expert Info位置 | 典型提示 |
|---|---|---|
| snaplen截断 | Notes / Info | Packet size limited during capture |
| IP分片重组失败 | Errors / Malformed | New fragment overlaps old fragment或Reassembly error |
| offload聚合异常 | Warnings / Malformed | 长度字段异常、解析错位等 |
很多人都习惯只关注红色“Errors”,觉得黄色警告无所谓,但TRUNC的提示往往藏在“Notes”级别里。尤其当抓包文件里同时存在TCP和UDP时,Expert Info的统计列表会把UDP截断和TCP重传混在一起,要记得按协议过滤,或者直接对frame.len > frame.cap_len做一次“Analyze -> Apply as Filter”,先把截断包隔离出来。
3.3 十六进制视图下确认截断边界
如果需要在报告里说清楚“这包是被腰斩了”而不是“这包本来就短”,可以配合Packet Bytes十六进制视图进一步确认。操作方法是选中任意一个被怀疑的UDP包,切到Packet Bytes面板,查看数据末尾的最后一个字节。
- 如果数据在某个固定偏移处戛然而止,且之后全是灰色区域,通常对应snaplen截断。比如
snaplen=512,那所有截断包的最后一个字节都会落在512这个位置。 - 如果数据停止的位置正好是某个分片的边界,并且前面还能看到IP Fragment Offset字段的递进,那更可能是分片重组失败。
- 如果字节流内容显示是多个Payload的混合体,但IP/UDP头只有一个,需要考虑GRO聚合。
这种基于“数据到底断在哪”的显微镜式观察,比只读Expert Info更能帮你还原出抓包点的真实情况。
4. 实战复盘:一次UDP音视频传输丢包排查中的TRUNC线索
4.1 问题现场:RTP丢包率异常与抓包文件的“残缺”包
有一次帮客户排查视频会议卡顿问题,现象是接收端显示丢包率在5%到10%之间波动,但网络设备上所有的丢包计数器都是零。我们在发送端和接收端同时用Wireshark抓包,想通过RTP序列号对比确定丢包发生在哪一段链路。
接收端的抓包文件里出现了大量UDP包,Info列清一色显示[Packet size limited during capture: 1434 bytes captured (1448 bytes original)]。第一反应是“是不是交换机把这几个包丢了”,因为从数量上看,丢包率正好和截断包的比例接近。但做RTP流分析时发现,这些截断包的RTP序列号并没有中断,也就是说包其实到了,只是负载数据被截断了。
4.2 排查链路:从流量统计到Follow UDP Stream
顺着这个线索继续查,我先用Wireshark的Telephony -> RTP -> Stream Analysis打开对应的RTP流,发现“丢包率”指标骤降,实际丢包率远低于客户端报告的数值。原因很简单:客户端判断丢包不只是看RTP序列号,还会校验负载完整性,那些负载被截断的UDP包在上层Socket读出来时发现长度不对,就被应用层统计成了“坏包”甚至“丢包”。
接着我又拿一个截断包看它的长度字段:UDP头里的Length写的是1448,但实际捕获长度只有1434,差了14字节。14正好是以太网帧头的大小,说明抓包工具是先把以太网头也算进snaplen了,导致UDP层被砍掉了最后14字节。再回头看抓包配置,原来是那边同事在远程抓包时为了减小pcap文件体积,给tcpdump加了-s 1434参数——1434这个值听着挺专业,实际上既不等于MTU,也没计算IP/UDP头开销。
4.3 抽丝剥茧:snaplen截断与分片重组失败的分辨技巧
这个案例里还有一个小插曲:抓包里同时存在另一个IP分片相关的异常,让我一度怀疑是不是分片重组的问题。分辨两个成因其实有规律:
| 判断角度 | snaplen截断 | 分片重组失败 |
|---|---|---|
| 截断偏移 | 所有包都断在固定snaplen值 | 断点随分片大小变化 |
| 伴随现象 | 无额外分片提示 | 能看到多个IP分片包 |
| 长度字段 | 原始长度>捕获长度,差值恒定 | 原始长度与分片偏移相关 |
| Expert Info | Notes级别 | Errors级别,常见overlap提示 |
在那种情况下,如果真的是分片重组失败,包列表里应该还能看到多个Fragmented IP protocol分包;而这次看到的每个截断包都是独立完整的IP包,没有分片标志,所以可以直接锁定为snaplen截断。最后把抓包参数改成-s 0重新抓了一遍,客户端显示的丢包率瞬间恢复正常,证明网络本身并没有丢包——问题出在抓包姿势上。
5. 如何抓全UDP数据包:snaplen设置经验与截断后的补救思路
5.1 设置合理的snaplen:经验值与计算方式
抓包之前设置snaplen,最稳的选择是直接设成0或65535,让驱动“有多少抓多少”。但在内存和磁盘受限的嵌入式设备或者长时间抓包场景下,确实需要控制文件大小,这时候可以精确计算:
- 标准以太网帧最大1518字节(含FCS),抓完整一帧不下于单个帧,snaplen设为
1514(去掉FCS)就够; - 如果抓802.1Q VLAN包,以太网头加4字节,设为
1518; - 如果抓巨型帧(jumbo frame),按MTU 9000算,设为
9000 + 14,也就是9014; - 如果怕性能不够,只想留包头的诊断用途,不要低于96字节,并且要在报告里写明“这个文件不包含完整负载”。
tcpdump和dumpcap命令行分别对应:
tcpdump -i eth0 -s 0 -w full.pcap udp port 5000 dumpcap -i eth0 -s 65535 -w full.pcapWireshark图形界面里,取消勾选“Limit each packet to”就等于无限长,一般本地网卡上不需要勾选。
5.2 关闭网卡offload,避免“假巨型包”相关截断
如果你抓到的UDP包普遍长度超过1500,或者同一个流里出现超大包和截断包混在一起,先别急着怀疑MTU设置,多半是网卡的GRO/LRO在捣乱。Linux下关闭后要确认一下:
ethtool -K eth0 gro off ethtool -K eth0 lro off ethtool -k eth0 | grep -E "gro|lro"ethtool -k显示large-receive-offload: off和generic-receive-offload: off才算生效。Windows下则是在网卡高级属性里把“Large Receive Offload”设为Disabled,“Receive Buffers”适当调大。关闭offload后再次抓包,你会发现包长度回归正常,很多莫名其妙的“截断”也随之消失。
5.3 TRUNC数据包仍能榨取的信息量
如果手头的pcap已经写满了TRUNC包,也别急着删掉重抓。大多数情况下,即使UDP负载被截断,IP头、UDP头、端口号、包长信息都还在,这些足够你回答以下问题:
- 该UDP会话的流量速率是多少,包大小分布如何?
- 序列号是否连续(RTP、QUIC等基于UDP的协议)?
- 往返时延、抖动是否正常?
- 是否存在IP分片,分片偏移是否规律?
- 哪个端口对哪个端口在大量通信,是否与预期行为一致?
真正受影响的是深度解析协议内容,比如SIP消息体、RTP音频数据、DNS应答资源记录里的具体字段。做这类分析时,可以尝试用Wireshark的“Follow UDP Stream”看看首屏数据,虽然没有完整负载,但偶发情况下应用层协议的前几个字段还在,依然能辅助判断。
最后再分享一个小技巧
如果你跟我一样经常在远程服务器上用tcpdump抓包,建议在抓包命令里固定加上-s 0,然后用-C 100和-W 50限制文件大小和数量,这样既不会因为snaplen太小留下残缺证据,也不会把磁盘写爆。我踩过一次这个坑之后,已经养成习惯:抓完包先跑一下过滤器frame.len > frame.cap_len,只要有任何一个包命中,就说明当前抓包文件对“完整数据”这件事是打了折扣的——宁可重新抓,也别拿一个先天残缺的文件去做后续分析。