阅读949 返回首页    go 京东网上商城


IPv6兼容解决方案

一 背景

WWDC2015苹果宣布在iOS9支持纯IPv6的网络服务,并且要求2016年提交到AppStore的应用必须兼容纯IPv6的网络,要求适配的系统版本是iOS9以上(包括iOS9),否则会有过审被拒的可能。

d4f02e8375605ddb18934d7e704eae74a8007140

到目前为止多个阿里云客户都已提前咨询阿里云是否支持IPv6,多个阿里云客户的App送审后审核不通过。在什么场景下会有问题?是否需要阿里云公网地址及相关服务立即支持IPV6?有什么过渡方式?这就是本文档需要回答的问题。

IPv6地址示例:2001:0db8:85a3:08d3:1319:8a2e:0370:7344 

 

现在我们大部分服务器都是使用IPv4接入互联网的,我们要如何做兼容呢?也就是说如何做到IPv6和IPv4的兼容和相互访问?
要想使应用完全支持IPv6的环境,从协议到硬件,要做比较彻底的调整。不但客户端要做IPv6的改造,服务器也要适配IPv6,主要有以下四种对应关系,必须做好以下每一种:


(a) socket api支持RFC 4038—Application Aspects of IPv6 Transition

    v4 socket接口只能支持IPv4 stack

    v6 socket能支持IPv4 stack和IPv6 stack

(b) 服务器IP

    返回v4 IP

    返回v6 IP

    IPv4-only

    IPv6-only

    IPv4-IPv6 Dual stack

    464XLAT用于程序只有v4地址(使用v4 socket),但是本地网络是IPv6网络,程序需要访问v4资源,类似NAT64,不过区别在于服务器是运营商提供,手机上需要安装CLAT服务:RFC6877。


b4452275e7775903fccf38c3dcdfcdb5fb7be23a

这样我们在IPv6的环境下也是可以访问IPv4的后台资源的,我们的后台也就暂时不需要做什么变动。

::ffff:0:0/96 — This prefix is designated as an IPv4-mapped IPv6 address. With a few exceptions, this address type allows the transparent use of theTransport Layer protocols over IPv4 through the IPv6 networking application programming interface. Server applications only need to open a single listening socket to handle connections from clients using IPv6 or IPv4 protocols. IPv6 clients will be handled natively by default, and IPv4 clients appear as IPv6 clients at their IPv4-mapped IPv6 address. Transmission is handled similarly; established sockets may be used to transmit IPv4 or IPv6 datagram, based on the binding to an IPv6 address, or an IPv4-mapped address. (See also Transition mechanisms.)

从上文可以看到如果服务器地址为128.0.0.128,我们转换成IPv4-mapped IPv6 address::ffff:128.0.0.128或者纯16进制::ffff:ff00:00ff,然后赋值给sockaddr_in6.sin6_addr=”::ffff:128.0.0.128”;。这个socket虽然用了IPv6的sockaddr_in6,但实际上走的是IPv4 stack。

IPv4-mapped IPv6 address是让用户能够使用一致的socket api来访问IPv4和IPv6网络。

这里我们先看看Wikipedia对NAT64/DNS64的描述:

NAT64 is a mechanism to allow IPv6 hosts to communicate with IPv4 servers. The NAT64 server is the endpoint for at least one IPv4 address and an IPv6 network segment of 32-bits, e.g., 64:ff9b::/96 (RFC 6052RFC 6146). The IPv6 client embeds the IPv4 address with which it wishes to communicate using these bits, and sends its packets to the resulting address. The NAT64 server then creates a NAT-mapping between the IPv6 and the IPv4 address, allowing them to communicate.

DNS64 describes a DNS server that when asked for a domain's AAAA records, but only finds A records, synthesizes the AAAA records from the A records. The first part of the synthesized IPv6 address points to an IPv6/IPv4 translator and the second part embeds the IPv4 address from the A record. The translator in question is usually a NAT64 server. The standard-track specification of DNS64 is in RFC 6147.[10]

There are two noticeable issues with this transition mechanism:

  • It only works for cases where DNS is used to find the remote host address, if IPv4 literals are used the DNS64 server will never be involved.
  • Because the DNS64 server needs to return records not specified by the domain owner, DNSSEC validation against the root will fail in cases where the DNS server doing the translation is not the domain owner's server.

