简介
NDP
,英文全程为Neighbor Discovery Protocol
,也即邻居发现协议,由RFC2461定义。NDP
协议实现的以下功能有
NDP
协议使用ICMPv6
报文来实现以上功能,其中为NDP
定义的ICMPv6
消息如下
这篇文章先讲地址解析跟无状态配置两部分。
地址解析
地址解析主要用到邻居请求NS
报文跟邻居通告NA
报文。通过这两种报文来解析三层地址对应的链路层地址,替代IPv4
中的ARP
广播。
如下图所示主机A
需要使用目的地址fec0::1:0:0:1:b
来访问主机B
,初始情况下A
没有B
的IPv6
地址对应的MAC
地址,因此需要借助NDP
协议来获取fec0::1:0:0:1:b
地址对应的MAC
地址。
第一步是A
发送NS
报文,目的IP
是B
的被请求节点组组播地址,目的MAC
则是B
的被请求节点组地址对应的组播MAC
地址,同时报文中携带A
自己的MAC
地址(Source Link-layer Address)。
第二步是B
发送NA
报文,B
在地址生成的时候就会加入自己的被请求节点组播组,这样他就能侦听发送到这个组播组的报文,当A
发送NS
报文的时候,B
就能收到,并回复NA
报文,报文中则会携带自己的MAC
地址(Target Link-layer Address)。
参照上图,基本可以比较明确。
做个实验抓包看,wsl
的tap0
的ipv6
地址是fd00::a
,qemu
的enp0s1
的ipv6
地址是fd00::b
。现在wsl
的tap0
地址fd00::a
来ping
这个qemu
的enp0s1
地址fd00::b
。
这是qemu
中的配置,此时邻居表中没有wsl
的fd00::a
地址对应的MAC
地址
同理,此时wsl
这边也没有
接着fd00::a
来ping
地址fd00:b
,通了之后查看邻居表
抓包链接
wsl
发出的NS
报文(Type = 135,Code = 0)
NS报文
NS
报文格式如下所示
qemu
回复的NA
报文
NA报文
NA
报文的格式如下(Type = 136,Code = 0)
其中第四点Flags
Router Flag
:表示消息发送者是否为路由器,是路由器则置1
Solicited Flag
:该NA
消息是否为响应某个邻居请求的消息,是则置1
Overide Flag
:该NA
消息是否可以覆盖已有的条目 ,是则置1
无状态配置
无状态配置在RFC2462中定义。这里的配置不止是指地址的配置,还有DNS
,路由器等。
前面的文章介绍过单播地址的无状态配置方法。
前缀公告
前缀公告,也即路由公告 ,主机从RA
报文中,获取路由器分配的前缀,简单流程如下。
一般前缀的获取会有两种情况
- 第一种如上图所示,路由器打开
RA
消息抑制功能,主机发送RS
报文,路由器收到RS
报文后,回复RA
报文 - 第二种就是主机不发送
RS
报文,但是路由器周期性的发送RA
报文,如果Linux
主机打开的accept_ra
选项跟autoconf
选项,则会自动根据RA
中的路由前缀自行构造IPv6
地址
这里就用之前文章的抓包的文件来分析RS跟RA报文了,文件链接
RS报文
RS
报文如下,在RFC2461定义 (Type = 133,Code = 0)
可以看到RS
的源地址是linklocal
地址,目的地址也是链路上的所有组播路由器
RFC2461中提到对RS
报文可以暂时忽略Reserved
部分
Future versions of this protocol may define new option types. Receivers MUST silently ignore any options they do not recognize and continue processing the message.
RA报文
RA
报文如下,在RFC2461定义,(Type = 134,Code = 0)
RA
报文可以携带的Options
信息种类则是非常的多,除了图中的地址前缀 ,DNS Server
信息,还可以用于PMTU
中传递MTU
相关信息。
hop limit
图中RA
报文的hoplimit
为64
,那么接收到此RA通告前缀构造地址的的PC
,之后发出的报文都是64
的hoplimit
flags
Mbit
M
位默认为0
,该标志指示主机该使用哪种自动配置方式获取IPv6
单播地址
- 为
0
时,收到该RA
消息的主机使用消息中包含的IPv6
前缀用于无状态地址自动配置 - 为
1
时,收到该RA
消息的主机采用有状态自动配置,也就是DHCPv6
的方式来获取IPv6
地址
Obit
Obit
默认为0
,该标志指示主机使用何种方式来配置除了IPv6
地址以外的其他配置信息
- 为
0
表示,除了IPv6
地址以外的其他参数,比如DNS Server
,主机不应该使用有状态自动配置机制来配置 - 为
1
表示,除了IPv6
地址以外的其他参数,主机需要使用DHCPv6
来配置,比如DNS
等
Mbit跟Obit结合小结
根据参考链接,下面是一些设备在Obit = 0
的测试结果,说明不同主机主机对Mbit
的处理可能不同
- 在思科的设备上,将M比特置0(默认就是0),RA消息会携带IPv6前缀信息,Win7主机收到该RA消息后,使用消息内的前缀信息构建IPv6地址,但是不会发送DHCPv6 Solicitation消息去请求地址信息
- 在思科的设备上,将M比特置1,RA消息依然会携带IPv6前缀信息,而Win7主机收到该RA消息后,依然会使用RA消息中的IPv6前缀构建IPv6单播地址,同时主机发送DHCPv6 Solicitation消息去请求地址信息
- 在华为的设备上,将M比特置0(默认就是0),RA消息会携带IPv6前缀信息,Win7主机收到该RA消息后,使用消息内的前缀信息构建IPv6地址,但是不会发送DHCPv6 Solicitation消息去请求地址信息
- 在华为的设备上,将M比特置1 ,则该接口发送的RA消息将不包含任何IPv6前缀,自然主机也就无法使用RA中的前缀构造IPv6地址。当主机收到M=1的RA消息,将会发送DHCPv6 Solicitation消息去请求IPv6地址
以上测试,思科平台采用C3640-IK9O3S-M。同时注意上述测试O比特始终为0。总结一下,其实M比特对于windows7而言,就是一个是否使用DHCPv6获取IPv6地址的开关,如果为0,则否,如果为1,则是,而且为1时并不代表就不能使用无状态自动配置来获取地址。
router time
单位为秒,主机将路由器视为缺省路由器的时间,该计时器到计数为0
时,该路由器将不会出现在主机的缺省网关列表中,不过从我做的实验来看,主机收到RA
报文,不一定会那发送RA
报文的路由器当成自己的默认网关
不过这里就会显示一个proto ra
的打印(我也不是特别清楚)
options:prefix
由RFC2461定义
Lbit
L
比特位,默认为1
,为1
时表示RA消
息中的该前缀是分配给本地链路的,因此,向包含这个指定前缀的地址发送数据的节点认为目的地是本地链路可达的。
Abit
A
比特位,默认为1
- 为
1
时,指示本地链路的主机可以使用该前缀进行无状态自动配置 - 为
0
时,表示该前缀不能用于无状态自动配置
valid && preffered lifetime
IPv6
前缀信息中有两个时间,分别是valid lifetime
跟preffered lifetime
其关系如下,他表示的是一个IPv6
地址的一个生命周期。当地址处于deprecated
状态,地址不能主动的发起连接只能是被动的接受连接,这也是为了保证上层应用而设计的,但是过了valid lifetime
时间地址就变为invalid
,这 时任何连接就会down
掉。
可以使用ip addr show
查看IPv6
地址的这两个时间点,这里特地sleep 5s
来查看时间差
DAD
Duplicate Address Detection
地址重复检测机制- 只要是获得了一个
IPv6
地址或者是启动一个IPv6
接口(link down and link up),无论是有状态或者是无状态自动配置的,都需要先经过DAD
,保证在链路上的唯一性(就算是Linklocal地址也要做DAD
检测) DAD
使用NS
跟NA
消息实现
工作流程如下
我们的2000::1
这个时候还没通过DAD
检测,实际上是一个tentative
地址(但实际上主机A
还是会加入这个2000::1
对应的被请求节点多播组)。所以源IP
是::
,也就是128
个0
,作为NS
消息的源IP
,而目的IP
则是2000::1
对应的被请求节点组播地址。
如果1秒后没有检测到冲突,A
就会发送一个NA
消息,宣告大家我将正式使用这个IPv6
地址。如果有其他设备已经使用了这个地址,就会发送一个NA
消息,这样主机就知道这个地址已经有人再用了,就会放弃这个地址。如下所示。其实这个过程就很像IPv4
中的ARP Probe
。
内核接口/proc/sys/net/ipv6/conf/xxx/dad_transmits
用来表示需要dad
检测的次数,如果为0
则表示不进行dad
检测
抓包文件链接上传于此
DAD NS
报文如下
DAD NA
报文如下
当然前面有提到,一开始当地址为tentative
状态时,但还是会加入相应的多播组。如果碰到如下两台设备都要做DAD
检测,会是怎样的结果呢?
- 若2个节点配置相同地址,同时作重复地址检测时,该地址处于
tentative
状态,当一方收到对方发出的DAD NS
,则接收方将不启用该地址 - 一种极端的情况,如果同时收到
NS
报文,则两端都放弃改地址
前缀重编址
RA
报文中的前缀是有valid lifetime
跟preffered lifetime
的,而前缀重编址,让新老前缀平滑过渡,则是通过利用IPv6
地址生存周期,把preffered lifetime
设置为0,使地址处于deprecated
状态,地址不能主动的发起连接只能是被动的接受连接。而当valid lifetime
过去之后,地址变为invalid
则不可用了。
这样灵活的设置地址生存时间,实现新老前缀平滑过渡,无需在主机终端上消耗大量的手工劳动重新配置地址。
这边可以用radvd
去做这个前缀过渡(图中的AdvSendAdvert
需要改为off
,不然为on
的话,radvd
会一直发送RA
报文)
不过我发现地址处于deprecated
状态依旧可以进行通信?