背景
从今年六月起IOS平台应用程序上线app store需要其支持IPV6-only网络的访问。这无疑给IOS开发人员和应用程序服务器后台的支持维护工作设了一道巨大的关卡,之前就一直传来业内的小伙伴频频被拒的消息,虽然网上的各种解决方案层出不穷,直接原因总结起来就是APP客户端在美国的IPv6-Only网络环境下不能正确访问后台的app server。说起来仅仅是很小的一个访问测试,但是这个隐藏的系统内部的经络是十分错综复杂,要保障各个环节任何步骤不出问题更是难上加难。前日某银行应用程序服务器DNS解析失常,直接导致其后台服务器在internet上”失联”,某公司在DNS GSLB解析时不稳定,经排查存在timeout现象,导致app sever解析不正常…….app server处在如此不稳定的网络中,再加上国际间网络路由复杂,保障客户端正确请求app server 这一条件比app store在代码层面上的审核要求显得更加苛刻,这也成了一个主要的难题。
由于IPv6和IPv4的不兼容性,IPv6网络在我国的发展过程呈现的特点就是客户接入端响应很高,各大高校,政府纷纷试点部署,但是在内容上业务端的部署开展却是屡屡受挫,就连国内偌大的阿里云都不支持IPv6,为了响应现在IPv6的客户端去访问ipv4的服务器这一需求,且原先的NAT-PT在实际网络应用中面临各种缺陷,NAT64+DNS64的技术在这种情况下便应育而生,所以在app store审核才会添加此项。而DNS64+NAT64转换的环境也是官方给出的测试环境。
DNS64+NAT64
现实中我们用的DNS64和NAT64:
app store测试环境
在apple官网上给了一种测试环境是用MAC配置DNS64和NAT64环境,如下:
DNS64+NAT64技术原理
让我们来看一个完整的IPv6-Only客户端与IPv4-Only app server通信的过程。
- 基于DNS64域名解析:客户端向指定的本地DNS服务器发起example.apple.com的AAAA解析请求,本地DNS服务器(带有DNS64功能)收到此请求后会帮其递归,从根域开始查找,一直找到apple.com这个域的授权域名服务器(如在com域名服务器查询到的apple域权威域名服务器为ns.apple.com和其A或AAAA记录),并开始向其解析example.apple.com的主机记录。本地DNS服务器会先发一条AAAA记录的request请求,此时如果ns.apple.com在记录文件或数据库有example.apple.com且为AAAA记录,则直接回复给本地DNS服务器,本地DNS服务器直接将解析到的AAAA记录回复给客户端,根据这条AAAA记录客户端直接通过IPv6网络向app server后台发起连接请求,若ns.apple.com的记录文件或数据库中example.apple.com的解析记录为A记录,则会回复empty,代表没有IPv6记录,在本地DNS收到其回复后依据DNS64模块向ns.example.com发起一条A记录请求,ns.example.com返回解析文件或数据库中的A记录给DNS64服务器,之后DNS64会将这条A记录合并为一条AAAA记录返回给IPv6-Only的客户端。这样就保证了对客户端透明,即无论收到的递归解析回复的主机记录类型是A或是AAAA,返回客户端的都是IPv6-Only 客户端可以直接请求的AAAA记录。流程如图:
问题是DNS64如何对A记录进行合并成为AAAA记录呢?其中常用的一种方法为:DNS64将NAT64路由器的前128bits的IPV6前缀前96位提取出来再将解析到的32位A记录地址放入IPv6地址的后32位,即合成了一个IPv6的AAAA记录。如:解析到的A记录为8.8.8.8,NAT64的IPv6前缀为64ff:ff9b::/96,则DNS64返回客户端的AAAA记录为64ff:ff9b::8.8.8.8。(详见RFC6052)
- 基于NAT64转法:客户端在解析到主机记录后会发起连接数据包,数据包根据IPv6网络路由到NAT64的IPV6接口,当有状态的NAT64设备收到数据包,会使用一个未使用的端口与其源地址进行映射,如将源IP和源端口 2001:c68:101:1::111 ,150转换为其ipv4接口地址8.8.7.8,2000 ,再根据SIIT算法将IPv6的报头转换为IPv4的报头,将目的地址的前缀去掉,还原为app server的ipv4地址并保持端口不变,将之前的映射后的源地址和源端口填入新的报头中。重新封装完成之后,即可将就该后的数据包通过IPv4网络路由到app server。在app server回包的时候根据转换后的请求数据包的源IP路由到NAT64的IPv4网络接口,NAT64设备根据映射表对其进行还原。最后通过IPv6网络将IPV6数据包路由回客户端。
需要注意的是:在真实的使用环境中,客户端通过非DNS查询获取得到的IPv6记录,在NAT64上v6到v4的转换任然会进行,DNS64和NAT64是分离的,并且IPV6数据包和IPV4数据包转换除了地址需要转换之外,数据包的格式也需要进行转换,这个过程按照SIIT(RFC2765)无状态IP/ICMP翻译算法进行。
除此之外,和NAT一样,任何对IP报头进行加密的协议都不能与NAT64进行兼容,如AH或是ESP的传输模式的时候,不能进行端到端的IPSEC验证。
如何保障可用性
满足测试环境中IPv6-only客户端顺利访问IPv4-only的应用服务器,在应用可用性上应该至少保证满足两点
- 客户端通过DNS64正确解析到app server的AAAA记录地址
- 通过NAT64将客户端的请求数据包正确并快速路由到app server上
最近遇到的case
事件描述
某银行的应用程序审核持续被拒。经过测试我们发现在app store所属权威DNS server上没有其IPV6的AAAA记录。但是IPV4的A记录解析正常,在本地设定Local DNS为一台网上公开的DNS64的server,其IPV6地址为2001:778:0:ffff:64:0:de1c:9b19 (有能力的读者可自行设置测试,需要IPV6网络能到此DNS64 server)。经过nslookup调试并抓包发现回复其DNS 标准查询的response报文中的reply code为server failure,表示IPV6解析地址失常,具体原因见后面的分析。
情景模拟
一台阿里云服务器模拟应用程序服务器,一台citrix NetScaler做DNS解析,公司域名模拟客户在万网托管的域名。
dylan.phdata.cn.为后台app server FQDN,dylantestns.phdata.cn.为负载均衡设备的FQDN
原先客户域名在万网的设置:
在citrix上设置DNS解析:(A记录)
在客户端nslookup抓包:
set q=A后请求dylan.phdata.cn :
Set q=AAAA 后再请求dylan.phdata.cn:
如上dylan.phdata.cn的A记录解析正常,回复的reply code为no error,但是dylan.phdata.cn的AAAA记录解析失败,回复的reply code为server failure,表示查询失败。
故障原因
首先万网上设定dylan这个子域的NS为父域内的主机设置的方法是不合常理的(由于父域phdata.cn解析权已交由万网)按照DNS查询流程,稳定的子域的授权域名服务器应该保证由子域内的某台name server解析。且完整的子域授权应当保证父域内有子域的ns记录和对应的主机记录,子域内的权威域名服务器上应当配置完整的DNS相关配置。
回复reply code为server failure(等同于dig响应中的status:SERVFAIL),其代表的是LDNS无法和正在查询的权威name server进行通信,可能由于网络层路由不可达,还有可能就是name server不能回复请求报文,如权威域名服务器故障不可用或直接将LDNS的查询drop掉。当LDNS直接请求IPv6的AAAA记录,若被请求的name server不回复其request报文,则LDNS认为其无法与授权域名服务器进行通信,便不会再对主机的A记录再次进行请求。为了让LDNS的DNS64模块可以在查询IPv6 AAAA记录得知其为空后,发出IPv4的A记录请求,需要保证LDNS查询AAAA记录结果状态为no error。但是若LDNS在AAAA记录查询没有收到no error回复,则LDNS(DNS64模块)便不会继续查询A记录。
解决方案(GSLB+CNAME子域模式)
为了达到上述需求并规避server failed查询状态,我们可以设置CNAME子域的方式实现。设置CNAME的好处是权威域名服务器总会将这个CNAME记录返回给LDNS让其对CNAME的记录值进行重新解析,即LDNS在AAAA记录查询收到no error。
同时为了防止地理位置的阻碍,保障和加速client对app server的记录查询和业务访问。专业的智能DNS解析应用交付设备F5 GTM,citrix NetScaler等,其可以根据最精准的GSLB调度算法,(通过对DNS64的位置和跳数进行RTT测量,根据采集到的RTT值,GSLB Controller会选择RTT值最小的站点的VIP返回给LDNS)加速app client的DNS64解析和NAT64访问。
如我们利用NetScaler做GSLB并采用子域CNAME的方式:
- 万网配置:
以上的配置相当于构建了一个子域nslb,其子域中的主机:ns.nslb.phdata.cn即负载均衡设备负责子域名的解析,对于的A记录就是其对外接口地址。再将业务主机CNAME到子域下的某台主机名,当客户端的LDNS解析到CNAME记录时会以CNAME记录值去重新发起查询,只要在负载均衡上面完成稳定的子域配置和业务主机的CNAME后的记录即可。
如,在citrix上配置:
- 先后配置GSLB 解析的site和services,virtual server:
-
site配置:
-
services配置:
-
virtual server配置:
-
SOA记录:
-
NS记录:
用IPV6的客户端验证(nslookup并抓set query=AAAA的记录报文):
使用IPV6的客户端去访问阿里云上的IPV4的httpd服务器,访问正常。
注意,往往出现的错误reply code就是server failure(等同于dig响应中的status:SERVFAIL)。其代表的是LDNS无法和正在查询的权威name server进行通信,可能由于网络层路由不可达,还有可能就是name server不能回复请求报文,如权威域名服务器故障不可用,甚至不知道自己就是权威域名服务器。在这种情况下,可以使用dig +trace 选项来对域名解析进行调试,观察其输出信息,来帮助我们来排错。在此处如果缺少SOA和NS记录,负载均衡器就不知道自身就是授权的name server,便就不会回应自身没有的AAAA记录了。
正常的情况
由图可见,LDNS即前面给出的公开DNS64地址。由DNS64原理可验证,通过DNS64合并得出的IPV6地址的后32位即ipv4-only网络的后台app server地址,如3ad3.xxxx的十六进制进行十进制转换后即为58.211.x.x
当IPV6-only客户端去解析app server时,便可根据此AAAA记录路由到NAT的IPV6接口,再通过后32位的DIP路由到app server所在的内网入口,数据包的发送的过程便是如此,同理,回包时到达NAT64设备命中其转换会话表项即可。