Files
cs-note/hhs/NETWORK/03-网络层/01-IPv4首部与分段重组.md
T
2026-05-27 23:01:37 +08:00

11 KiB
Raw Blame History

tags, create time
tags create time
计算机网络
IPv4
IP首部
TTL
MTU
分片
ECN
PMTUD
IP Options
2026-05-17 23:40

IPv4 首部与分段重组

概述

IPv4 数据包是互联网的基本传输单元。理解其首部结构,有助于排查 MTU 问题、分析抓包工具输出、以及理解 IP 级故障恢复机制。

IPv4 首部格式(32-bit fields)

Version(4b) │ IHL(4b) │ DSCP(6b) │ ECN(2b) │     Total Length(16b)     │
├───────────────────────────────────────────────────────────────────────┤
│          Identification(16b)          │Rsv│DF│MF│   Offset(13b)      │
├───────────────────────────────────────────────────────────────────────┤
│         TTL(8b)       │   Protocol(8b)   │    Header Checksum(16b)   │
├───────────────────────────────────────────────────────────────────────┤
│                       Source Address (32b)                            │
├───────────────────────────────────────────────────────────────────────┤
│                    Destination Address (32b)                          │
├───────────────────────────────────────────────────────────────────────┤
│                       Options (variable, 0-40B)                      │
│                            ...padding...                             │
└───────────────────────────────────────────────────────────────────────┘

各字段详解

