简介 (Introduction)
互联网协议 (Internet Protocol, IP) [1] 用于在称为 catenet [2] 的互联网络系统中提供主机到主机的数据报服务。连接网络的设备称为网关 (gateways)。这些网关通过网关到网关协议 (Gateway to Gateway Protocol, GGP) [3,4] 相互通信以实现控制目的。有时网关或目的主机需要与源主机通信, 例如报告数据报处理中的错误。为此目的, 使用本协议——互联网控制消息协议 (Internet Control Message Protocol, ICMP)。ICMP 像高层协议一样使用 IP 的基本支持, 然而 ICMP 实际上是 IP 不可分割的组成部分, 必须由每个 IP 模块实现。
ICMP 消息在以下几种情况下发送: 例如, 当数据报无法到达目的地时, 当网关没有足够的缓冲容量来转发数据报时, 以及当网关可以引导主机通过更短的路由发送流量时。
互联网协议并非设计为绝对可靠的。这些控制消息的目的是提供关于通信环境中问题的反馈, 而不是使 IP 变得可靠。仍然无法保证数据报会被投递或控制消息会被返回。某些数据报可能在没有任何丢失报告的情况下无法投递。使用 IP 的高层协议如果需要可靠通信, 必须实现自己的可靠性机制。
ICMP 消息通常报告数据报处理中的错误。为了避免关于消息的消息的无限递归等问题, 不会发送关于 ICMP 消息的 ICMP 消息。此外, ICMP 消息仅针对分片数据报的第零片段 (fragment zero) 的处理错误发送。(第零片段的分片偏移量等于零。)
关键设计原则
1. IP 层的组成部分
应用层
↓
传输层 (TCP/UDP)
↓
网络层 (IP + ICMP) ← ICMP 是 IP 的组成部分
↓
数据链路层
ICMP 不是使用 IP 的高层协议, 而是 IP 层本身不可分割的组成部分。
2. 错误报告, 而非可靠性
ICMP 的功能:
- ✅ 报告数据报处理中的问题
- ✅ 提供关于网络状况的反馈
- ✅ 协助网络诊断
ICMP 不具备的功能:
- ❌ 保证消息投递
- ❌ 使 IP 变得可靠
- ❌ 提供端到端可靠性
- ❌ 实现流量控制
3. 无无限递归
规则: 不会发送关于 ICMP 消息的 ICMP 消息。
含错误的数据报
↓
发送 ICMP 错误消息 ✅
↓
含错误的 ICMP 消息
↓
不发送 ICMP 错误消息 ❌ (防止无限循环)
示例:
1. TCP 数据包 → IP 数据报 → 发生错误
→ 发送 ICMP Destination Unreachable ✅
2. ICMP Destination Unreachable → 发生错误
→ 不发送 ICMP 消息 ❌
这防止了错误消息的级联
4. 第零片段规则
ICMP 错误消息仅针对分片数据报的第一个片段 (分片偏移量 = 0) 发送。
原始数据报 (已分片):
┌─────────────┬─────────────┬─────────────┐
│ Fragment 0 │ Fragment 1 │ Fragment 2 │
│ offset=0 │ offset=500 │ offset=1000 │
└─────────────┴─────────────┴─────────────┘
↓ ↓ ↓
错误 错误 错误
↓ ↓ ↓
发送 ICMP ✅ 不发送 ICMP ❌ 不发送 ICMP ❌
原因:
- 避免为同一原始数据报生成多条错误消息
- 确保错误报告可管理
- 只有第一个片段包含完整的上层协议信息
ICMP 消息的常见场景
场景 1: 目的地不可达
主机 A → 路由器 → [网络 B 已断开]
↓
ICMP Type 3: Destination Unreachable
↓
主机 A 收到错误通知
场景 2: 重定向
主机 A → 网关 1 → 网关 2 → 目的地
↓
ICMP Type 5: Redirect
"对于此目的地, 直接使用网关 2"
↓
主机 A 更新路由表
场景 3: 超时
TTL=1 的数据包
↓
路由器将 TTL 减为 0
↓
ICMP Type 11: Time Exceeded
↓
源主机收到通知
场景 4: 源抑制 (拥塞控制)
网关缓冲区已满
↓
ICMP Type 4: Source Quench
↓
源主机降低发送速率
注意: 源抑制 (Source Quench) 现已废弃 (RFC 6633), 原因是其效果不佳且可能被滥用。
与其他协议的关系
ICMP 与 IP
IP 数据报:
┌─────────────┬──────────────────┐
│ IP Header │ IP Payload │
│ Protocol=1 │ ICMP Message │
└─────────────┴──────────────────┘
IP 头部:
- Protocol 字段 = 1 (表示 ICMP)
- Source Address = ICMP 发送方
- Destination Address = ICMP 接收方
ICMP 与 GGP
网关到网关协议 (Gateway to Gateway Protocol, GGP):
- 网关使用 GGP 在彼此之间进行控制通信
- ICMP 用于网关到主机的通信
- 目的不同, 互为补充的协议
ICMP 与高层协议
应用程序 (例如 ping 工具)
↓ 构造 ICMP 消息
带有 ICMP 模块的 IP 层
↓ 在 IP 数据报中发送 ICMP
网络接口
错误报告示例
示例 1: 主机不可达
步骤 1: 主机 A 向主机 B (10.0.2.100) 发送数据包
┌─────────────────────────────┐
│ Src: 10.0.1.10 │
│ Dst: 10.0.2.100 │
│ Data: "Hello" │
└─────────────────────────────┘
步骤 2: 路由器 R1 判断主机 B 不可达
路由器 R1 的路由表: 无到 10.0.2.0/24 的路由
步骤 3: 路由器 R1 发送 ICMP Destination Unreachable
┌─────────────────────────────┐
│ ICMP Type: 3 │
│ Code: 1 (Host Unreachable) │
│ Contains: IP header + 64 │
│ bits of original │
│ datagram │
└─────────────────────────────┘
步骤 4: 主机 A 收到 ICMP 并向应用程序报告错误
示例 2: 需要分片但设置了 DF 标志
步骤 1: 主机 A 发送带有 Don't Fragment (DF) 标志的大数据包
┌─────────────────────────────┐
│ Src: 192.168.1.10 │
│ Dst: 203.0.113.50 │
│ Flags: DF=1 (不允许分片) │
│ Length: 1500 bytes │
└─────────────────────────────┘
步骤 2: 路由器 R1 收到数据包
- 出口接口 MTU = 1000 字节
- 数据包大小 = 1500 字节
- DF 标志已设置 → 无法分片
步骤 3: 路由器 R1 发送 ICMP Destination Unreachable
┌─────────────────────────────┐
│ ICMP Type: 3 │
│ Code: 4 (Fragmentation │
│ needed but DF set) │
│ Next-Hop MTU: 1000 │
└─────────────────────────────┘
步骤 4: 主机 A 收到 ICMP
- 实现路径 MTU 发现
- 将数据包大小减小到 1000 字节
- 重新发送数据
这是路径 MTU 发现 (Path MTU Discovery, PMTUD) [RFC 1191] 的关键机制。
处理规则
发送方职责
-
判断是否应发送 ICMP:
- 这是错误条件吗?
- 这是关于 ICMP 消息的吗? (如果是, 不发送)
- 这是关于第零片段的吗? (如果不是第零片段, 不发送)
-
构造 ICMP 消息:
- 设置适当的 Type 和 Code
- 计算校验和
- 包含原始 IP 头部 + 原始数据的前 64 位
-
通过 IP 发送:
- 使用 IP 协议号 1 (ICMP)
- 设置适当的 IP 头部字段
接收方职责
-
验证消息:
- 验证校验和
- 检查 Type 和 Code 值
-
根据 Type 进行处理:
- 错误消息: 向上层协议报告
- 查询消息: 生成响应
- 信息消息: 相应处理
-
传递给适当的处理程序:
- 根据原始数据报信息进行多路分解
- 通知受影响的协议或应用程序
历史背景: ICMP 在 RFC 792 (1981年9月) 中作为原始互联网协议套件的一部分被定义。它至今仍是 IP 网络的基本组成部分, 尽管多年来一些消息类型已被废弃, 也新增了一些类型。