ICMP 协议
在之前网络层的介绍中,我们知道 IP 提供一种无连接的、尽力而为的服务。这就意味着无法进行流量控制与差错控制。因此在 IP 数据报的传输过程中,出现各种的错误是在所难免的,为了通知源主机 IP 数据报传输过程中遇到的问题,因此设计了因特网控制报文协议(ICMP)。
虽然说 ICMP 协议将 IP 协议封装在内部,所以大多数人将 ICMP 视为传输层的协议,但实际上 ICMP 是 IP 协议的重要组成部分,所以将其放在网络层更为合适。
ICMP 的报文一般有两种,查询报文和查询报文。
查询报文:例如我们在使用 ping 命令,子网掩码查询,时间戳查询等情况时,都会发送查询报文。
差错报文:而差错报文是在当对应的路由器或者终端设备收到查询报文后,产生了一系列问题。把出现的问题,回复给发起者的报文就是差错报文。
但考虑到整体网络资源的占用上,在如下情况下,是不会产生差错报文的:
- 差错报文不会产生差错报文 - 防止 ICMP 无限产生和传送差错报文
- 目的地址是广播或多播的 IP 数据包
- 链路层广播的数据包
- 不是 IP 分片的第一片 - IP 是尽力而为,自然不需要可靠性
- 源地址不是某个主机的数据包
ICMP 类型
由于 ICMP 本身就是为了弥补 IP 协议不可靠的特性,起到排错目的,所以它的 Header 并不复杂。
![f0fc7c04b2336e6b39f9507b00feba86.png](https://i-blog.csdnimg.cn/blog_migrate/2b7fa07c3c21b6aa96289cbed65ba93d.png)
正如图中所示的,对于 ICMP Header 来说,比较重要的就是 Type (8 bit)和 Code (8 bit) 字段,用来表示各种错误的情况。
其中完整的介绍可以参考这篇 wiki,下面就介绍上常用的部分。
![9a798b6fda13570b568c01eaf73cc623.png](https://i-blog.csdnimg.cn/blog_migrate/e16d13241fef84ece6500ad9179005ca.jpeg)
下面我们抓个包,来看一下。
Ping 命令测试网络连通性
这里在主机上 Ping 下百度,通过 Wireshark 抓到的数据包如下:
![71fb5ae0923a7189242ec376f417dd0f.png](https://i-blog.csdnimg.cn/blog_migrate/b0d3c237db1c8be938488108942dc9a3.jpeg)
先看一下 Echo Request 包,对应 Type 为8,Code 为0:
![71fb5ae0923a7189242ec376f417dd0f.png](https://i-blog.csdnimg.cn/blog_migrate/b0d3c237db1c8be938488108942dc9a3.jpeg)
Echo Reply 包 - Type 为 0,Code 为 0:
![da54b741ff442db1294a7d5d01c358c8.png](https://i-blog.csdnimg.cn/blog_migrate/4bec9631920f03a3d26212f9bb5dc7e1.jpeg)
Traceroute 测试网络连通性
在 IP 协议中,为了防止出现环路而设置了 TTL 字段。该字段也在 traceroute 中起到了很大的作用,通过设置 TTL 的数值,来获取数据报的传递过程。
TTL:当 IP 数据包进行传送时,每经过一个路由器,TTL 指就会减一,当 TTL = 0 时,该 IP 数据报会被丢弃。
下面就来了解下 Traceroute 的通信过程,用到的拓扑如下:
![b493b77d68bb4cff3300c01bded1d092.png](https://i-blog.csdnimg.cn/blog_migrate/b0d2897b8f267e9770886eb6bae643ba.png)
当主机收到目的主机的 IP 后,会给目的主机发送一个 TTL = 1 的 UDP 数据包。
![9b172b936ec00a5c72f22d557d063579.png](https://i-blog.csdnimg.cn/blog_migrate/ac7bcd5ef594f67bbf3d52a93542e476.jpeg)
而经过第一个路由器后,TTL - 1 变成 0.这时路由器会把数据报丢弃,然后把丢弃的数据包的 IP 头部封装起来,回复主机一个差错报文。如下:
![96b035308bfeed15b0a3cf389dd11313.png](https://i-blog.csdnimg.cn/blog_migrate/ff89a743e6ec2a11faa80a2fa80f5fc8.jpeg)
这个过程主机会发三次,也就是说会产生 3 个 TTL =1 的 UDP,如下
![9d8d3569925f903e470b58a6e6da8b81.png](https://i-blog.csdnimg.cn/blog_migrate/654a8580ca461a4b917764737b14f50d.png)
接着会在再次发送 3 个 TTL = 2 的 UDP 报文,如下
![6205ac4ac95cfba24a603921c1ba542e.png](https://i-blog.csdnimg.cn/blog_migrate/1a83f3ab6eb2ee986014006810c515f5.jpeg)
第二个路由器,会再次向主机发送一个差错报文,如下:
![49425485429f0cf7b93d980085ee93d9.png](https://i-blog.csdnimg.cn/blog_migrate/9e8422cac6c99aa8bf263f38aef66958.jpeg)
这里需要注意的是:由于第二台路由器已经相当于是目的地,所以将数据包拆到传输层,但由于传输层上的端口标识了应用层的应用,而在该路由器上不在该应用,进而回复了端口不可达的报文。
由于图中只经过 2 个路由器,所以截止发送到 TTL = 2
![fbe13a3cff36f9fd3cb28de741b85a1d.png](https://i-blog.csdnimg.cn/blog_migrate/c52cf6e8d25027a80fdcba69a2a870ec.png)
并且我们可以从 TTL = 2 的回复差错报文看出,只有两个差错报文。其中有个差错报文出现了丢失,并且没有给主机回复差错报文丢失的情况