字段 大小 说明
Version 4 bit 版本号,IPv4 = 0100
IHL (Internet Header Length) 4 bit 首部长度,单位 4 bytes。最小值 5(20 bytes),最大 15(60 bytes)
DSCP (Differentiated Services Code Point) 6 bit QoS 优先级标记,替代早期的 ToS 字段前 6 位
ECN (Explicit Congestion Notification) 2 bit 显式拥塞通知。末 2 bit 用于在不丢包的情况下通知端主机网络拥塞(00=不支持, 10/01=支持 ECN, 11=拥塞已经历)
Total Length 16 bit 整个 IP 包总长(含首部),最大 65535 字节
Identification 16 bit 唯一标识符。同一原始包的分片共享此 ID
Reserved 1 bit 保留位,必须为 0
DF (Don't Fragment) 1 bit 置 1 则禁止分片;路由器不能分片的包如果 DF=1,直接丢弃并返回 ICMP "Fragmentation Needed"
MF (More Fragments) 1 bit 置 1 表示后面还有分片;最后一个分片 MF=0
Fragment Offset 13 bit 该分片在原始数据中的偏移量(以 8 字节为单位)
TTL (Time To Live) 8 bit 生存时间,每经过一个路由器减 1,归零时丢弃并发送 ICMP Timeout
Protocol 8 bit 上层协议编号:TCP=6, UDP=17, ICMP=1, IGMP=2
Header Checksum 16 bit 仅校验首部的 CRC,不校验 payload
Source/Dest Address 各 32 bit 源和目的 IP 地址

最小 vs 最大 IP 包

最小 IP 包:        20B 首部 + 0B 数据 = 20 bytes
最小以太网帧承载:  20B 首部 + 8B ICMP Echo = 28 bytes
                    → 加上 14B EthHdr + 4B FCS = 46 bytes ≥ MTU 下限 ✅

最大 IP 包:        20B 首部 + 65515B 数据 = 65535 bytes
受限于链路 MTU:   通常 1500B Payload → 最大常用包 1520 bytes

[!tip] 为什么 IHL 最大值是 15? IHL 以 4 字节为单位,最大值 15 × 4 = 60 bytes。去掉固定首部 20 bytes,Options 最多 40 bytes。这就是为什么 Options 字段上限是 40B。

Options 字段(可选,0-40 bytes)

Options 是 IPv4 首部中最容易被忽略的部分,但在网络诊断和特殊场景中依然重要:

选项类型 说明 典型用途
Record Route 记录包经过的每一跳路由器 IP 路由追踪(类似 traceroute)
Timestamp 每个路由器记录到达时间戳 测量延迟、时钟同步分析
Strict Source Route 指定完整路径,逐跳严格匹配 诊断路由问题(现代网络几乎禁用)
Loose Source Route 指定必须经过的中间节点,其余自由路由 绕路测试

[!warning] 安全注意 现代路由器和防火墙通常丢弃包含 Options 的 IP 包,因为 Source Route 曾被用于 IP 欺骗攻击。这也是为什么正常流量中你几乎看不到 Options。

Header Checksum 逐跳重算

与 L2 CRC 和 TCP/UDP Checksum 不同,IP Header Checksum 每经过一个路由器都要重新计算——因为 TTL 会递减。

flowchart LR
    A["路由器收到包"] --> B["TTL -= 1"]
    B --> C["重新计算 Checksum"]
    C --> D["转发到下一跳"]

    style A fill:#87CEEB,color:#000
    style D fill:#98FB98,color:#000

[!question] 为什么 IP Checksum 只校验首部? 早期设计为减轻路由器负担——只校验 20 bytes 首部远比校验整个 64KB 包高效。数据完整性由上层协议(TCP/UDP Checksum)保证。这也是 IP 被称为"尽力而为"协议的原因之一。

TTL 深度解析

TTL 的常见误解

[!question] TTL 是时间吗? 很多人以为 TTL 的单位是秒——这其实是 IPv6 的 Hop Limit 的前身历史遗留误解。在 IPv4 中 TTL 是跳数计数器——每经过一个路由器(三层转发节点)减 1,不是按时间递减。名字容易误导,但行为很简单:减到 0 就丢弃。

flowchart LR
    A["Source<br/>TTL=64"] -->|"路由器减1"| B["TTL=63"]
    B -->|"路由器减1"| C["TTL=62"]
    C -->|"路由器减1"| D["TTL=61"]
    D -->|"到目的地"| E["TTL=60<br/>继续处理"]
    
    style A fill:#DDA0DD,color:#000
    style E fill:#98FB98,color:#000

查看 TTL 的实践

# ping 默认从 64 或 128 开始,减去到达时的 TTL ≈ 经过了跳数
$ ping -c 1 example.com
PING example.com (93.184.216.34): 56 data bytes
64 bytes from ... icmp_seq=0 ttl=55 time=23.1 ms
# 64 - 55 = 9 跳

# Windows 默认 TTL=128
$ tracert example.com
  1     1 ms     1 ms     1 ms  192.168.1.1
  2     2 ms     2 ms     2 ms  10.0.0.1
  ...
  9     23 ms    23 ms    23 ms  93.184.216.34

Linux 系统初始 TTL

$ sysctl net.ipv4.ip_default_ttl
net.ipv4.ip_default_ttl = 64

# macOS / Windows 默认 128
# 某些嵌入式设备可能用 32 或 60

MTU 与分片(Fragmentation)

什么是 MTU?

MTU(Maximum Transmission Unit)是链路层允许的最大 IP 包载荷大小。超出 MTU 的包需要被分片。

链路类型 典型 MTU Jumbo Frame
Ethernet 1500 bytes 9000 bytes
Wi-Fi (802.11n/ac/ax) 1500 ❌ 不支持
PPPoE (宽带拨号) 1492 (8B PPPoE 头开销) —
IPv6 1280 (硬性最小 MTU) 可选
GRE 隧道 1476 (24B GRE 头开销) —
VXLAN 1450 (50B VXLAN 头开销) —

分片规则

当 IP 包 > MTU 且 DF=0 时,路由器将其切分为多个分片:

原始 IP 包 (Payload = 3000 bytes) ── MTU=1500 ──→

分片 1:  Headers + [Bytes 0..1479]   Offset=0   MF=1
分片 2:  Headers + [Bytes 1480..2959] Offset=185*8=1480  MF=1
分片 3:  Headers + [Bytes 2960..2999] Offset=370*8=2960  MF=0 (最后一片)
                                         ↑ offset × 8 = 实际偏移

关键限制: 除最后一个分片外,每个分片的 payload 必须是 8 字节的整数倍。这就是为什么 offset 字段以 8 字节为单位。

分片的优缺点

优点 缺点
允许大应用层数据穿越小 MTU 链路 增加路由器的 CPU 负担
透明(对应用层无感知) 任一丢包导致整个原始包失效
— 攻击者可以利用分片做碎片攻击(Teardrop 等)
— IPv6 已取消中间路由器分片,改由端到端 PMTUD

Wireshark 中识别分片

实战排查时,抓包识别分片是最常见需求:

# tcpdump 过滤分片包(offset > 0 或 MF=1 的包)
$ tcpdump -i eth0 'ip[6:2] & 0x3fff != 0' -nn

# Wireshark 显示过滤器
# ip.frag_offset > 0       → 非首片
# ip.flags.mf == 1         → 还有后续分片
# ip.id == 0x1234          → 按 Identification 追踪同组分片

[!tip] 分片重组技巧 Wireshark 默认会自动重组分片。如果需要查看原始分片:Edit → Preferences → IPv4 → 去勾选 "Reassemble fragmented IPv4 datagrams"。

常见分片攻击

攻击手法 原理 防御
Teardrop 构造重叠偏移的分片,重组时内核缓冲区溢出 更新内核补丁(已修复)
Ping of Death 分片重组后 IP 包 > 65535 bytes,触发整数溢出 现代系统已防御
Rose Attack 发送大量不完整的分片,消耗重组缓冲区 设置重组超时、限制并发分片数
Fragment Overlap 后续分片覆盖前片数据,绕过基于首片的防火墙规则 防火墙需做完整分片重组后再检测

PMTUD(Path MTU Discovery)

现代网络推荐使用 路径 MTU 发现而非分片:

[!warning] PMTUD Black Hole 如果中间路由器静默丢弃了 DF=1 的大包,但不返回 ICMP,源主机会一直重传失败——这就是 PMTUD Black Hole。常见于错误配置的防火墙(拦截了 ICMP "Fragmentation Needed")。TCP 的对策是 net.ipv4.tcp_mtu_probing(值设为 2),主动探测合适的 MSS。

sequenceDiagram
    participant Src as 源主机
    participant R as 瓶颈路由器(MTU=1400)
    participant Dst as 目标服务器

    Src->>Dst: IP Packet (size=1500, DF=1)
    Note over Src: DF(Do Not Fragment)=1
    R->>R: MTU=1400 < 1500, DF=1 → 无法分片!
    R->>Src: ICMP Type 3 Code 4 "Fragmentation Needed"
    Note over Src: Path MTU = 1400, Max IP Payload = 1400 - 20(IP头) = 1380
    Src->>Dst: IP Packet (size=1400, DF=1) ✅
    Dst-->>Src: ACK ✅
# 检查当前 PMTUD 状态
$ ip route show | grep mtu
default via 192.168.1.1 dev eth0 mtu 1500

# Linux 内核 PMTUD 控制
$ sysctl net.ipv4.tcp_mtu_probing
net.ipv4.tcp_mtu_probing = 0  # 0=关闭, 1=低速率, 2=始终开启

协议编号对照表

Protocol 值 名称 用途
1 ICMP 网络诊断(ping、traceroute)
2 IGMP 组播管理
6 TCP 可靠面向连接传输
17 UDP 无连接不可靠传输
47 GRE 虚拟私有隧道
50 ESP IPsec 加密封装安全载荷
51 AH IPsec 认证头
89 OSPF 动态路由协议

关联笔记