题目
什么是 ICMP 协议?其工作原理和应用场景是什么?
答案
@[toc] --- ## 什么是 ICMP IP 协议作为一种提供不可靠数据交付的网络层协议,在传输的过程中,分组后的 IP 数据报可能会发生丢失、重复、延迟和乱序等各种情况,但是 IP 协议对这些糟糕的情况并不拥有有效的检测和弥补措施,当然更不会将这些结果通知收发双方。 针对于此,**网际控制报文协议**(Internet Control Message Protocol,**ICMP**)的功能有两点: - 功能 1:确认 IP 数据报是否成功送达目标地址 - 功能 2:如果某个 IP 数据报因为某种原因未能正常到达目的地,则由 ICMP 负责通知具体的原因 ## ICMP 的工作原理 ICMP 协议通过发送 **ICMP 报文**来通知具体出错原因。 注意,ICMP 报文既不是由发送方发出的也不是由接收方发出的呢,而是**由路由器发出来的**。 举个例子:主机 A 在不知情的情况下向主机 B 发送了数据包,而主机 B 正在呼呼大睡。主机 A 和主机 B 不在同一个局部网内,假设它俩之间会经过两个路由器,看下图: ![](https://cs-wiki.oss-cn-shanghai.aliyuncs.com/img/20210426173258.png) 众所周知,除了 IP 地址我们还需要 MAC 地址才能确保数据包精准的找到传送方向,因此,路由器 2 为了知道主机 B 的 MAC 地址,它会广播一个 ARP 请求报文,希望获取到主机 B 的 MAC 地址,而主机 B 都关机了自然也就无法应答这个请求报文了。 为此,路由器 2 会一遍又一遍的重新发送着 ARP 请求报文,在多次无果后,路由器 2 就会返回一个 ICMP Destination Unreachable 的包给主机 A,通知主机 A,非常遗憾,您发往主机 B 的包未能成功抵达。 ## ICMP 报文的类型 ICMP 报文会作为数据部分被 IP 协议添加 IP 首部封装成 IP 数据报进行明文传输,由 IP 协议指定源 IP 地址和目的地址 ![](https://cs-wiki.oss-cn-shanghai.aliyuncs.com/image-20230329152750418.png) ![](https://cs-wiki.oss-cn-shanghai.aliyuncs.com/img/20210426185710.png) 其中,ICMP 报文类型就由 ICMP 首部的前 4 位的字段 “类型” 来表示,大体上可以分为两种: - 查询报文 - 差错报文 1)**查询报文**:用于主机进行诊断的查询消息。常见的 ICMP 查询报文类型有以下几种: - 回送应答(Echo Reply),对应 ICMP 报文首部类型字段的值:`0` - 回送请求(Echo Request),对应 ICMP 报文首部类型字段的值:`8` 回送消息是用于进行通信的主机或路由器之间,判断所发送的数据包是否已经成功到达对端的一种消息。 可以向对端主机发送 ICMP 回送请求的消息(Echo Request,类型 8),也可以接收对端主机发回来的 ICMP 回送应答消息(Echo Reply,类型 0) ![](https://cs-wiki.oss-cn-shanghai.aliyuncs.com/img/20210426182137.png) 2)**差错报文**:用于通知主机出错的原因。一旦 IP 协议发现某个 IP 数据报出错了,首先就会毅然地丢弃出错的这个 IP 数据报,然后发送 ICMP 差错报文。常见的 ICMP 差错报文类型有以下几种: ## ICMP 的应用 ### ping:基于 ICMP 查询报文 `ping` 命令是基于 ICMP 回送消息实现的。 `ping` 这个单词源自声纳定位,而这个命令的作用也确实如此,它发送类型为 0 的 ICMP Echo Request 消息,收到请求的主机则用类型为 8 的 ICMP Echo Reply 消息进行回应。`ping` 就会计算发送 Requenst 和接收到 Reply 的消息间隔时间,并计算有多少个包被送达,丢失了多少个包等。用户就可以据此判断网络大致的情况。 ![](https://cs-wiki.oss-cn-shanghai.aliyuncs.com/img/20210426182137.png) ### tracerout:基于 ICMP 差错报文 `traceroute` 命令是基于 ICMP 差错报文实现,在 Linux 下这条命令是 `traceroute`,在 Windows 是 `tracert` 大家可能会觉得 ICMP 差错报文是只有在通信异常的时候才会生成,其实不然,`traceroute` 命令就是一个例外,它会使用 ICMP 的规则,**故意制造一些能够产生异常的场景** ![](https://cs-wiki.oss-cn-shanghai.aliyuncs.com/img/20210426220326.png) `traceroute` 命令有两大作用: 1)**故意设置特殊的 TTL(IP 头中有一个 `TTL` 字段,是 IP 数据报可以经过的最大路由数,每经过一个处理他的路由器此值就减 1,当此值为 0 则数据报将被丢弃),来追踪去往目的主机上沿途经过的路由器**。 具体来说,就是发送端主机会不断的向接收端主机发送 **UDP 报文**,UDP 报文被封装成 IP 数据报,同时将 TTL 从 1 开始按照顺序递增。 比如说,将 TTL 设置 为 1,那么遇到第一个路由器的时候,这个 IP 数据报就会被丢弃,接着返回 ICMP 差错报文,类型是 **ICMP 超时消息** 接下来将 TTL 设置为 2,第一个路由器过了,遇到第二个路由器时这个 IP 数据报就会被丢弃,接着返回 ICMP 差错报文 ...... 这样,traceroute 就拿到了所有路由器 IP。 2)**故意设置不分片,从而确定路径的最大传输单元 MTU**。 某些情况下我们并不知道路径的 MTU 大小,所以我们需要某种手段去获取 MTU,才能控制发送的数据包的大小。 发送端主机要做的工作很简单,就是像往常一样发送 IP 数据报,但是将 IP 首部的【标志(Flag)】置为 1 代表不能分片 这样,如果 IP 数据报的长度超过了 MTU,该数据报会被路由器直接丢弃,并且给发送端主机发送 **ICMP 目标不可达消息**,其代码为 `4`,即**需要进行分片但设置了不分片位** 这样,发送端主机每次收到 ICMP 需要进行分片但设置了不分片位消息时就减小 IP 数据报的长度,直到顺利到达目标主机。