ICMP经常被认为是IP层的一个组成部分。它传递差错报文以及其他需要注意的信息。ICMP报文通常被IP层或更高层协议(TCP或UDP)使用。一些ICMP报文把差错报文返回给用户进程。

ICMP报文是在IP数据报内部被传输的,格式为:20个字节的IP首部加上后面的ICMP报文。

ICMP 报文格式中,类型字段可以有15个不同的值,以描述特定类型的ICMP报文。某些ICMP报文还使用代码字段的值来进一步描述不同的条件。 检验和字段覆盖整个ICMP报文。使用的算法与IP首部检验和算法相同。ICMP的检验和是必需的。

ICMP 报文的类型

类型代码描述查询差错
00回显应答(Ping应答)*
3目的不可达:
0网络不可达*
1主机不可达*
2协议不可达*
3端口不可达*
4需要进行分片但设置了不分片比特*
5源站选路失败*
6目的网络不认识*
7目的主机不认识*
8源主机被隔离(作废不用)*
9目的网络被强制禁止*
10目的主机被强制禁止*
11由于服务类型TOS,网络不可达*
12由于服务类型TOS,主机不可达*
13由于过滤,通信被强制禁止*
14主机越权*
15优先权中止生效*
40源端被关闭(基本流控制)*
5重定向:*
0对网络重定向*
1对主机重定向*
2对服务类型和网络重定向*
3对服务类型和主机重定向*
8  0  请求回显(Ping请求)              *     
90路由器通告*
100路由器请求*
11超时:
0传输期间生存时间为0(Traceroute)*
1在数据报组装期间生存时间为 0*
12参数问题:
0坏的IP首部(包括各种差错)*
1缺少必需的选项*
130时间戳请求*
140时间戳应答*
150信息请求(作废不用)*
160信息应答(作废不用)*
170地址掩码请求*
180地址掩码应答*

不同类型由报文中的类型字段和代码字段来共同决定。

最后两列表明ICMP报文是一份查询报文还是一份差错报文。因为对ICMP差错报文有时需要作特殊处理,因此我们需要对它们进行区分。例如,在对ICMP差错报文进行响应时,永远不会生成另一份ICMP差错报文(如果没有这个限制规则,可能会遇到一个差错产生另一个差错的情况,而差错再产生差错,这样会无休止地循环下去)。

当发送一份ICMP差错报文时,报文始终包含IP的首部和产生ICMP差错报文的IP数据报的前8个字节。这样,接收ICMP差错报文的模块就会把它与某个特定的协议(根据IP数据报首部中的协议字段来判断)和用户进程(根据包含在IP数据报前8个字节中的TCP或UDP报文首部中的TCP或UDP端口号来判断)联系起来。

下面各种情况都不会导致产生ICMP差错报文:

  1. ICMP差错报文(但是,ICMP查询报文可能会产生ICMP差错报文)。
  2. 目的地址是广播地址或多播地址(D类地址)的IP数据报。
  3. 作为链路层广播的数据报。
  4. 不是IP分片的第一片。
  5. 源地址不是单个主机的数据报。这就是说,源地址不能为零地址、环回地址、广播地址或多播地址。

这些规则是为了防止过去允许ICMP差错报文对广播分组响应所带来的广播风暴。

ICMP 地址掩码请求与应答

ICMP地址掩码请求用于无盘系统在引导过程中获取自己的子网掩码。系统广播它的ICMP请求报文(这一过程与无盘系统在引导过程中用RARP获取IP地址是类似的)。无盘系统获取子网掩码的另一个方法是BOOTP协议。ICMP地址掩码请求和应答报文的格式如下:

ICMP报文中的标识符和序列号字段由发送端任意选择设定,这些值在应答中将被返回。这样,发送端就可以把应答与请求进行匹配。

ICMP 时间戳请求与应答

ICMP时间戳请求允许系统向另一个系统查询当前的时间。返回的建议值是自午夜开始计算的毫秒数,协调的统一时间(Coordinated Universal Time,UTC)(早期的参考手册认为UTC是格林尼治时间)。这种ICMP报文的好处是它提供了毫秒级的分辨率,而利用其他方法从别的主机获取的时间(如某些Unix系统提供的rdate命令)只能提供秒级的分辨率。由于返回的时间是从午夜开始计算的,因此调用者必须通过其他方法获知当时的日期,这是它的一个缺陷。

请求端填写发起时间戳,然后发送报文。应答系统收到请求报文时填写接收时间戳,在发送应答时填写发送时间戳。但是,实际上,大多数的实现把后面两个字段都设成相同的值(提供三个字段的原因是可以让发送方分别计算发送请求的时间和发送应答的时间)。

ICMP 不可达差错

ICMP的一个规则是,ICMP差错报文必须包括生成该差错报文的数据报IP首部(包含任何选项),还必须至少包括跟在该IP首部后面的前8个字节。

导致差错的数据报中的IP首部要被送回的原因是因为IP首部中包含了协议字段,使得ICMP可以知道如何解释后面的8个字节。事实上,UDP首部中的内容是源端口号和目的端口号,如果我们来查看TCP首部,可以发现源端口和目的端口被包含在TCP首部的前8个字节中。

ICMP 报文的 4.4BSD 处理

类型代码描述处理方法
00回显应答(Ping应答)用户进程
3目的不可达:
0网络不可达“无路由到达主机”
1主机不可达“无路由到达主机”
2协议不可达“连接被拒绝”
3端口不可达“连接被拒绝”
4需要进行分片但设置了不分片比特“报文太长”
5源站选路失败“无路由到达主机”
6目的网络不认识“无路由到达主机”
7目的主机不认识“无路由到达主机”
8源主机被隔离(作废不用)“无路由到达主机”
9目的网络被强制禁止“无路由到达主机”
10目的主机被强制禁止“无路由到达主机”
11由于服务类型TOS,网络不可达“无路由到达主机”
12由于服务类型TOS,主机不可达“无路由到达主机”
13由于过滤,通信被强制禁止(忽略)
14主机越权(忽略)
15优先权中止生效(忽略)
40源端被关闭(quench)TCP由内核处理,UDP则忽略
5重定向:
0对网络重定向内核更新路由表
1对主机重定向内核更新路由表
2对服务类型和网络重定向内核更新路由表
3对服务类型和主机重定向内核更新路由表
8  0  请求回显(Ping请求)                                   
90路由器通告用户进程
100路由器请求用户进程
11超时:
0传输期间生存时间为0(Traceroute)用户进程
1在数据报组装期间生存时间为 0用户进程
12参数问题:
0坏的IP首部(包括各种差错)“协议不可用”
1缺少必需的选项“协议不可用”
130时间戳请求内核产生应答
140时间戳应答用户进程
150信息请求(作废不用)(忽略)
160信息应答(作废不用)用户进程
170地址掩码请求内核产生应答
180地址掩码应答用户进程

如果最后一列标明是“内核”,那么ICMP就由内核来处理。如果最后一列指明是“用户进程”,那么报文就被传送到所有在内核中登记的用户进程,以读取收到的ICMP报文。如果不存在任何这样的用户进程,那么报文就悄悄地被丢弃(这些用户进程还会收到所有其他类型的ICMP报文的拷贝,虽然它们应该由内核来处理,当然用户进程只有在内核处理以后才能收到这些报文)。有一些报文完全被忽略。最后,如果最后一列标明的是引号内的一串字符,那么它就是对应的Unix差错。