您的位置 首页 golang

带你深入熟悉你所不知道的ICMP协议


简介

Internet Control Messages Protocol 因特网控制 报文 协议,经常被认为是IP层的一个组成部分。它传递差错报文以及其他需要注意的信息。 ICMP 报文通常被IP层或更高层协议(TCP或 UDP )使用。一些ICMP报文把差错报文返回给用户。

ICMP是在IP数据报文中,直接传输。
不同类型由报文中的类型字段和代码字段来共同决定 ,比如 type 为8 Code 为0,那么这个为ICMP的Echo Request 如果Type 为0 Code为0 那么就为ICMP的 reply 还包含很重要的Identifier 2个字节:用于区分不同进程的应用。比如, Ping 测试,开启了两个窗口,它用于这个标识这个Request 与Reply
到低 属于第一个窗口,还是第二个窗口。

Sequence Number:2个字节:用于对应请求与响应 :比如,我们都知道一个Ping ,在cisco路由器上会发送5个,那么第一个Request Sequence number为1 ,如果收到了关于第一个Request的回应,那么这个reply的Sequence number也为1,如果丢失了,那么就没有响应。

R1——————–R2, 测试 R1发送两次 ping包,得到的 抓包 结果

可以从 id=0x0001,Seq=1/256 发现Requset 与reply都为1,第二个Requset为2,reply也为2 那么展开看看Identifier的标识,都显示为1, 开始发送第二个Ping包。

抓包结果,Id=0x0003,下面一个Identifier也为3,

Ping通过Sequence Number与ID标识,正确的回显了Request与reply的信息,并且它们的数据中通常Requset与reply是不同的,它们依靠这个计算出源到达目往返使用的时间。
下面是ICMP的详细类型与代码信息。这才是
正真 有用的东西。

CMP 另外一个重大的作用是,当一个应用程序出现某些错误或者不可达的信息时候,会返回一个ICMP差错报文,用于告诉源这个错误的信息,如果在开发程序的时 候,调用了这个机制,那么当收到这个错误信息,提交给应用程序的时候,这个程序会自动断开服务,并且报错,比如 我们在路由器上常用的telnet ,如果被ACL拒绝了,会显示一个ICMP错误信息,提示 Destination unreachable; gateway or host down,这对故障排错是很有作用的。

以太网 | IP首部 | ICMP首部 | IP 首部 | 8字节差错数据包
当 发送一份ICMP 差错报文时,报文始终包含IP的首部和产生ICMP差错报文的IP数据包的前8个字节。这8个字节标识的是是哪种协议产生的差错(比如TCP UDP,会标识它的源目端口号 TCP还会有序列号) 由于告诉源的应用程序 然后由这个应用程序发送差错提示

R1———–R2————R3 R3上写了ACL决绝R1的流量,R1 Telnet R3,返回了一个ICMP错误消息

上面已经提到过,一个差错报文始终包含IP的首部和IP数据包的前8个字节,也就是说不包含IP首部在内 ,就是TCP的源目端口与序列号。
仔细看这个抓包的结果,有两个IP头部,那么表达的意思是什么。

首先第一个IP首部,标识产生这个ICMP差错报文的源是谁(这里是R3拒绝掉流量,所以为R3) 标识的类型为3,code为13,通过上面的对应表 可以看出是由于过滤,通信不可达。

第二个IP首部,标识了这个Telnet的发起端为谁,(这里为R1) 并且标识了因为什么协议产生的差错
这 样做,是为了保证源端在运行许多应用程序的情况下,能清楚
知道是因为什么程序而出错,然后通过这个错误回显给应用程序,如果编程人员在设计代码的时候, 调用了这个机制,那么就能立即停止服务 并且报错,如果,没有这个机制,那么就会一直发送请求。比如 TFTP ,它是不会识别这种差错报文,所以 我们通常在做TFTP升级IOS 或者配置的时候,由于没打开TFTP软件,服务器发送了差错报文,但是TFTP识别不了,就会一直在请求当中。 这对我们排错也非常有用,能有效 了解到流量是在哪被过滤或者出错的。 建议在内部网络中开启ICMP的应答,在边界网络关闭,因为对于外部的恶意流量,没必要回答这个消息,浪费路由器资源,通过 no ip unreachables
也可以通过debug ip icmp,会得到一个提示。

Tracerouter的实现:Tracerouter是为了解决IP提供的可选字段中的路径记录功能不足而开发的,因为路径记录只能记录9个地址的存在,并且包括来回,并不适应现网络的环境,而Tracerouter利用 TTL ,来达到路径记录的特效。

