跳到主要内容

简介 (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] 的关键机制。

处理规则

发送方职责

  1. 判断是否应发送 ICMP:

    • 这是错误条件吗?
    • 这是关于 ICMP 消息的吗? (如果是, 不发送)
    • 这是关于第零片段的吗? (如果不是第零片段, 不发送)
  2. 构造 ICMP 消息:

    • 设置适当的 Type 和 Code
    • 计算校验和
    • 包含原始 IP 头部 + 原始数据的前 64 位
  3. 通过 IP 发送:

    • 使用 IP 协议号 1 (ICMP)
    • 设置适当的 IP 头部字段

接收方职责

  1. 验证消息:

    • 验证校验和
    • 检查 Type 和 Code 值
  2. 根据 Type 进行处理:

    • 错误消息: 向上层协议报告
    • 查询消息: 生成响应
    • 信息消息: 相应处理
  3. 传递给适当的处理程序:

    • 根据原始数据报信息进行多路分解
    • 通知受影响的协议或应用程序

历史背景: ICMP 在 RFC 792 (1981年9月) 中作为原始互联网协议套件的一部分被定义。它至今仍是 IP 网络的基本组成部分, 尽管多年来一些消息类型已被废弃, 也新增了一些类型。