目录

  • ​​背景​​
  • ​​ipv6 访问 ipv4​​
  • ​​NAT64​​
  • ​​nat64 rfc​​
  • ​​dns64 rfc​​
  • ​​nat46​​
  • ​​Dual stack: 双栈​​
  • ​​程序实现双栈​​
  • ​​查看一个域名是否支持ipv6的4A记录​​
  • ​​客户端的连接处理​​
  • ​​参考​​

背景

IPv6出来已经很多年,虽然距离普及还很远,但项目里要加上,IPv6最大的问题是包格式与IPv4不兼容。

0                   1                   2                   3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Version| IHL |Type of Service| Total Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Identification |Flags| Fragment Offset |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Time to Live | Protocol | Header Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Source Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Destination Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Options | Padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Version| Traffic Class | Flow Label |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Payload Length | Next Header | Hop Limit |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
+ +
| |
+ Source Address +
| |
+ +
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
+ +
| |
+ Destination Address +
| |
+ +
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

粗略一看,这个应该是兼容的啊。毕竟前4bit都是版本号,拿到数据包时,判断一下版本号,根据不同的版本号做不同的处理,即可做兼容,很多软件都是这么做的。
然而问题是,IP数据包涉及的不仅仅是软件,还有硬件,比如路由器。当一个数据包经过路由器时,它需要解析包头里的数据,得到目标地址,才知道数据包转发到哪里。如果这个包头格式不一样了,那这个数据包就无法正常转发。对于软件,可以重新发布一个版本来解决,但绝大部分的家用路由器,是不带更新功能的,那要让它支持Ipv6,只能扔掉买一个新的。在现实生活中,一个数据包的传输,可能会经过很多路由的,例如:

客户端 --------> 家庭路由 --------> 小区路由 --------> ISP主路由 --------> 服务器

当这个问题扩大到整个社会,就会有无数的家庭路由,无数的小区路由。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,否则用户就访问不了了。流程如下所示:

DNS64
^ |
| |
| v
IPv6客户端 --------> IPv6路由器 --------> NAT64(192.168.0.101) --------> IPv4服务器(192.168.0.100)

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实现ipv6 client 访问ipv4 Server_DNS


参考:​​nat64 rfc6146​

dns64 rfc

通过NAT64实现ipv6 client 访问ipv4 Server_客户端_02

参考:​​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)。

~$ ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: enp2s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether b4:b5:2f:91:fe:21 brd ff:ff:ff:ff:ff:ff
inet 192.168.3.6/24 brd 192.168.3.255 scope global dynamic noprefixroute enp2s0
valid_lft 73235sec preferred_lft 73235sec
inet6 fe80::f2a1:25a2:d365:468c/64 scope link noprefixroute
valid_lft forever preferred_lft forever

可以看到,网卡2有两个地址:inet 192.168.3.6和inet6 fe80::f2a1:25a2:d365:468c,说明支持双栈。
最简单的办法,同时

程序实现双栈

最简单的办法,同时开两个socket,一个IPv4,一个IPv6,问题是这样写代码有点复杂。

  • 范例
root@debian:/home# netstat -lp | grep master
tcp6 0 0 [::]:8182 [::]:* LISTEN 1458/./master
root@debian:/home# telnet 127.0.0.1 8182
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
^C^]
telnet> quit
Connection closed.
root@debian:/home# telnet -6 ::1 8182
Trying ::1...
Connected to ::1.
Escape character is '^]'.
^]
telnet> quit
  • Linux下,同一个程序以Dual Stack模式监听时,netstat只显示IPv6的监听(上面telnet测试就只grep到一个记录),而部分程序(如sshd)则显示两个,如下所示,猜测可能是开了两个socket监听而不是用双栈实现。
# linux
root@debian:/home# netstat -lp | grep sshd
tcp 0 0 0.0.0.0:ssh 0.0.0.0:* LISTEN 595/sshd
tcp6 0 0 [::]:ssh [::]:* LISTEN 595/sshd
  • 用::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检测​

通过NAT64实现ipv6 client 访问ipv4 Server_服务器_03

客户端的连接处理

  • 服务端角度
    服务端如果需要对外部署的话,无论是自建服务器还是云服务器,在部署的时候都能够知道是否支持IPv6;
  • 客户端角度
    客户端是不能确定服务端是否启动ipv6以及到达服务端的链路是否支持ipv6的。
    公司可以发布一个支持IPv6的客户端,但即使查询IPv6的DNS成功,也无法保证客户端到服务器之间的所有设备都支持IPv6,DNS查询成功只是表示客户端到DNS服务器之间的IPv6链路是通的,与服务器不是同一条链路,直接用IPv6去连服务器可能会失败。
    IETF推荐的做法是:优先查询IPv6地址,然后是IPv4地址,一个个尝试去连接。没看错,就是for循环一个个去试。

参考


https://www.h3c.com/cn/d_201908/1222492_30005_0.htm