Tracerouter的原理:在Tracerouter一个目的的时候,源端会发送3个大于30000端口的UDP报文,TTL=1,当第一个路由器收 到以后,会把TTL置0,而丢弃这个数据包,并返回一个ICMP TTL exceeded的消息,当源收到这个错误消息后,再次发送3个大于30000端口UDP报文,TTL=2,当传达到第二个路由器的时候,把TTL置0, 丢弃这个数据,并返回ICMP TTL exceeded消息,当源收到以后,继续发送UDP报文,TTL=3,这样直到到达目的地,当目的主机收到以后,发现是给自己的数据包,发现自己并没有 打开关于这个UDP端口号的服务,
(大于30000端口,就是为了确保目的端没有使用这个端口)从而回复一个“端口不可达”错误的ICMP消息,从而实现路径记录的功能,因为回显错误信息中,都包含了它们的地址。

R1———R2—————-R3, R1上Tracerouter R3,经过了2跳,所以看到有关于6个UDP的数据包,发现前面的都是 TTL exceeded,而最后一个是 Destination Unreachalbe

Tracerouter的功能,在应用中还是比较适用的,可以探测经过了哪些路由器,和路径测试,并且如果能从DNS解析到它们的名字,那么它们就会显示出来经过路由器的名字。 有些OS的实现可能不同,比如微软基于TTL值来测试的

最后一个关于分片:分片在网络中,经常出现,但是在现代的网络中 因该合理的控制 MTU ,避免不必要的分片,特别是UDP的数据,最容易造成分片,TCP由于有流量控制与 MSS 机制。 分片最容易出现在VPN的网络中,因为VPN在加密的情况下,使用ESP 、tunnel Mode、GRE、等协议,还会产生新的头部,往往会超过IP MTU 1500, 至于为什么是1500,后面会解释,先介绍下特点
IP分片:1、IP把MTU与数据长度进行比较
2、如果需要则进行分片。分片可以发生在原始发送端主机上,也可以发生在中间路由器上
3、把一个IP数据包分片以后,只有到达目的地才进行重新组装。(FR fragment)
4、重新组装由目的端的IP层来完成,其目的是使分片和重新组装的过程对运输层(TCP和UDP)是透明的。
5、已经分片的数据包有可能再次进行分片(可能不只一次)
6、当IP数据包被分片以后,每一片都成为一个分组,具有自己的IP首部,并且选择路由的时候与其他分片独立,这样,当数据包到达目的地的时候,可能不是同一路径,会失序,但是IP首部中有足够的信息让
接收端能正确的组装这些分片 比如是ICMP、TCP与UDP的流量话,那么只有第一个分片有ICMP、TCP或UDP的首部信息,其余的都没有。 而且这些头部信息,也算在数据部分里面。
7、尽管IP分片在过程中看起来是透明的,但是如果中途丢失了其中一个分片的话,那么整个数据包重新发送。
8、IP层本身没有超时重传机制————它必须依靠高层来提供可靠性(TCP有超时和重传机制,但UDP没有。一些UDP 应用程序本身提供超时和重传),当来自TCP报文段的某一片丢失后,TCP在超时后会重新发送整个
TCP报文段,不能只重传某一片数据报。
比如一个TCP的数据大小为2000,分成两个分片,但是其中一个丢失了,那么TCP会发送重传机制,但是重传的是整个数据包,因为TCP是需要对整个数据包最确认,而不是分片,而且分片对于TCP和UDP是透明的。
9、如果对数据报分片的是中间路由器,而不是起始端,那么起始端系统无法知道数据报如何被分片。所以,经常要避免分片的存在。
由 于以太网EthernetII最大的数据帧是1518Bytes,除去以太网帧的帧头(DMAC目的MAC地址 48bit=6Bytes+SMAC源MAC地址48bit=6Bytes+Type域2bytes)14Bytes和帧尾CRC校验部分4Bytes (这个
部份 有时候大家也把它叫做FCS),那么剩下承载上层协议的地方也就是Data域最大就只能有1500Bytes,这个值我们就把它称之为MTU, 也就是指IP MTU。
这个MTU就是网络层协议非常关心的地方,因为网络层协议比如IP协议会根据这个值来决定是否把上层传下来的数据进行分 片。就好比一个盒子没法装下一大块面包,我们需要把面包切成片,装在多个盒子里面一样的道理。当两台远程PC互联的时候,它们的数据需要穿过很多的路由器 和各种各样的网络媒介才能到达对端,网络中不同媒介的MTU各不相同,就好比一长段的水管,由不同粗细的水管组成(MTU不同 )通过这段水管最大水量就要由中间最细的水管决定。


比如一个 数据包为1501,如下图

