引子: 提到网络协议, 大家最先想到的肯定是TCP, IP, HTTP等这些"家喻户晓"的协议, 但是还有很多"默默无闻"的协议, 在背后做了很多的工作, 没有这些协议整个计算机网络是不能正常工作的. 这篇文章要介绍的ICMP协议就属于这样一种协议.
1. 什么是ICMP协议
ICMP协议的全称是网际控制报文协议(Internet Control Message Protocol). 它的作用是什么呢? 众所周知IP协议是一个不安全的协议, 也就是说IP协议只管传递上层协议的数据包而不管这个数据包是否有没有被目的主机正确接收, 对数据包传递进行差错控制是由上层协议自己实现的(比如TCP协议). 这样看下来貌似没有ICMP协议什么事了, 数据包的传递由IP协议做了, 数据包的差错控制由上层的比如TCP协议做了, 那ICMP协议岂不成了鸡肋? 但是要注意到, 从数据包传递到数据包差错控制之间还有一个过程, 那就是上层协议如何知道数据包出错了? 介绍到这里, 大家应该知道ICMP协议的作用是什么了, 简单的说ICMP协议的核心作用就是对上层协议报告数据包传递时的差错.
下面是ICMP协议在处于的网络层级:
icmp-layer
可以看到ICMP也是一个网络层的协议. 如果从ICMP的功能上看, 将其归到网络层也是合理的. 因为ICMP的功能就是向高层协议传递数据包的出错信息, 所以肯定不能放到传输�层. 但是我个人认为ICMP的功能其实是可以放到IP协议中进行实现的, 但是可能由于历史原因当时设计IP协议的时候并没有考虑到这一点所以后面为了实现差错控制新增了这一个协议. 不过换句话说将ICMP和IP进行分离也有一定的好处, 就是每个协议的功能更加专一, IP协议就负责传递数据, ICMP就负责差错控制.
虽然ICMP是网络层协议, 但是它不像IP协议和ARP协议一样直接传递给数据链路层, 而是先封装成IP数据包然后再传递给数据链路层. 所以在IP数据包中如果协议类型字段的值是1的话, 就表示IP数据是ICMP报文. IP数据包就是靠这个协议类型字段来区分不同的数据包的.
这里再提一点, 从上图还可以看到在ICMP旁边还有IGMP协议, 这个协议的全名叫做互联网组管理协议(Internet Group Management Protocol). 这个协议的作用简单来说就是帮助路由器来管理其所在网络中可用的主机. 这个协议的详细介绍不会在本篇涉及, 后面会新开一篇文章介绍
2. ICMP协议的格式
ICMP协议的类型分为两大类, 查询报文和差错报文. 查询报文总是成对出现.
ICMP协议的种类:
种类 | 类型 | 报文 |
---|---|---|
差错报告报文 | 3 | 终点不可达 |
4 | 源点抑制 | |
11 | 超时 | |
12 | 参数问题 | |
5 | 改变路由 | |
查询报文 | 8或0 | 回送请求或回答 |
13或14 | 时间戳请求或回答 |
从上面的表格可以看到, icmp报文的种类是有多种的, 虽然每一种类型的报文的首部都是不同的, 但是前4个字节的结构对于所有的报文来说都是一样的, 所以可以得出如下的icmp的通用结构
icmp-structure下面简单看一下ICMP头部的每一个字段的含义:
- 类型字段顾名思义是定义了ICMP报文的类型
- 代码字段表示的是发送这个ICMP报文的原因
- 校验和字段
- 首部的其余部分对于不同的ICMP是不同的
- 数据部分对于差错报告报文是用于找出引起差错的原始分组的信息, 对于查询报文是基于查询类型的额外的信息
3. 差错报告报文
虽然ICMP支持差错报告报文, 但是这个报文不是用来纠正错误的, 而是用来简单的报告错误的, 至于对于错误怎么处理是高层协议的职责. 同时, 差错报文总是发送给最初的数据源(这是因为在ICMP数据报中唯一可以使用的就是源IP和目的IP).
如下是差错报告报文的分类:
icmp-error-message-category这里不会介绍所有的差错报告报文, 只会选取其中的一个进行讲解, 其他的报文类型也全部类似, 相信掌握了一个之后其他的也很容易理解. (这个是ICMP的RFC文档, 可以供大家参考).
3.1 超时报文
因为超时报文比较容易在本机上模拟和被wireshark抓到, 所以这里选择超时报文进行讲解
3.1.1 什么是超时报文
超时报文会在两种情况下产生, 一个是由路由器产生, 一个是由主机产生.
-
由路由器产生: 我们知道在网络上传输的数据包种都有一个叫做生存时间的字段(这个字段存在于IP头中), 从名字就可以看出来这个字段是用于控制数据包的在网络上的生存时间的, 当数据包通过路由器的时候这个字段的值就会减一, 当这个字段的值变成0时就会丢弃这个数据包, 同时路由器还会向源点发送一个超时报文. 如果是这种情况下产生的超时数据包, 那头部的代码字段的值就是0.
-
由主机产生: 我们还知道如果数据包太大在IP层会将数据包进行分片并为每一个分片打上标记然后发送, 等到了目的地会根据标记将所有的分片组合成一个完成的数据包. 当主机接收到第一个分片的时候就会启动一个定时器, 如果在指定的时间没有收集到所有的分片, 主机就会将所有的分片都抛弃, 同时向源点发送一个超时报文. 如果是这种情况下产生的超时数据包, 那头部的代码字段的值就是1
3.1.2 超时报文的格式
icmp-time-exceeded-message其他类型的差错报文的格式基本都是这个结构
从这里看出来超时报文的格式和之前已经说过的ICMP的通用结构是一致的, 只不过对类型, 代码等进行了具体化.
报文的数据部分的内容是源数据包的IP头和源数据包的数据部分的头8个字节, 这个是为什么呢? 之前说过ICMP是用于向上层的协议来报告错误的, 所以ICMP得先知道将错误信息提交给上层的哪一个协议, 这个信息就保存在那8个字节中. 我们知道上层的协议都是把整体作为下一层的数据部分, 然后加上下一层的头部, 具体来说就是IP协议会把TCP或者UDP协议整体放到IP协议的数据字段中, 所以那8个字节就是TCP或者UDP的header中的一部分, 大家看一下TCP或者UDP的结构就可以知道, TCP或者UDP中的端口信息就在那8个字段范围之内. 所以根据这个端口信息就可以知道将错误传递给上层的哪个协议了.
3.1.3 超时报文协议的"真面目"
接下来我们就来看看超时报文协议到底长什么样.
在揭开超时报文的"庐山真面目"之前要做一些准备工作. 要看超时报文长什么样首先总得捕获到它, 所以先要想办法产生超时报文. 从之前的介绍中可以找到如果生存时间到了路由器就会给源主机发送一个超时报文, 所以我们用下面的命令来产生超时报文:
ping -m 1 8.8.8.8
-m参数用于设置TTL(生存时间)
在执行该命令前记得先启动wireshark
效果如下图:
terminal-ping然后打开wireshark看看抓到包
wireshark-icmp-ping可以看到这是一个ping request(ping的底层其实也是一个ICMP协议, 下一篇文章会介绍), 重点关注这个数据包的IP头. 可以看到IP数据包中的类型就是ICMP类型, 且TTL已经被设置成1了, 所以只要经过一个路由器这个数据包就会超时了, 而刚才ping的8.8.8.8是一个DNS域名解析服务器, 所以经过的路由器肯定不止一个, 所以肯定可以收到超时数据包.
看一下超时数据包:
wireshark-time-exceed-message可以看到由于我们设置的请求数据包的TTL是1, 所以在经过网关路由器的时候TTL就被减成0了, 所以网关路由器发送了一个超时数据包给我的计算机. 可以看到接收到的超时报文中的数据字段就如同之前说的是源IP头和源IP数据字段的前8个字节.
4. 未完待续
ICMP协议的大类只有两种, 但是每一类下面的种类太多所以不能全部介绍, 这篇文章先介绍了ICMP中差错报文中超时报文(这个理解了其他类看看文档也很好理解), 下一篇会介绍ICMP的另外一大类查询报文, 我们平时使用的ping, traceroute这些命令的底层就是依赖于ICMP的查询报文来实现的.
网友评论