ICMP 是一种面向无连接的协议,负责传递可能需要注意的差错和控制报文,差错指示通信网络是否存在错误 (如目的主机无法到达、IP 路由器无法正常传输数据包等。注意,路由器缓冲区溢出导致的丢包不包括在 ICMP 响应范围内,在 TCP 负责范围)。
ICMPv4 和 ICMPv6 分别指用于 IPv4 和 IPv6 的 ICMP 版本。在 IPv4 中,协议字段值为 1 表示该报文携带了 ICMPv4;在 IPv6 中,ICMPv6 报文位于扩展头部里,ICMPv6 扩展头部上一个头部包含了值为 58 的 “下一个头部” 字段。
ICMP 报文
所有 ICMP 报文都以 8 位的类型 (Type) 和代码 (Code) 字段开始,其后跟随的 16 位校验和 (Checksum) 字段涵盖整个报文。
类型字段用于确定特定的报文,ICMPv4 和 ICMPv6 的该字段值并不相同;代码字段进一步肯定报文的含义,ICMPv4 和 ICMPv6 的该字段值并不相同;校验和字段用于确定报文信息的正确性。
ICMP 报文可分为两类:有关 IP 数据报传递的 ICMP 报文 (差错报文) 和信息采集和配置的 ICMP 报文 (查询或者信息类报文)。
由类型字段决定的 ICMPv4 报文类型
(*) 标记的类型是最常见的,(+) 标记的可能包含 [RFC4884] 扩展对象,E 表示差错报文,I 表示查询 / 信息类报文。
ICMPv4 报文类型使用的代码
由类型字段决定的 ICMPv6 报文类型:差错报文的类型从 0-127,信息类报文类型为 128-255
ICMPv6 报文类型使用的代码
一般来说,对于传入的 ICMP 信息,查询或信息类将被操作系统自动处理,差错类报文传递给用户进程或传输层协议 (除去重定向报文和目的地不可达,前者导致主机路由表的自动更新,后者用于路径 MTU 发现机制)。
传入的 ICMPv6 报文处理规则如下:
-
未知的 ICMPv6 差错报文必须传递给上层产生差错报文的进程;
-
未知的 ICMPv6 信息类报文被丢弃;
-
ICMPv6 差错报文将会尽可能多地包含到差错的原始 (违规) IPv6 报文,最终的差错报文大小不能超过最小的 IPv6 MTU (1280 字节);
-
在处理 ICMPv6 差错报文时,需要提取原始或违规数据包中的上层协议类型,用于选择适当的上层进程;
-
存在处理差错的特殊规则;
-
IPv6 节点必须限制它发生 ICMPv6 差错报文的速率。
查询 / 消息类报文
由于某些 ICMP 的功能已经被其他特殊目的的协议代替,保存下来的广泛使用的 ICMP 查询 / 信息类报文是回显请求 / 应答报文 (常用的 “ping”),以及路由器发现报文。
回显请求 / 应答相对简单,收到回显请求之后,ICMP 的实现要求将任何收到的数据返回给发送者。其报文结构如下:
发送主机利用标识符来分离返回的应答 (如多个 ping 同时允许的时候,用于区分返回的应答)。
当一个 ping 实例运行时,序列号从 0 开始,每发送一个回显请求则加 1.
路由器发现则较为复杂,也就是与移动 IP 一起使用的那个。其主要目的是让一台主机学习到它所在的本地子网中所有路由器,从而选择一台作为默认路由器,也用于发现那些愿意充当移动 IP 代理的路由器。
地址数给出报文中路由地址块的个数,每个块包含一个 IPv4 地址及相应的优先水平 (优先水平是一个 32 位的有符号二进制补码整数,其值越大代表优先级越高。默认的优先水平是 0,特殊值 0x80000000 表示这个地址不应该用作有效的默认路由);
地址条目大小给出每个块的 32 位字数;
生命周期给出地址列表被认为有效的秒数;
序列号字段给出了自从初始化之后代理产生的这种扩展的个数;
注册字段给出了发送 代理愿意接受 MIPv4 注册的最大秒数 (0xFFFF 表示无穷大);
那些字母的含义:R (为 MIP 服务所需的注册)、B (代理太忙无法接受注册)、H (代理愿意充当本地代理)、F (代理愿意充当外地代理)、M (支持最小封装格式)、G (代理支持封装数据报的 GRE 隧