4. IP协议基础:IPv4头部结构、分片与重组、TTL分析、IP选项字段
IP协议是整个TCP/IP栈的“腰杆子”。你想想看,没有IP,数据包连去哪都不知道。这一章我们就把IPv4的底裤扒干净——头部每个字节干什么用、包太大怎么切、TTL怎么防环路、还有那些几乎没人用的选项字段。
本章核心:抓包时你看到的每一个IP头部字段,背后都有故事。理解它们,你才能读懂Wireshark里那些“奇怪”的现象。
4.1 IPv4头部结构——20字节的“身份证”
IPv4头部标准长度是20字节,不含选项。我刚开始学的时候觉得这20字节好复杂,后来抓包抓多了,闭着眼都能背出来。
先看一张完整的头部结构图:
每个字段我都给你拆开讲:
| 字段 | 长度 | 作用 | 抓包时怎么看 |
|---|---|---|---|
| 版本 | 4bit | IPv4固定为4 | Wireshark直接显示"Version: 4" |
| 首部长度 | 4bit | 单位4字节,最小5(20B),最大15(60B) | 看"Header Length"字段 |
| 服务类型(ToS) | 8bit | QoS标记,现在多用DSCP | 大部分场景为0 |
| 总长度 | 16bit | IP包总字节数,最大65535 | 减去头部长度=数据长度 |
| 标识 | 16bit | 分片时同一组包的ID | 分片包标识相同 |
| 标志 | 3bit | DF(不分片)、MF(更多分片) | DF=1时路由器不能分片 |
| 片偏移 | 13bit | 分片在原始包中的位置 | 单位8字节 |
| TTL | 8bit | 最大跳数,防环路 | 每经过一个路由器减1 |
| 协议 | 8bit | 上层协议类型 | 6=TCP, 17=UDP, 1=ICMP |
| 首部校验和 | 16bit | 只校验头部 | 路由器会重新计算 |
| 源/目的IP | 各32bit | IPv4地址 | 抓包最直观的字段 |
我的习惯:抓包时先看"总长度"和"首部长度"。如果总长度远大于MTU(1500),那这个包大概率被分片了。另外,首部长度如果大于5,说明有选项字段——这种情况现在很少见了。
4.2 分片与重组——包太大?切了再说
以太网MTU是1500字节。如果IP包超过这个值,路由器就得把它切开。我遇到过最头疼的问题就是分片导致的性能故障——有些防火墙会丢弃分片包,导致大文件传输卡死。
分片的核心逻辑就三个字段:标识(Identification)、标志(Flags)、片偏移(Fragment Offset)。
看一个分片流程:
分片的关键点:
- DF标志=1:路由器不能分片,包太大直接丢弃,返回ICMP错误。我遇到过VPN隧道MTU问题,就是DF=1导致的。
- MF标志=1:后面还有分片。MF=0表示这是最后一个分片。
- 片偏移:单位是8字节。比如偏移185,表示数据从1480字节开始。
我曾经踩过的坑:有一次客户说文件上传到某台服务器总是卡在99%。抓包一看,所有大包都设置了DF=1,中间有个链路的MTU只有1400。服务器返回ICMP"需要分片但DF已设置"的报文,但客户防火墙把ICMP给过滤了。结果就是——TCP永远无法完成三次握手之外的数据传输。解决方案:要么改MTU,要么放行ICMP。
重组是在接收端完成的。接收端根据标识字段把属于同一组的分片找出来,再按片偏移排序拼接。如果某个分片丢了,整个包都重组失败——TCP会重传整个数据段,而不是只重传丢失的分片。
4.3 TTL分析——你的包能走多远?
TTL(Time To Live)虽然名字叫"生存时间",但实际是最大跳数。每经过一个路由器,TTL减1。减到0时,路由器丢弃这个包,并给源IP发一个ICMP超时报文。
默认值因操作系统而异:
| 操作系统 | 默认TTL | 说明 |
|---|---|---|
| Linux | 64 | 大多数发行版 |
| Windows | 128 | Win7/10/11都是128 |
| macOS/iOS | 64 | 和Linux一样 |
| Android | 64 | 基于Linux内核 |
| Cisco路由器 | 255 | 设备间通信常用 |
抓包时看TTL能判断什么?
- 判断源端系统:TTL=128大概率是Windows,TTL=64大概率是Linux/macOS。
- 估算跳数:比如抓到TTL=56,初始64,说明经过了8跳。
- 检测环路:如果TTL在多个包中持续递减到0,说明有路由环路。
我常用的traceroute原理:就是利用TTL。先发TTL=1的包,第一个路由器返回ICMP超时;再发TTL=2,第二个路由器返回...以此类推,就能画出整条路径。Windows的tracert用ICMP,Linux的traceroute默认用UDP。
看一个Wireshark抓包示例:
# 抓包过滤:icmp
# 一个ping包的IP头部
Internet Protocol Version 4, Src: 192.168.1.100, Dst: 8.8.8.8
0100 .... = Version: 4
.... 0101 = Header Length: 20 bytes (5)
Differentiated Services Field: 0x00 (DSCP: CS0, ECN: Not-ECT)
Total Length: 60
Identification: 0x1a2b (6699)
Flags: 0x40, Don't fragment
Fragment Offset: 0
Time to Live: 64 ← 初始值64,Linux系统
Protocol: ICMP (1)
Header Checksum: 0x3c4d [validation disabled]
Source Address: 192.168.1.100
Destination Address: 8.8.8.8
注意看Flags字段显示"Don't fragment"——很多现代系统默认设置DF=1,因为分片会降低性能。
4.4 IP选项字段——几乎没人用的“古董”
IP选项字段让头部长度从20字节扩展到最多60字节。但说实话,我在生产环境几乎没见过。为什么?因为大多数路由器和防火墙会直接丢弃带选项的包——安全风险太高。
常见的IP选项:
| 选项类型 | 编号 | 作用 | 现状 |
|---|---|---|---|
| NOP(无操作) | 1 | 填充对齐 | 偶尔见到 |
| EOOL(选项结束) | 0 | 标记选项结束 | 偶尔见到 |
| 记录路由 | 7 | 记录经过的路由器IP | 几乎不用,空间有限 |
| 时间戳 | 68 | 记录每跳时间 | 几乎不用 |
| 严格源路由 | 137 | 强制指定路径 | 安全风险,被禁用 |
| 松散源路由 | 131 | 指定部分路径 | 安全风险,被禁用 |
安全提醒:源路由选项(严格/松散)曾经被黑客用来绕过防火墙。攻击者可以伪造路径,让流量绕过安全设备。现在几乎所有网络设备都默认丢弃带源路由选项的包。如果你在抓包中看到这些选项,大概率是有人在搞事情。
我个人建议:抓包时如果看到IP头部长度大于20字节,先警惕一下。用Wireshark的"Expert Info"功能看看有没有异常标记。正常流量中,IP选项几乎绝迹。
4.5 实战:用Wireshark分析IP头部
打开Wireshark,抓一个ping包,看看IP头部:
- 过滤条件输入
icmp或ip.addr == 你的目标IP - 展开"Internet Protocol Version 4"那一行
- 观察每个字段的值
- 重点关注:TTL、标识、标志、总长度
试试这个实验:
- ping一个本地地址,看TTL是多少
- ping一个远程地址(比如8.8.8.8),看TTL减少了多少
- 用
ping -f -l 2000 目标IP(Windows)强制发送大包且设置DF=1,看会不会收到ICMP错误
总结一下:IPv4头部就20字节,但每个字节都有意义。分片靠标识+标志+偏移三件套,TTL帮你判断距离和系统类型,选项字段基本是历史遗迹。抓包时多看看这些字段,你能发现很多网络问题的根因。