ICMPv6(Internet Control Message Protocol for IPv6)
前言
IPv6使用的ICMPv6与IPv4使用的ICMPv4类似。定义了基本的ICMPv6的报文。用于错误报告和网络诊断。
与IPv4的ICMP不同的是,ICMPv6提供了很多IPv6协议操作必须的重要函数。例如IPv6一个重要的协议,邻居发现协议就是在ICMPv6上运行的,它执行了大量的功能,比如自动地址配置和链路层地址解析。因此任何支持IPv6的节点都必须完全实现ICMPv6。
与其他高层协议不同,IPv4与6的ICMP完全不同,TCP与UDP的分租格式及算法都是一样的,通过地址翻译机制可使得IPv4与IPv6的通信,但是两者ICMP提供相互操作确实很难的。
本篇将通篇对ICMPv6的基础学习进行记录。
ICMPv6报文
[RFC2463]定义了四种错误报文和两种信息报文。在分组处理过程中遇到问题时,就可以向源端提供报文,而信息报文则提供一些诊断功能。
4种错误报文是:
- 目标不可达(Destination Unreachable)
- 分组太长(Packet Too Big)
- 超时(Time Exceeded)
- 参数问题(Parameter Problem)
2种信息报文是:
- 回送请求(Echo Request)
- 回送应答(Echo Reply)
除了这些之外,还有一些其他的规范,例如邻居发现,节点信息查询,多播监听发现和移动IPv6都定义了一些额外的ICMPv6报文。后面在邻居发现分组都是装载在ICMPv6报文中的。[RFC2461]为ND协议定义了5个这样的ICMPv6报文。
如上图所示,就是通用的ICMPv6的报文格式。IPv6的各种拓展首部都可以放在ICMPv6首部之前。ICMPv6报文中包含以下信息:
- 类型:8比特的类型字段定义ICMPv6的报文类型,可以将ICMPv6报文划分为错误报文或者信息报文。类型0~127用于错误报文,类型128~255用于信息报文。
- 代码:8比特代码字段的值取决于报文类型,传送了更多与特定报文有关的信息。
- 校验和:校验和字段装载了伪首部加上整个ICMPv6报文的反码和的16比特反码。
- 报文主体的长度和内容取决于报文类型。由于ICMPv6首部不包含长度字段,所以ICMPv6报文的长度是从整个分组长度(通常就是IPv6首部的长度字段值)和拓展首部的长度推导出来的。
目的不可达报文
目标不可达报文可能由三个节点产生:分组的源节点、通往分组目的地路径上的中间节点、目的地节点。产生报文即可反映无法传送到分组的各种原因。目的不可达报文格式如下图所示:
目标不可达报文的类型字段值为1,代码字段可取值为0~4,表示意义如下所示:
发送方将未用字段设定为0,接收方会将其忽略。在不超过最小IPv6MTU(最大传输单元 Maximum Transmission Unit),报文主题包含了尽可能多的原始分组,存储足够 多的原始分组字节就使得源节点的高层协议能识别出引发ICMPv6错误报文的分组所属的流。
即使某些中间链路由于ICMPv6错误报文太长而将其丢弃了,ICMPv6的错误报文也不会重发,这样就可能错过避免错误的恰当时机,因此限制原始分组的最大长度是很有必要的。即使相应节点知道错误报文目的地的路径MTU长度,但是分片本身也存在缺点,所以也应当避免对分组进行分片。有的原始分组中可能包含一些扩展首部,标识流所必需的分组长度可能很长,所以,又希望尽可能多地存储原始分组。
需要注意的是,IPv4的错误报文存储的内容除了原始分组的IP首部外,只包含净荷的前八个字节,这是因为IPv4中没有可以任意长的扩展首部,这样也就足够了。
当节点的ICMPv6层收到一个目的不可达错误报文的时候,必须通知高层的进程。以采取行动及时避免错误。比如当一个有多台候选服务器的UDP客户应用程序收到端口不可达错误的通知后可即使跟换服务器使用而不是等待超时。
分组太长报文
当中间节点由于输出链路的MTU小于分组长度而无法转发分组时,就会生成分组太长报文。PMTU(Path MTU)发现记住利用分组太长报文来确定两个端点之间所有路由段的最小链路MTU。这种机制可以帮助传输节点选择正确的分组长度,使得分组可以达到目的地而不会被丢弃。
上图所示就是分组太长报文,其类型字段值为2,代码字段值为0。MTU字段存储了下一跳链路的MTU值,与目标不可达报文一样,在不超过最小IPv6 MTU情况下,报文主体中包含了尽可能多的原始分组。
然后,源节点会按照通知的MTU长度对分组进行分片。节点上的ICMPv6层收到一条分组太长报文时,必须通知高层的进程。这样,高层协议就可以调整TCP片长度以避免分片,从而优化行为。
注:因为需要通过ICMPv6目的不可达报文来通知PMTU发现机制分组超长,所以建议不要在路由器或者防火墙中滤掉这样的ICMPv6错误报文。以免停止PMTU发现机制的工作,这样有事就会造成通信的中断。
超时报文
中间路由在响应一个跳数限制字段值为0或者该路由器对跳数限制技术进行了减量操作之后跳数限制变为0的分组时,就生成超时报文。同样的,在超出分组重装时间后也会如此。
上图就是超时报文的格式,报文类型字段为3,代码字段取值为0-1,细节见上。发送方将未用字段设置为0,接收方将其忽略,在不超过最小IPv6MTU情况下,报文主体中包含尽可能多的原始分组,以便为源节点提供线索来确定出错分组。
参数问题报文
节点处理一个分组且在分组首部遇到一个问题的时候,会丢弃分组,并生成一调参数问题报文。
如上图所示就是参数问题报文(类型值为4)以及代码取值细节(取值0-2)
指针字段是原始分组中遇到错误的位置的字节偏移量,这个错误随后触发了ICMPv6错误报文。如果由于MTU限制进行了截尾操作,使得错误不在报文主题,则偏移量会执行越过ICMPv6分组末尾的位置。
报文主体中包含尽可能多的原始分组,以便为源节点提供线索来确定出错分组。
回送请求报文
节点生成回送请求报文主要是为了进行诊断,比如确定一个感兴趣节点的可达性以及往返时延。
上图就是回送请求报文格式,类型字段位128,源节点生成了标识符和序列号字段的值。这些值可以帮助源节点将回送请求报文和返回的回送应答报文对应起来。数据字段中包含零个或者这多个任意内容的字节。
回送应答报文
每个IPv6接受到一条请求报文时都必须响应,并产生一条回送应答报文。
如上所示即是回送应答报文格式。类型值为129,代码值为0,标识符和序列号字段以及下面的数据字段都是从接受到的回送请求报文中获得。
注:与错误报文不同,回送应答1分组可以大于最小MTU长度。因为一些“ping”实现会发送回送请求报文应接受回送应答报文,对数据字段进行“完整性”检测,所以,对数据字段进行截尾是不合适的。
ICMPv6报文处理规则
产生ICMPv6报文的节点根据下列规则来设置得到的IPv6分组的源地址。
- 如果ICMPv6报文是为了响应一个共目的地是分配给这个节点的单播地址的分组而产生的,就将那个单播地址作为输出ICMPv6报文的源地址。
- 如果ICMPv6报文是 为了响应一个其目的地址是一个多播组地址、 任播地址或者未分配给这个节点的单播地址的分组而产生的,那么,ICMPv6的源地址就必须是分配给这个节点的单播地址之一。 应该根据源地址选择规则来选择地址。但当所做的选择能为接收报文的节点提供更多信息时,该节点也可以使用其他地址。
- 除了回送请求报文之外,前面几节讨论的所有其他类型的ICMPv6报文的目的地都是发起ICMPv6报文的分组的源地址。回送请求报文的目的地可以是任意一个有效的IPv6地址。
ICMPv6实现在处理或生成ICMPv6分组时,必须注意下列规则。
- 如果ICMPv6层收到了一条未知类型的错误报文或信息报文,必须将分组传送给高层。节点收到一条ICMPv6错误报文或重定向报文时,一定不能生 成ICMPv6错误报文。这条规则可以防止在两个节点间形成ICMPv6错误风暴。
- 如果原始分组的目的是一一个 多播地址或者分组带有链路层多播或广播地址,节点一定不能产生ICMPv6错误报文。例外的情况是:节点可以生成一条分组太长报文,以及说明逐跳选项或目的选项错误的代码2参数问题报文。即使原始分组的目的是一个多播地址,也可以生成一条分组太 长报文,为多播信道上的PMTU发现提供方便。
- 如果原始分组的源地址不能唯一地标识一个节点,节点一定不能生成ICMPv6错误报文。这类源地址包括不确定地址,或发送错误报文的节点已知为任播地址的地址。
- 节点必须限制ICMPv6错误报文的产生速度,以缓和错误报文风暴,比如,当一个远程故障节点不停地发送错误的报文,并忽略ICMPv6错误报文时, 就可能出现这种错误报文风暴。推荐的限速方法是基于令牌桶模型(token bucket model)的,这个模型限制了生成的错误报文的平均数,但仍然允许短期内错误报文的爆发。