NAT64是一种有状态的网络地址与协议转换技术,一般只支持通过IPv6网络侧用户发起连接访问IPv4侧网络资源。但NAT64也支持通过手工配置静态映射关系,实现IPv4网络主动发起连接访问IPv6网络。NAT64可实现TCP、UDP、ICMP协议下的IPv6与IPv4网络地址和协议转换。

    a 客户端进行getaddrinfo的域名解析

    b DNS返回结果,如果返回的IP里面只有v4地址,并且当前网络是IPv6-only网路,DNS64服务器会把v4地址加上64:ff9b::/96的前缀,例如 64:ff9b::14.17.32.211。如果当前网络是IPv4-only或IPv4-IPv6,DNS64不会做任何事情。

    c 客户端拿到IPv6地址进行connect。

    d 路由器发现地址的前缀为64:ff9b::/96,知道这个是NAT64的映射,是需要访问14.17.32.211。这个时候需要进行NAT64映射,因为到外网需要转换成IPv4 stack。

    e 当数据返回的时候,按照NAT映射,IPv4回包重新加上前缀64:ff9b::/96,然后返回给客户端。

ad894d6d69c92fb7a11af2c6f470fec231ed3e18

af9ea6363c2b04c50d1b2fdbbc77798bc06c3044

//NAT64 address sample

//address init

const char* ipv6_str = “64:ff9b::14.17.32.211”;

in6_addr ipv6_addr = {0};

int v6_r = inet_pton(AF_INET6, ipv6_str, &ipv6_addr);

sockaddr_in6 v6_addr = {0};

v6_addr.sin6_family = AF_INET6;

v6_addr.sin6_port = htons(80);

v6_addr.sin6_addr = ipv6_addr;

 

//socket connect

int v6_sock = socket(AF_INET6,SOCK_STREAM,IPPROTO_TCP);

std::string v6_error;

if (0 != connect(v6_sock, (sockaddr*)&v6_addr, 28))

{

      v6_error = strerror(errno);

}

 

//get local ip

sockaddr_in6 v6_local_addr = {0};

socklen_t v6_local_addr_len = 28;

char v6_str_local_addr[64] = {0};

getpeername(v6_sock, (sockaddr*)&v6_local_addr, &v6_local_addr_len);

inet_ntop(v6_local_addr.sin_family, &v6_local_addr.sin6_addr, v6_str_local_addr, 64);

close(v6_sock);


  1. IPv6主机发起www.abc.com的AAAA域名解析到DNS64(主机配置的DNS地址是DNS64);
  2. DNS64触发AAAA到DNS AAAA中查询;
  3. DNS AAAA返回NULL的信息到DNS64;
  4. DNS64然后触发A的申请到DNS A中查询;
  5. DNS A返回www.abc.com的A记录(1.1.1.1);
  6. DNS64合成IPv6地址(64:ff9b:1.1.1.1),返回AAAA response给IPv6主机;
  7. IPv6主机发起目的地址为64:ff9b:1.1.1.1的IPv6数据包,由于NAT64在IPv6域内通告配置的IPv6Prefix,因此这个数据包转发到NAT64设备上;
  8. NAT64执行地址转换和协议转换,目的地址转换为192.0.2.1,源地址根据地址状态转换(64:ff9b:1.1.1.1,1500)>(1.1.1.1,2000)在IPv4域内路由到IPv4 Server;
  9. 数据包返回,目的地址和端口为1.1.1.1,2000;
  10. NAT64根据已有记录进行转换,目的地址转换为2001:db8::1,源地址为加了IPv6前缀的IPv4Server地址64:ff9b:1.1.1.1,发送到IPv6主机。

注:AAAA记录(AAAA Record)是用来将域名解析到IPv6地址的DNS记录,用户可以将一个域名解析到IPv6地址上,也可以将子域名解析到IPv6地址上。

这里一般connect的时候会返回错误码network is unreachable,因为根本没有v6的协议栈,就像没有硬件设备一样,但是不排除会有系统会返回no route to host。当然,如果服务器的地址是Teredo tunneling 2001::/32,可以客户端直接做隧道。如果是6to4 2002::/16,并且客户端有RAW socket权限加上非NAT网络,这种情况下可以客户端自己做6to4的路由。 

88ad76232f60c60a77dd2c35f81a95acba7e8e3c

iOS设备需要连接Mac机创建的NAT64/DNS64的Wi-Fi,就是传说中的IPv6的网络环境,再通过有线网络、路由器,访问到IPv4的资源,就可以做到IPv6->IPv4的连接。

