从2016年6月1号开始,苹果强制要求上架AppStore的应用支持IPv6-only network。
本文分为两部分:通过代码检查是否兼容IPv6-only网络,以及如何搭建IPv6-only网络的测试环境。旨在帮助快速检查app是否支持IPv6-only Network。可以当做 Supporting IPv6 DNS64/NAT64 Networks 中 Ensuring IPv6 DNS64/NAT64 Compatibility 一节的速成版本。
最便捷的检查方式是:找一台Mac,共享Internet到IPv6 DNS64/NAT64网络,然后让待测试设备连接到此网络,并测试app功能是否正常。
需注意,OS X 10.11后才支持创建IPv6 DNS64/NAT64网络。如果待测试设备不是iOS或OS X或macOS设备(比如要测试Andr**d上的app是否兼容IPv6-only网络),请确保设备支持 RFC6106 。
用在OS X(macOS)上创建IPv6 DNS64/NAT64网络很简单,只需要:
打开System Preference,按住Option点击Sharing,松开Option:
勾选 Create NAT64 Network ,把来自其他网卡的Internet共享给Wifi:
将测试设备连接到此Wifi,并测试App功能是否正常。
尽量使用以下框架实现网络请求:
检查是否使用过IPv4特定的API,包括但不仅限于:
inet_addr() inet_aton() inet_lnaof() inet_makeaddr() inet_netof() inet_network() inet_ntoa() inet_ntoa_r() bindresvport() getipv4sourcefilter() setipv4sourcefilter()
如果代码中需要检查IPv4类型,则也应一并检查IPv6类型:
IPv4 | IPv6 |
---|---|
AF_INET | AF_INET6 |
PF_INET | PF_INET6 |
struct in_addr | struct in_addr6 |
struct sockaddr_in | struct sockaddr_in6 |
kDNSServiceProtocol_IPv4 | kDNSServiceProtocol_IPv6 |
如果app需要连接到没有域名的IPv4-only服务器,请使用 getaddrinfo 处理IPv4地址,好处是当app处于IPv6-only网络时, getaddrinfo 会生成一个对应的IPv6地址。
下面的代码展示了如何使用 getaddrinfo 正确处理IPv4地址。内存中有4字节存储了一个IPv4地址({192, 0, 2, 1}),代码将其转换称了string(”192.0.2.1”),然后使用 getaddrinfo 生成了对应的IPv6地址(存储了”64:ff9b::192.0.2.1”的sockaddr_in6结构体),然后尝试连接到此IPv6地址:
#include <sys/socket.h> #include <netdb.h> #include <arpa/inet.h> #include <err.h> uint8_t ipv4[4] = {192, 0, 2, 1}; struct addrinfo hints, *res, *res0; int error, s; const char *cause = NULL; char ipv4_str_buf[INET_ADDRSTRLEN] = { 0 }; const char *ipv4_str = inet_ntop(AF_INET, &ipv4, ipv4_str_buf, sizeof(ipv4_str_buf)); memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_DEFAULT; error = getaddrinfo(ipv4_str, "http", &hints, &res0); if (error) { errx(1, "%s", gai_strerror(error)); /*NOTREACHED*/ } s = -1; for (res = res0; res; res = res->ai_next) { s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (s < 0) { cause = "socket"; continue; } if (connect(s, res->ai_addr, res->ai_addrlen) < 0) { cause = "connect"; close(s); s = -1; continue; } break; /* okay we got one */ } if (s < 0) { err(1, "%s", cause); /*NOTREACHED*/ } freeaddrinfo(res0);
需注意, getaddrinfo 兼容自动转换至IPv6地址的特性是iOS 9.2和OS X 10.11.2以后才支持的,但是这段代码可以保证在老的操作系统上的兼容性。
Over