Skip to main content

5. 为什么说 ICMP 协议是网络最强辅助

轻解计算机网络已有高清 PDF 版本可以离线阅读了,全册 65 页,如果有需要离线版的高清 PDF 可以直接下载

ICMP 全称互联网控制报文协议(Internet Cntrol Message Protocol),是网络层的重要协议。

ICMP 是干啥用的

它到底是用来干啥的呢?为啥叫控制报文协议,控制的是什么?

ICMP 分为查询报文和差错报文两大类。查询报文是我们主动发起的,比如ping命令;而差错报文是在发生差错之后要发给源端的,这都是互联网协议模型约定好的。

ICMP的差错报文反馈发生在通信环境中的遇到的各种问题。通过这些信息,使管理者可以对所发生的问题作出诊断,然后采取适当的措施解决。

ICMP的差错报文是整个数据传输链路中非常重要的一个环节。打个比喻,差错报文就是一个只报告坏消息的信使,当数据包在网络中一路畅通的时候,ICMP 差错报文就像隐身了一样,你根本不会知道它的存在,一旦数据包在网络中碰到了各种各样的障碍,这个信使就出来活动了,它的目的只有一个,就是把这个数据包遭遇的不测通知给发送端,但是话术就那么20多种(对应差错代码)。

比如下面两个场景,想必你也有点熟悉吧。

  • 当路由器收到一份IP数据报但又不能转发时,就要发送一份 ICMP「主机不可达」差错报文。

  • 当IP数据报应该被发送到另一个路由器时,收到数据报的路由器就要发送 ICMP「重定向」差错报文给IP数据报的发送端。

ICMP 协议说明

虽然工作在网络层,看上去和 IP 协议是并列的,但是 ICMP 报文要附加 IP 头,一般被 IP 层或者更高层的协议(例如TCP或UDP)使用。很少有应用程序直接使用 ICMP 协议,除了 pingtraceroute

ICMP 协议格式

ICMP 协议格式和 IP 协议、TCP 协议这些比起来,那还是非常简单的。

类型

类型字段占用 8 位,主要定义报文的大类,比如类型为 3 统一表示的是不可达,而具体原因是什么则要由代码字段决定。

代码

代码字段同样占用 8 位,代码字段其实就是类型下的子类型,比如上面说了类型为 3 是不可达,代码为 0 表示网络不可达,代码为 1 表示主机不可达。

检验和

用于错误检查,和 IP 协议的检验和的作用一致。

内容

因为类型和代码不同,表示产生差错的原因不同,不同的原因都要有对应的描述,内容这部分就是用来描述产生差错的原因的。

接下来会举几个例子说明。

下面这张图是 ICMP 的分类,包括查询报文和差错报文,需要原始 Excel 的同学可以回复 ICMP获取源文件。

目的不可达差错报文

目的不可达是网络传输中经常遇到的问题,各位在开发的过程中可能也碰到过,尤其是做网络编程的时候,经常会碰到,比如连错IP了,比如端口设置错了。

通过上表可知,当类型为 3 的时候,都是不可达的错误,而代码可以从 0 -15,也就是说有16种不可达的具体原因。这种情况下的协议格式是下面这样的。

类型为 3 ,代码 0 - 15。检验和后面有 4 个字节的空间是不使用的,但是必须为0 ,没理由,就这样。

前面说到了内容部分是根据类型和代码不同而不同的。如果是目的不可达,也就是类型是 3 的情况下,内容分为两部分,IP首部和原始IP数据报中数据部分的前 8 个字节。

原始IP数据报中数据部分指的就是TCP或者UDP这些网络层之上的协议,拿 TCP 来说,TCP 是传输层的,当 TCP 数据报到达网络层,会加上 IP 首部,变成一个 IP 数据包。所以这里说的数据部分就是 TCP 数据报,但是这个数据报可能很大,所以只用前 8 个字节就够了,因为前8个字节包含的信息已经足够用了。

回想一下 TCP 协议的格式,前 8 个字节就是下图红框部分,包含源端口和目的端口以及序号。

例如代码为 3 的时候,差错信息是端口不可达,那有了 TCP 协议的前8个字节就能知道导致这个错误的原始数据报文中的目的端口是多少,不可达的端口也就是这个端口。也可以知道原始报文的源端口是多少,有了源端口号就知道这个数据包是哪个用户进程发出来的,就可以交给这个进程对这个差错及时进行处理了。

源端口号是关联用户进程的重要标示,比如我们开发了一个应用,这个应用占用了 8888和8898两个端口,如果安装了这个应用的机器收到了一个差错报文,而差错报文中的内容部分的原始数据包前8个字节拆解后,发现源端口是8898,那就知道这个要交给我们开发的这个应用去处理了。

下面是一个端口不可达的差错报文,用 WireSharek 监测到的格式。

telnet 一个没有开放的端口即可获得 ICMP 端口不可达的差错报文。

查询报文

将 ICMP 用作查询报文的场景比较少,用作查询报文的意思就像是使用 ARP 协议或者 TCP 协议这种,是我们主动发起的,只不过选了 ICMP 协议。

比如 pingtraceroute这两个,之后我们再讲,这两个比较有意思,对 ICMP 应用很巧妙。

另外,可以用作无盘系统启动过程中来获取自身的子网掩码。还可以用作向第三方系统查询当前的时间戳。

了解一下就可以了。

有一些场景不发送差错报文

有些场景下是不发送差错报文的,这样做的目的是为了防止ICMP差错报文带来广播风暴。

  1. ICMP差错报文本身发生差错,是不会对差错报文再发送差错报文的。是不是读起来有点绕,TCP 、UDP 出错会发送差错报文,但是 ICMP差错报文在通知源端的过程出错了,那就不管了,要不然可能就没玩没了的发了,比如源端的网线断了。但是, ICMP查询报文可能会产生ICMP差错报文,比如ping命令在传输过程中出错了,源端会收到差错报文。

  2. 目的地址是广播地址或多播地址(D类地址)的IP数据报,不发送差错报文。

  3. 作为链路层广播的数据报,不发送差错报文,ARP 就是典型的链路层广播数据报。

  4. 不是IP分片的第一片,不发送差错报文。数据如果过长,网络层是会进行分片的,这些分片实际上还是同一个数据包的,这种情况下只对第一片发送差错报文,其他分片不管。

  5. 源地址不是单个主机的数据报,不发送差错报文。 源地址不能为零地址、环回地址、广播地址或多播地址。

总结

1、 ICMP 在网络层,但要加上 IP 首部;

2、ICMP 分为查询报文和差错报文,主要用到的还是差错报文;

3、ICMP 的差错报文就好像一个只通知坏消息的信息,当数据报在网络中出现问题的时候,及时告知源端,告知的内容包括原因以及产生错误的原始数据报的必要部分;

4、有一些情况是不会发送 ICMP 差错报文的,这样做是为了防止网络风暴;