当出现网络不通的情况时,我们往往第一反应是ping
一下或者telnet
下端口。如果不通,往往需要traceroute
跟踪下路由看看到哪一跳不通,好方便定位问题。由于telnet
用的TCP
协议,暂时我们不去讨论,但是ping
和traceroute
都是基于ICMP
协议,我们来讨论讨论,了解它的细节帮助我们以后遇到网络问题更有头绪,虽然不要我们研发来处理,但是会提高工作沟通的效率!
由于就像是获取情报的侦察机,故理解为网络侦察机,帮助我们前方探路,留下重要记录,解决繁杂的网络问题!
一、ICMP协议
我们上面说了ARP
协议,除了 ARP
协议,OSI 第 3 层还有其他的协议,比如这里要说的ICMP
协议。ICMP
是 Internet Control Message Protocol
的缩写,表示 “互联网控制报文协议”。
其实这个协议我们已经在不知不觉中已经使用到了,比如我们的ping
命令或者traceroute
命令。并且我们不能忘记ARP
协议不是真正的第三层协议:
ARP
协议 “跨接” 了 OSI 第 2 层和第 3 层;ARP
协议的作用不是传输信息,而是将 IP 地址和 MAC 地址相关联。
⭐那么回到ICMP
协议,ICMP
协议也不会与 IP
协议竞争,因为它的目的不是传输信息。ICMP
协议的作用是控制传输错误,并帮助我们进行网络调试。
因此注意,ICMP
是帮助我们快速排查网络问题的工具。因此,ICMP
协议是 IP
协议的 “补充”,或更准确地说,是 TCP/IP
协议栈的 “补充”,ICMP
协议使得我们在出现问题时更容易理解网络上到底发生了什么。
二、ICMP协议的角色
ICMP 协议基本上有两个主要角色:差错通知和信息查询。
上半图:IP 数据包被对方的计算机处理的过程中,发生了什么错误时被使用。不仅传送发生了错误这个事实,也传送错误原因等消息。
下半图:在送信方的计算机向对方计算机询问信息时被使用。被询问内容的种类非常丰富,他们有目标IP 地址的机器是否存在这种基本确认,调查自己网络的子网掩码,取得对方机器的时间信息等。
三、实际抓包
废话不多说,我们直接来通过抓包来学习ICMP
协议!我随便找了一个网站做下ping
的操作,比如:
ping shop.t.mukewang.com
我们看到在windows
下默认会尝试4次的交互,因此我们抓包中也可以看到四对请求和回执:
我们拿84号的请求帧来看看里面的情况:
我们来看下上图中的IP
数据的部分。其中用的协议是IPV4
,并且头部长度为20字节,有一个很重要的参数是Protocol
,这里指明是ICMP
协议。
好了,还记得我们之前抓的TCP
报文吗?这里的类型就是对应的TCP
。下面观察ICMP
的部分,我们可以看到,ICMP
有点像TCP
,这里说的像是说我们可以看到ICMP
跟TCP
一样是基于IP
协议的。
Type
: 该字段有 1 个字节,表示特定类型的 ICMP 报文。Code
: 该字段有 1 个字节,进一步细分ICMP
的类型。如上图所示,Type
的值为 8,Code
的值为 0,表示回显请求。Checksum
: 该字段有 2 个字节,表示校验和。Identifier
: 该字段有 2 个字节,用于匹配Request/Reply
的标识符。Seq Num
: 该字段有 2 个字节,用于匹配Request/Reply
的序列号。Data
: 数据载荷。
我们结合实际抓包,实际上整个ICMP
报文的格式如下图所示:
学习知识要抓重点,核心中的核心字段是type
和code
两个。所有ICMP
用来交流错误通知和信息询问的报文,都是由类型和代码的组合来表示的。RFC 定义了多种组合:
可以看到,type
等于8并且code
等于0的时候表示ping
请求,对应我们上面抓包的值,那么回应呢?type
等于0并且code
等于0的时候表示ping
应答。
我们简单看下reply
包里面字段验证下吧!
当然了,上面演示的都是正常无错误的情况,实际上只有发生错误的时候,这里的code
和type
才更加有存在意义。
例如,type
为 3 的 ICMP
数据包说明 “目标不可达”(Destination Unreachable
)。
如果我将数据包发送到一台机器,却收到 type
为 3 的 ICMP
消息,那么我就知道网络上存在问题,不能到达目的地。
当 type
为 3 时,消息的 code
则会告诉我到底是什么导致了此网络问题:
如果
code
为 0,则说明该网络不可达,Network Unreachable
。一般来说,是因为途中的一个路由器的路由表中没有到达此目标网络的路由记录;如果
code
为 1,则说明该机器不可达,Host Unreachable
。应该是最后一个路由器发送了ARP
请求,但没有得到响应。
除此之外,还有其他的自动消息,以下是比较常用的自动消息:
type
(类型)为 5 的自动消息:“ICMP Redirect
”,表示 “ICMP
重定向”,表明到目标有一条更短的路径;(当路由器通过接收数据包的接口返回数据包时,会使用type
为 5 的自动消息。这意味着不一定要经过此接口,而有一条更短的路径。看到此消息的网络管理员就可以改善网络上的路由。)type
(类型)为 11 的自动消息:“TTL exceeded
”,表示 “超过TTL
”。TTL
我们以前已经介绍过了,是Time To Live
的缩写,表示 “生存时间”。所以TTL exceeded
表明数据包的生存期已到期,需要丢弃此数据包。
对于第二点,IP头里面有个叫TTL
的字段,之前说过,是为了避免消息进入死胡同出不来:
表示数据报在网络中的寿命。由发送数据报的源点设置这个字段,其目的是为了防止那些无法交付的数据报无限制的在互联网中兜圈子(例如从路由器R1转发到R2,再转发到R3,然后又转发到R1),因而白白浪费网络资源。数据报每经过一个路由器,这个值就会减1,当减至0时,就丢弃该数据报。window系统默认为128。发送 ICMP 回显应答时经常把 TTL 设为最大值 255。
就像打乒乓球一样,来来回回无休止。一段时间后,许多数据包将执行相同的操作,网络就会饱和。
因此,如果一个数据包在两个路由器之间像打乒乓球那样无休止地互相传输,则当 TTL
达到 0 时,该过程将停止。由于有了 TTL
,我们可以避免由于错误的路由配置而导致网络饱和。ICMP
的 “TTL exceeded
” 消息也有助于了解网络问题。
四、调试网络的有用消息
这已经不是陌生的知识点了,就是 ping
和 traceroute
命令,这些 ICMP
数据包可以帮助我们调试网络问题。
实际上我们已经在上面使用了ping
命令,我们再来总结下:ping
命令实际上是两种类型的 ICMP
消息的组合,即 type
为 8 的 “echo request
” 消息和 type
为 0 的 “echo reply
” 消息。
那么很显然,ping 的原理是,一台机器发送 “echo request
” 消息,目标机器以 “echo reply
” 消息响应。这就是为什么当我们从一台机器成功 ping
通另一台机器时,我们知道两个方向的路由都是正确的。
traceroute
命令则更复杂一些,它使用了 ICMP
的 “TTL exceeded
” 自动消息。原理如下,其实也很简单:
假设我想用 traceroute
命令来查看从我这台机器到达 Github
的主机的路径。我怎么知道我经过的第一个路由器的 IP 地址呢?
我可以借助我这台机器的路由表,但是这样只能查找到第一个路由器的 IP
地址。
那么如何才能自动拿到第一个路由器的IP
地址呢?
提示告诉我们使用 ICMP
的 “TTL exceeded
” 数据包。因此,解决方法可能是让经过的第一个路由器生成此数据包。这样一来,当我这台机器收到此错误消息,我就可以在数据包中看到第一个路由器的地址。
那么,如何能让经过的第一个路由器生成 ICMP
的 “TTL exceeded
” 错误消息呢?
只需将数据包中的 IP
报文的 TTL
的值设置为 1 即可。这样,第一个路由器接收到数据包,将数据包中的 TTL
值减 1,因此 TTL
的值就变为 0,第一个路由器就必须将该消息丢弃,并向我这台机器发送 ICMP
的 “TTL exceeded
” 错误消息。这样,我就能知道第一个路由器的 IP
地址了!
既然我们已经知道了原理,那么要知道第二台路由器的地址,只需将数据包中的 TTL
值设置为 2 即可。以此类推,我们就可以知道经过的所有路由器的 IP
地址了!
客户端发送一个
TTL
为1的ICMP
请求回显数据包,在第一跳的时候超时并返回一个ICMP
超时数据包,得到第一跳的地址。客户端发送一个
TTL
为2的ICMP
请求回显数据包,得到第二跳的地址。客户端发送一个
TTL
为3的ICMP
请求回显数据包,到达目标主机,目标主机返回一个ICMP
回显应答,traceroute
结束。
老规矩,抓个实际的网路包来看看吧!
我们可以看到,向每一跳的路由器发出了三个ICMP
包。那么对应抓包显然每个节点都会请求三次:
并且我们可以看到,IP
头里面的TTL
值为1,我们顺便看下回执:
可以看到,一跳被消耗了,第一跳的路由器192.168.101.1
丢弃报文放弃转发并且回复我们客户端Time-to-live exceeded
。
我们再来看个第六跳吧,我们可以看到第六条的信息为:
6 19 ms 9 ms 5 ms 222.190.59.61
显然这一跳的路由器地址为222.190.59.61
,根据设想,请求的ttl
是6,并且222.190.59.61
给我们回复Time-to-live exceeded
。
五、总结
ICMP
是帮助我们快速排查网络问题的工具。因此,ICMP
协议是IP
协议的 “补充”,或更准确地说,是TCP/IP
协议栈的 “补充”,ICMP
协议使得我们在出现问题时更容易理解网络上到底发生了什么。ICMP 协议基本上有两个主要角色:差错通知和信息查询。
ping
命令实际上是两种类型的ICMP
消息的组合,即type
为 8 的 “echo request
” 消息和type
为 0 的 “echo reply
” 消息。ICMP
报文头中核心中的核心字段是type
和code
两个。所有ICMP
用来交流错误通知和信息询问的报文,都是由类型和代码的组合来表示的。type
为 3 的ICMP
数据包说明 “目标不可达”(Destination Unreachable
)。如果
code
为 0,则说明该网络不可达,Network Unreachable
。一般来说,是因为途中的一个路由器的路由表中没有到达此目标网络的路由记录;如果
code
为 1,则说明该机器不可达,Host Unreachable
。应该是最后一个路由器发送了ARP
请求,但没有得到响应。
type
(类型)为 5 的自动消息:“ICMP Redirect
”,表示 “ICMP
重定向”,表明到目标有一条更短的路径;(当路由器通过接收数据包的接口返回数据包时,会使用type
为 5 的自动消息。这意味着不一定要经过此接口,而有一条更短的路径。看到此消息的网络管理员就可以改善网络上的路由。)type
(类型)为 11 的自动消息:“TTL exceeded
”,表示 “超过TTL
”。TTL
我们以前已经介绍过了,是Time To Live
的缩写,表示 “生存时间”。所以TTL exceeded
表明数据包的生存期已到期,需要丢弃此数据包。如果一个数据包在两个路由器之间像打乒乓球那样无休止地互相传输,则当
TTL
达到 0 时,该过程将停止。由于有了TTL
,我们可以避免由于错误的路由配置而导致网络饱和。ICMP
的 “TTL exceeded
” 消息也有助于了解网络问题。traceroute
的工作原理 是利用ICMP
差错控制报文中的TTL
超时会回头向源点发送一个时间超时报文。例如A 主机traceroute
B主机,A会封装一些分组,这些分组很特殊,例如第一个分组的TTL
设置为1 ,第二个分组的TTL
设置为2 以此类推.......当第一个分组到达第一个路由器时,发现TTL变成了0就会给源主机发送一个时间超时报文,这也就知道了这个分组所经过的一个路由器,同理可得。当最后一个分组到达B主机时。收集每个时间超时的报文中的IP
就获得了A主机到B主机的路径。
OK,ICMP
协议的介绍暂时告一段落。下面进军 OSI
第 4 层。