分成了两个分片,其中第一个分片包含UDP的首部,而第二个分片没有标识,只有IP的首部。 这样,如果中间经过了PAT的设备或者防火墙,很有可能造成丢失,而分片的丢失,代表整个数据包全部丢弃,UDP没有重传机制。
R1———R2————R3 ,这里我把R2的出接口MTU改为200, 我用R1 Ping 大小为1000,只发送一个Request
这里得到了5个分片包,这是软件的问题,通过Sniffer 之类的抓取的话,会有6个分片,不过可以通过计算算出来,

这是第一个分片,但是不知道为什么 这个软件也没有在第一个分片上显示ICMP的头部信息,其他软件都会显示。
首先,先看下我发送了一个1000字节的数据包,这1000字节包括了 20字节的IP首部 ,和ICMP 8字节的首部,那么数据部分因该是972,先看下未分片之前的抓包。 Data 为972

为什么分片的数据部分只有176呢 ,加上20字节的首部也并没有达到接口的200,那是分片中有一个规定 在分片的时候,除最后一片外,其他每一片中的数据部分(除IP首部外的最后一个分片)必须是8字节的整数倍。 所以这里为176,而不是180.
这里注意的是,第一个分片中,通常会包含协议的头部信息,比如TCP UDP、这里因该是ICMP的头部,但这个软件并没有显示,直接显示数据大小为176,实际因该是168+ICMP 8字节头部。

之 间说因该有6个分片,而这里只显示了5个分片,可能是软件的一种优化,但是,挺不习惯的。 这里5个分片数据部分都为176,所以176*5=880, 而实际数据部分是 972+ICMP 8字节 980,所以最后一个分片的数据部分是 980-880=100
关于MTU的探测:我们通常探测MTU,因该要探测路径MUT,所谓路径MTU,是指这个源到目的中出口接口最小的MTU,因为MTU属于单方向的,而返回的MTU可能与去的MTU不一致。

在一般的路由器上都有这样的功能。路径MTU发现机制,这对我们实施VPN和修改接口MTU是很有帮助的。
环境还是之前 R1——–R2———R3 R2出接口MTU为200, R1ping的时候,把DF位置位,不允许这个数据包分片,那么当接口小的MTU丢弃这个数据包的时候,会返回一个分片不可达的差错报文 。

MTU of next hop:200 ,这对于一个VPN的网络是很有帮助的,通常我遇到的朋友在实施VPN的时候,说流量大的时候性能非常不好,速度非常慢,而且会有时候丢包,这大部分原因 是因为分片造成的,VPN的加解密本来就很消耗路由器的资源,加上对分片的处理,VPN情况下,分片也会加密,而且对于PAT的穿越性 很不好, 所以造成性能下降。
这个是通过debug显示不出来的,但是cisco 路由器上可以通过扩展Ping 来实现,而且更直观
R1——-R2———R3 这里我把R2的接口MTU改为500,方便测试,在R1是使用扩展Ping
这里的 注意是DF位置位, 并且使用路径记录, 设置包大小的范围,我这里从100开始 到700,间隔100,也是每次发100大小的包测试。

没超过MTU之前 都有路径记录,并且数据包通过了,当在600的时候,由于超出了MTU的范围,需要分片,而我又把DF置位了,它就会提示Maximum MTU 500 ,就是表示到达目的的MTU最大为500.
所以,特别在做VPN实施的时候, 不要认为隧道建立了,流量能通过了 就代表完善了,一定要注意MTU的范围,这个可以通过IP头部+其他头部信息 计算可以得出来。

特别说明

1 IP MTU
对 于网络层的上层协议而言(我们以TCP/IP协议族为例),网络层IP协议会检查每个从上层协议下来的数据包的大小,并根据本机MTU的大小决定是否作 “分片”处理。分片最大的坏处就是降低了传输性能,本来一次可以搞定的事情,分成多次搞定,所以在网络层更高一层(就是传输层)的实现中往往会对此加以注 意!有些高层因为某些原因就会要求我这个面包不能切片,我要完整
面包,所以会在IP数据包包头里面加上一个标签:DF(Donot Fragment)。这样当这个IP数据包在一大段网络(水管里面)传输的时候,如果遇到MTU小于IP数据包的情况,转发设备就会根据要求丢弃这个数据 包,然后返回一个错误信息给发送者。这样往往会造成某些通讯上的问题,不过幸运的是大部分网络链路MTU都是等于1500或者大于1500。
对于 UDP协议而言,这个协议本身是无连接的协议,对数据包的到达顺序以及是否正确到达不甚关心,所以一般UDP应用对分片没有特殊要求。对于 TCP协议 而言 就不一样了,这个协议是面向连接的协议,对于TCP协议而言它非常在意数据包的到达顺序以及是否传输中有错误发生。所以有些TCP应用对分片有要求— 不能分片(DF)。
2、 MSS
MSS是最大传输大小的缩写,它是TCP协议里面的一个概念。如下图1-1所示:

