邻居发现协议(NDP)替代了IPv4的ARP,并且添加了新的功能。它的所有功能都是基于ICMPv6报文来实现。NDP基于ICMPv6实现,NDP使用的所有报文均封装在ICMPv6报文中,所以NDP被认为是3层协议。在三层完成地址解析,主要好处是:地址解析在三层完成,不同的二层介质可以采用相同的地址解析协议。可以使用三层的安全机制避免地址解析攻击。使用组播方式发送请求报文,减少了二层网络的性能压力。
这个功能对应的是IPv4的ARP(地址解析协议)。主机A要和主机B通信,需要知道主机B的二层地址。
地址解析使用两种报文,邻居请求NS(neighbor solicitation),邻居通告NA(neighbor advertisement)。
在上图中主机A发给主机B的报文为组播报文,主机B发给主机A的是单播报文,其他无关的路由器是不会回应的。
上图过程可以这样描述:
主机A:谁叫李法拉?你住在哪里?
主机B: 我叫李法拉,住在MAC地址的xxxxx。
主机C: 不是叫我,不管他。
在网络拓扑中,邻居的状态可能会随时发生变化,包括掉电,接口卡插拔等。如果目的地失效,则必然无法通信,如果路径失效,可能找另外一条路径来走。因此节点需要维护一张邻居表,可以了解邻居的状态。 RFC2461中定义了5种邻居状态,分别是:
1、未完成(Incomplete,还有没有票?不知道啊)。表示正在解析地址,但邻居链路层地址尚未确定。
2、可达(Reachable,我就是今天的票!)表示地址解析成功,该邻居可达。
3、陈旧(Stale,我的这张旧船票还能登上你的破船吗?)表示可达时间耗尽,未确定邻居是否可达。
4、延迟(Delay,破船到底还有没有?),表示未确定邻居是否可达。DELAY状态不是一个稳定的状态,而是一个延时等待状态。
5、探查(Probe,这张票还能用吗?能到xx地方吗?),节点会向处于PROBE状态的邻居持续发送NS报文。
Empty表示邻居表项为空。
是在接口使用某个IPv6单播地址之前进行的,主要是为了探测是否有其它的节点使用了该地址。尤其是在地址自动配置的时候,进行DAD检测是很必要的。
DAD机制通过NS和NA报文实现。节点会发送NS报文(有人叫张拉拉吗?),其源地址为未指定地址,目的地址为接口配置的IPv6地址。如果收到自己的报文(听到自己的回音,奥,自己的声音不管他),直接忽略。在NS报文发送到链路上后,如果在规定时间内没有收到应答的NA报文,则认为这个单播地址在链路上是唯一的,可以分配给接口(好了,我就叫张拉拉了);反之,如果收到应答的NA报文(一个响亮的声音回来,我就叫张拉拉!呀丫丫,有人和我同名啊,算了,改个名字吧),则表明这个地址已经被其他节点所使用,不能配置到接口。
路由器发现功能用来发现与本地链路相连的设备,并获取与地址自动配置相关的前缀和其他配置参数。
路由器周期发送RA(route advertisement)消息。每台设备为了让二层网络上的主机和设备知道自己的存在,定时都会组播发送RA报文,RA报文中会带有网络前缀信息,及其他一些标志位信息。
主机发送RS(route solicitation),路由器回应RA(route advertisement)。 很多情况下主机接入网络后希望尽快获取网络前缀进行通信,此时主机可以立刻发送RS报文,网络上的设备将回应RA报文。主机收到包含路由信息的RA报文后,会更新自己的路由表。当主机向其他设备发送报文时,通过查询该列表的路由信息,选择合适的路由发送报文。
当网关路由器发现更好的报文转发路径时候,会用重定向报文告诉主机。
上图主机H1要发送数据到网络N2,经过路由器R1,由R1再转发到到R2,但路由器R1发现R2和它是同一网段,并且R2是直接连接着网络N2,这时候路由器R1就发送重定向报文(NDP redirect)告诉主机H1,以后再给网络N2的报文就直接给R2好了,别那么绕弯子,费劲!
在重定向功能中,只有主机才会处理重定向报文,在图例中,H1会更新自己的路由表,下次再发送到N2的报文便会直接转发到R2。
NDP定义了5种ICMPv6报文类型:
类型133 路由器请求(RS):由主机发起,用来请求一个路由器发送一个RA
类型134 路由器通告(RA):由路由器发起,通告路由器的存在和链路的细节参数(链路前缀,MTU,跳数限制等),周期性发送,也用于答RS。
类型135 邻居请求(NS):由节点主机发起,用来请求另一台主机的链路层地址,或实现地址冲突检测、邻居不可达检测。
类型136 邻居通告(NA):有节点发起用来响应NS,如果一个节点改变了他的链路层地址,那么它能够主动发送一个NA来通告这个新地址。
类型137 重定向(Redirect)
NDP消息通常在链路本地的范围内收发。
为了进一步增强安全性,承载所有NDP消息的IPV6数据包的跳数限制为255,如果收到的数据包跳数小于255的,说明该数据包最少已经经过一台路由器,因此该数据包应该被丢弃。这样可以防止NDP受到来自不与本地链路相连的源节点的攻击或欺骗。