需要一台用非Wi-Fi方式上网的Mac电脑(10.11以上的系统)、iOS9以上(包含iOS9)设备和互联网有线接口。目的是用Mac作一个热点,然后用iPhone连接这个Wi-Fi。我们产生的是一个本地的IPv6 DNS64/NAT64网络,这项功能是OS X 10.11新加的。


a 在“系统偏好设置”界面选中“共享”的同时,要按住“option”键。

9ce5c7876315c388abc3b04b9ad35b247d385305

b 不要松开“option”键,选择“Internet Sharing”;

8aecef425ac8f126b82224544cdfe850c1a4d530

c 松开“option”键,选择“Create NAT64 Network”选框;

527583bfda2cf8959e605309f102559721f1d22c

d 选择提供网络连接的网络接口设备;

4f83a16da20632875a08e38519efe7cd20116b67

e 选择“Wi-Fi”选框;

0841a7619d479d673aa2d312f18518b4a72d163c

f 点击“Wi-Fi Options”并配置网络名和安全选项;

63798caf08e2fc7051799ed1781efd938d023c3f

6881ae949dce2a49668791d7f15adee5219ddac4

选择“Internet Sharing”选框以生效本地网络;

21eff6b2f0f553c25562c8b874f1ae5edc99d0ea

点击“Start”开始网络共享;

08fdb886793aa539843e19015b499c8e017d8614

现在可以用iPhone连接上这个刚创建好的热点开始测试了,注意此时要把iPhone设成飞行模式,以保证只用Wi-Fi上网。

测试重点:

 IPv4和IPv6网络环境判断是否正确 

UDP和TCP的切换是否正确。

四  对开发同学的建议

c9dc94640a8d94283c18c9528846ae0d00cb5ea7


SCNetworkReachabilityCreateWithName 

9e226066a3d575d64abd170a1392e9054fcac89f

代码中以上对应类型都要处理。

45321412af9770e404d69305da8fb7eee01ff51b

这些API都是只针对IPv4做处理的,换用兼容IPv4及IPv6的API。
判断当前客户端是处于IPv4-only、IPv6-only还是IPv4和IPv6并存的环境,然后分别使用不同的网络API。

客户端做不同的处理的前提是需要知道客户端可用的IP协议栈。可用的IP stack类型分别是IPv4-only、IPv6-only、IPv4-IPv6 Dual stack。
我们先定义客户端可用的IP协议栈的含义:获取客户端当前能使用的IP协议栈。例如iOS在NAT64 Wi-Fi连接上的情况下,Mobile的网虽然存在IPv4的协议,但是系统是不允许使用的。iOS只能使用Wi-Fi的协议栈,在NAT64 Wi-Fi的情况下就是IPv6-only网络了。如果遇到IPv6-only网络,需要把它当作NAT64来处理,在v4 IP前添加前缀64:ff9b::/64。但是NAT64和IPv6-only不是等价的。IPv6-only网络可能支持NAT64,能访问v4的互联网资源,但是IPv6-only能访问v6的互联网资源,不支持NAT64。这里假设IPv6-only的网络都是支持NAT64的,对v4 IP进行64:ff9b::/96的处理。

 


//gateway

in6_addr addr6_gateway = {0};

if (0 != getdefaultgateway6(&addr6_gateway))

       return EIPv4;

if (IN6_IS_ADDR_UNSPECIFIED(&addr6_gateway))

       return EIPv4;

in_addr addr_gateway = {0};

if (0 != getdefaultgateway(&addr_gateway))

return EIPv6;

if (INADDR_NONE == addr_gateway.s_addr || INADDR_ANY == addr_gateway.s_addr)

       return EIPv6;

//getaddrinfo

struct addrinfo hints, *res, *res0;

memset(*hints, 0, sizeof(hints));

hints.ai_family = PF_INET6;

 

(1) wikipedia Transition from IPv4 :leftwards_arrow_with_hook:

(2) wikipedia NAT64 :leftwards_arrow_with_hook:

(3) wikipedia DNS64 :leftwards_arrow_with_hook:

(4) wikipedia IPv6 address :leftwards_arrow_with_hook:

(5)https://developer.apple.com/library/prerelease/content/documentation/NetworkingInternetWeb/Conceptual/NetworkingOverview/UnderstandingandPreparingfortheIPv6Transition/UnderstandingandPreparingfortheIPv6Transition.html


最后更新:2017-11-11 23:35:10

  上一篇:go  阿里云长期最新幸运券使用规则
  下一篇:go  RabbitMQ安装