图1-1 TCP头部
注:URG等参数指的是 ACK URG PSH SIN FIN RST等参数
在 TCP报文中 MSS的位置就在选项的位置,根据RFC1323和RFC793规定,选项中内容有很多种,MSS是其中的一种,用kind=2表示;kind=1表示无 操作,kind=4、5、6、7称为选择ACK及回显选项,但是由于回显选项已经被时间戳选项取代,同时,目前定义的选择ACK选项仍未定论,也没有包括 在RFC1323中,所以具体代表什么含义还无定论。在实际网络数据传输,要求MSS+20TCP包头 +20 IP包头不大于MTU。MSS在TCP报文中是可选项,不是必选项,换句话说,MSS是可协商项,而且在协商过后,该选项内容可以改变,也可以没有;在协
MSS时,一般是建立TCP连结的两端发送Syn标志报文时互相通报,然后选取最小MSS作为双方的约定,如果双方都不通报或有一方不通报。
MSS 就是TCP数据包每次能够传输的最大数据分段。为了达到最佳的传输效能,TCP协议在建立连接的时候通常要协商双方的MSS值,这个值TCP协议在实现的 时候往往用MTU值代替(需要减去IP数据包包头的大小20Bytes和TCP数据段的包头20Bytes),所以往往MSS为1460。通讯双方会根据 双方提供的MSS值
最小值确定为这次连接的最大MSS值。

3. 区别及联系
由前面的叙述可知:MTU是一个二层的概念,以太网 最大的mtu就是1500(它是不包含二层头部的,加上头部应该为1518 bytes),当然这里说的是很常规的情况,也有些server,比如server 2008,出来的就是jumbo frame了,我们在这里讨论常规情况。IP MTU是一个三层概念,它包含了三层头部及所有载荷,根据下层为上层服务的,上层基于下层才能做进一步的扩展的原则,尽管IP MTU的变化范围很大(68-65535),但也不得不照顾以太网MTU的限制,说白了就是ip对以太网的妥协。MSS是TCP里面的一个概念,它是 TCP数据包每次能够传输的最大数据分段,不包含包头部分,它与IP MTU满足如下关系:IP MTU=MSS+20bytes(IP包头)+20bytes(TCP包头)。当然,如果传输的时候还承载有其他协议,还要加些包头在前面,简言 之,mtu就是总的最后发出去的报文大小,MSS就是需要发出去的数据大小,比如 PPPoE ,就是在以太网上承载PPP协议(点到点连接协议),它包括 6bytes的PPPoE头部和2bytes的PPP协议ID号,此时,由于以太网的MTU值为1500,所以上层PPP负载数据不能超过1492字节, 也就是相当于在PPPOE环境下的MTU是1492字节,MSS是1452字节。

4. MTU问题解决方法
通常情况下,MTU不匹配会表现为两种故障情况:
ping大包时不通无法访问某些站点
在这种情况下,通常有两种解决方法:
修改用户端MTU值(不推荐使用)修改传输路由所有设备MTU值,确保路径MTU值大于用户发送的IP报文的长度,以保证用户报文不会因为超过设备的MTU值被丢弃。主要要考虑下面几种情况:
· 对于纯IP网络,要保证:路径MTU值>最大用户报文长度
· 对于纯MPLS网络(没有VPN业务),要保证路径MTU值>最大用户报文+一层标签长度(4)
· 对于三层VPN业务,要保证:路径MTU值>最大用户报文+两层标签长度(8);
· 对于二层VPN业务,要保证:路由MTU值>最大用户报文长度+两处标签长度(8)+二层帧头长度(18)。
值得注意的是:fastethernet接口不能调整MTU,所以说在有些设备中,使用MTU命令不能解决问题的。此外,更改MTU后,如果IGP是OSPF的话,不同的MTU可能会造成OSPF 停留在INIT状态,此时需要将两端的MTU调整一致。

如果大家有任何疑问或者文中有错误跟疏忽的地方,欢迎大家留言指出,博主看到后会第一时间修改,谢谢大家的支持,更多技术文章尽在网络之路Blog,版权归网络之路Blog所有, 原创不易,侵权必究,觉得有帮助的,关注转发一波谢谢。

上一篇回顾

下一篇学习

文章来源:智云一二三科技

文章标题:带你深入熟悉你所不知道的ICMP协议

文章地址:https://www.zhihuclub.com/99869.shtml

关于作者: 智云科技

热门文章

网站地图