IPv4 首部与分片:用一个 3000 字节的 ping 观察分片

拆解 IPv4 首部的 20 个字节,动手制造分片,计算每个分片的偏移量,并顺带理解 TTL 与 traceroute 的原理。

DATE
LEN
583 字
TTL
2 min

IP 层的工作看似简单——把数据报从一台主机送到另一台——但首部里藏着不少值得推敲的设计。这篇用一个“超大号” ping 来观察 IPv4 分片。

IPv4 首部

HDRIPv4 Header (RFC 791)
012345678910111213141516171819202122232425262728293031
Version4
IHL4
DSCP6
ECN
Total Length16
Identification16
R1
DF1
MF1
Fragment Offset13
TTL8
Protocol8
Header Checksum16
Source Address32
Destination Address32
Options(IHL > 5 时存在)

几个关键字段:

  • IHL:首部长度,单位是 4 字节。最常见的值是 5,即 20 字节;
  • Total Length:首部 + 数据的总长度,单位是字节;
  • Identification / Flags / Fragment Offset:分片三件套;
  • TTL:每经过一个路由器减 1,减到 0 就丢弃并回送 ICMP 超时;
  • Protocol:上层协议,1=ICMP、6=TCP、17=UDP。

制造分片

以太网 MTU 一般是 1500 字节。让 ping 发一个远超 MTU 的报文,并且不设置 DF 位:

# -s 3000:ICMP 数据部分 3000 字节;-M dont:不设置 DF,允许分片
ping -c 1 -s 3000 -M dont 192.0.2.1

# 对比:设置 DF(禁止分片),本地就会直接报错
ping -c 1 -s 3000 -M do 192.0.2.1
# ping: local error: message too long, mtu=1500

用 Wireshark 抓包,过滤器:

ip.flags.mf == 1 || ip.frag_offset > 0

算一算分片

IP 层要发送的数据 = ICMP 首部 8 字节 + 数据 3000 字节 = 3008 字节。

每个分片能携带的数据 = MTU 1500 − IP 首部 20 = 1480 字节,且必须是 8 的倍数(因为 Fragment Offset 的单位是 8 字节)。1480 ÷ 8 = 185,刚好整除。

分片携带数据Total LengthOffset 字段实际字节偏移MF
114801500001
21480150018514801
3486837029600

三个分片的 Identification 相同,接收方据此把它们归为一组;靠 Offset 排序;看到 MF=0 就知道是最后一片。

笔记

只有第一个分片带有 ICMP 首部。后续分片里没有端口、没有 ICMP 类型——这也是防火墙处理分片如此麻烦的原因。

技巧

IPv6 中路由器不再分片,只能由源主机分片(通过扩展首部),路径上 MTU 不够时路由器直接回送 ICMPv6 Packet Too Big。

TTL 与 traceroute

TTL 防止报文在路由环路中无限转发。traceroute 巧妙地利用了它:

SEQtraceroute 原理
Host R1 R2 Target 探测报文 TTL=1 ICMP Time Exceeded(Type 11) 探测报文 TTL=2(经 R1 转发) ICMP Time Exceeded(Type 11) 探测报文 TTL=3 ICMP Port Unreachable(Type 3, Code 3)
  • Linux 的 traceroute 默认发送 UDP 探测报文到高位端口,到达目标后目标回送“端口不可达”;
  • Windows 的 tracert 使用 ICMP Echo,到达目标后收到 Echo Reply。

过滤 traceroute 相关的 ICMP:

icmp.type == 11 || icmp.type == 3

小结

  • IHL 单位 4 字节,Fragment Offset 单位 8 字节,Total Length 单位 1 字节——三种单位别搞混;
  • 分片由 Identification 归组、Offset 排序、MF 标记结尾;
  • 尽量避免分片:现代 TCP 通过 MSS 协商和路径 MTU 发现(PMTUD)来规避它;
  • TTL 不只是“防环路”,也是 traceroute 的基础,还能粗略推测操作系统(Linux 初始 64、Windows 128)。
↑↓ 选择 · Enter 打开 · Esc 关闭