目录
- 背景
- ipv6 访问 ipv4
- NAT64
- nat64 rfc
- dns64 rfc
- nat46
- Dual stack: 双栈
- 程序实现双栈
- 查看一个域名是否支持ipv6的4A记录
- 客户端的连接处理
- 参考
背景
IPv6出来已经很多年,虽然距离普及还很远,但项目里要加上,IPv6最大的问题是包格式与IPv4不兼容。
- ipv4 数据包格式:
ipv4 RFC791: 格式
- ipv6 数据包格式
ipv6 rfc2460 格式
粗略一看,这个应该是兼容的啊。毕竟前4bit都是版本号,拿到数据包时,判断一下版本号,根据不同的版本号做不同的处理,即可做兼容,很多软件都是这么做的。
然而问题是,IP数据包涉及的不仅仅是软件,还有硬件,比如路由器。当一个数据包经过路由器时,它需要解析包头里的数据,得到目标地址,才知道数据包转发到哪里。如果这个包头格式不一样了,那这个数据包就无法正常转发。对于软件,可以重新发布一个版本来解决,但绝大部分的家用路由器,是不带更新功能的,那要让它支持Ipv6,只能扔掉买一个新的。在现实生活中,一个数据包的传输,可能会经过很多路由的,例如:
当这个问题扩大到整个社会,就会有无数的家庭路由,无数的小区路由。ISP的主路由和服务器由于商业的驱动,可以及时更新,而无数的家庭路由,无数的小区路由,显然没法短时间内全部更新,也没必要更新。
目前的情况是,客户端、路由器都有可能支持IPv6,也有可能都不支持,因此IPv4和IPv6的兼容是必须得做的,不然就可能失去一部分用户了。
这个兼容是指“不管客户端以及所经过的路由是IPv4还是IPv6,不管服务器是IPv6还是IPv4,两者都能正常进行交互”。排除正常的条件((如:客户端为IPv6,服务器也是IPv6)的情况,需要特殊处理的情况为IPv4访问IPv6和IPv6访问IPv4。
ipv6 访问 ipv4
NAT64
既然IPv6和IPv4兼容性是由它们的IP报文不一样,那么可以弄一个专门转换报文的服务,即NAT64(Network Address Translation IPv6 to IPv4)。
注: 比如 DPVS中的 NAT64 功能。
一个IPv6客户端想把一个报文发往一个IPv4服务器,就需要一个包含IPv4地址的IPv6地址,这由一个特殊的DNS服务提供,即DNS64。
服务器只有ipv4地址,所以服务器的域名对应一个ipv4地址;
client是ipv6地址进行请求,需要返回一个ipv6地址,所以给服务器的ip + ipv6 前缀。
整体上:
NAT64 + DNS64 实现 ipv6 client 访问 ipv4 Server.
类似于:DNS中配置域名的4A 记录为 ipv6 的vip + DPVS中配置 NAT64(IPV6 VIP下挂IPv4 服务)。
现在有一个ipv6 client需要访问ipv4 服务器,则:需要给这台服务器配置NAT64和DNS64,否则用户就访问不了了。流程如下所示:
1>运维部署一台NAT64服务器(自建,也可以是云服务商提供的服务器),配置好服务器的IPv4地址(以192.168.0.100为例)和IPv6前缀(一般是64:ff9b::/96 )
2>运维在DNS64服务器(DNS64服务器可能是自建,也可能是公共DNS64服务器,也可以是云服务商提供的服务器)把域名指向NAT64服务器的IPv4地址(以192.168.0.101为例)及前缀(必须和NAT64配置的前缀一致)
3>IPv6客户端需要和服务器通信,根据域名发起IPv6 DNS查询,由于服务器不支持IPv6,所以没有查询到。但是DNS64服务器发现了一个IPv4的地址,于是把这个IPv4加上前缀,得到一个IPv6地址,即64:ff9b::192.168.0.101,于是客户端往这个地址发请求。
4>NAT64收到IPv6数据包,会解析IP地址的前缀,发现和运维配置的前缀一致,于是把这个数据包转换为一个IPv4数据包,按NAT规则往配置好的服务器地址发送IPv4数据包
5>IPv4服务器收到IPv4数据包,返回IPv4数据包
6>NAT64收到服务器返回的数据包,按NAT规则转换为IPv6数据包,返回给IPv6客户端,完成了交互
注:
- DNS64返回域名对应的4A记录, 需保证流量可以路由到NAT64服务器。
nat64 rfc
参考:nat64 rfc6146
dns64 rfc
参考:dns64 rfc6147
nat46
NAT64原本设计的目的是让IPv6客户端访问IPv4,而不是IPv4访问IPv6。
实际中,ipv4 访问 ipv6 的需求比较少。
因为IPv4是旧标准,既然服务器支持IPv6,说明是从IPv4升级而来的,那保留IPv4功能即可。直接是NAT44,而不需要NAT46。
但事情也不是这么绝对,因此虽然很少有人提及,但还是有NAT46这种东西的,
见:NAT64 - NAT46
Dual stack: 双栈
既然IPv4和IPv6不兼容,那就没必要让它们兼容。可以同时开启IPv4和IPv6,这样各走各的路,互不干扰。那这就需要同时实现IPv4和IPv6协议栈,即双栈(Dual Stack)。
可以看到,网卡2有两个地址:inet 192.168.3.6和inet6 fe80::f2a1:25a2:d365:468c,说明支持双栈。
最简单的办法,同时
程序实现双栈
最简单的办法,同时开两个socket,一个IPv4,一个IPv6,问题是这样写代码有点复杂。
- 范例
- Linux下,同一个程序以Dual Stack模式监听时,netstat只显示IPv6的监听(上面telnet测试就只grep到一个记录),而部分程序(如sshd)则显示两个,如下所示,猜测可能是开了两个socket监听而不是用双栈实现。
- 用::1去监听时,只能通过::1来连接,用127.0.0.1是不行的。用::监听则可以用::1或者127.0.0.1连接
- 双栈虽然可以接受IPv4连接,但实际上是以IPv6模式来处理的,因此获得到的对端的IP地址为::ffff:192.0.2.1这种IPv4-mapped IPv6的格式,而不是原生的IPv4地址。
- ::ffff:127.0.0.1虽然是一个IPv6地址,但它不是::1,而是是等同于127.0.0.1。即监听::ffff:127.0.0.1时,只能从127.0.0.1连接,用::1是连不上的。
- ::ffff:c000:201和::ffff:192.0.2.1这两个地址是相同,把::ffff:c000:201用getaddrinfo解析,得到的就是::ffff:192.0.2.1,它们的转换算法:
查看一个域名是否支持ipv6的4A记录
想测试一个域名是否支持IPv6,有很多工具,比如nslookup -type=AAAA www.google.com 114.114.114.114;
也可以在线测试 :拨测:ipv6检测
客户端的连接处理
- 服务端角度
服务端如果需要对外部署的话,无论是自建服务器还是云服务器,在部署的时候都能够知道是否支持IPv6; - 客户端角度
客户端是不能确定服务端是否启动ipv6以及到达服务端的链路是否支持ipv6的。
公司可以发布一个支持IPv6的客户端,但即使查询IPv6的DNS成功,也无法保证客户端到服务器之间的所有设备都支持IPv6,DNS查询成功只是表示客户端到DNS服务器之间的IPv6链路是通的,与服务器不是同一条链路,直接用IPv6去连服务器可能会失败。
IETF推荐的做法是:优先查询IPv6地址,然后是IPv4地址,一个个尝试去连接。没看错,就是for循环一个个去试。
参考