通过NAT64实现ipv6 client 访问ipv4 Server

背景

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 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)。

~$ 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检测
在这里插入图片描述

客户端的连接处理

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

参考

https://www.cnblogs.com/coding-my-life/p/13977644.html
https://www.h3c.com/cn/d_201908/1222492_30005_0.htm
  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
IPv4是当前使用最广泛的互联网协议版本,但是由于IPv4地址资源有限,不足以满足日益增长的互联网用户需求,因此IPv6作为下一代互联网协议被广泛推广。IPv6IPv4不兼容,所以在将IPv6网络与IPv4网络连接时,需要通过端口映射来实现IPv6IPv4的端口映射主要有两种方式,一种是通过NAT64实现,另一种是通过代理服务器实现NAT64是一种网络地址转换技术,将IPv6网络的数据包转换为IPv4网络的数据包。在这种情况下,IPv6地址被映射到IPv4地址,IPv6端口则被映射到IPv4端口。当从IPv6网络发送数据包到IPv4网络时,NAT64将根据预设的映射规则进行数据包的转换与转发,确保数据包能够顺利到达IPv4网络。 另一种方式是通过代理服务器实现IPv6IPv4的端口映射。代理服务器作为一个中转站,接收来自IPv6网络的数据包,并将其转发到IPv4网络。在这种情况下,IPv6地址和端口信息被代理服务器IPv4地址和端口来代替,并通过代理服务器IPv4网络进行数据交互。 不论是通过NAT64还是代理服务器IPv6IPv4的端口映射都是为了实现IPv6网络与IPv4网络的互通。通过端口映射,IPv6用户可以访问IPv4资源,同时IPv4用户也可以访问IPv6资源,实现互联网的无缝连接。,从而更好地满足了互联网用户的需求。随着IPv6的推广和普及,IPv6IPv4的端口映射技术将会越来越重要和广泛应用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值