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

188 lines
7.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
tags: [计算机网络, IPv4, IP首部, TTL, MTU, 分片]
create time: 2026-05-17 23:40
---
# IPv4 首部与分段重组
## 概述
IPv4 数据包是互联网的基本传输单元。理解其首部结构,有助于排查 MTU 问题、分析抓包工具输出、以及理解 IP 级故障恢复机制。
## IPv4 首部格式(32-bit fields)
```
Version(4b) │ IHL(4b) │ DSCP/ECN(8b) │ Total Length(16b) │
├─────────────────────────────────────────────────────────────────┤
│ Identification(16b) │DF│ MF │Offset(13b)│
├─────────────────────────────────────────────────────────────────┤
│ TTL(8b) │ Protocol(8b) │ Header Checksum │
├─────────────────────────────────────────────────────────────────┤
│ Source Address (32b) │
├─────────────────────────────────────────────────────────────────┤
│ Destination Address (32b) │
├─────────────────────────────────────────────────────────────────┤
│ Options (variable) │
│ ...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 优先级标记;前 3 bit 为 ECN(Explicit Congestion Notification)|
| **Total Length** | 16 bit | 整个 IP 包总长(含首部),最大 65535 字节 |
| **Identification** | 16 bit | 唯一标识符。同一原始包的分片共享此 ID |
| **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
```
## TTL 深度解析
### TTL 的常见误解
很多人以为 TTL 的单位是秒。其实在 IPv4 中它是**跳数计数器**——每经过一个路由器(三层转发节点)减 1,不是按时间递减。
```mermaid
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 的实践
```bash
# 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
```bash
$ 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 (硬性最小) | 可选 |
| 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 |
### PMTUD(Path MTU Discovery)
现代网络推荐使用 **路径 MTU 发现**而非分片:
```mermaid
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 - IP头(20) - Eth(14) = 1366
Src->>Dst: IP Packet (size=1366, DF=1) ✅
Dst-->>Src: ACK ✅
```
```bash
# 检查当前 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 | 动态路由协议 |
## 关联笔记
- [[hhs/NETWORK/CIDR与子网划分]] — IP 地址的子网分配方法
- [[hhs/NETWORK/NAT原理与应用]] — NAT 如何处理 IP 包的 Checksum
- [[hhs/NETWORK/ICMP与Ping-Traceroute]] — ICMP 协议细节