Apple yawned, and the iOS industry started a storm. Since Apple announced in early May that all developers must submit new versions of their apps by June 1 to support ipv6-only networks, there has been intense research on how to support IPv6, and which modules in their apps don’t currently support IPv6.
In order to better communicate, an IPV6 exchange group (group number: 805558511) is specially built, hoping to communicate with each other:
One, what is pure IPv6 support?
First, IPV6 is an expansion of the IPV4 address space. At present, when we use iOS devices to connect to Wifi, 4G, 3G and other networks, the addresses assigned to the devices are IPV4 addresses. However, with the gradual deployment of IPV6 DNS64 / NAT64 networks by carriers and enterprises, the addresses assigned to the devices will become IPV6 addresses. These networks are so-called ipv6-only networks, and can still access content provided by IPV4 addresses. When the client requests domain name resolution from the server, it queries the IPv6 address through the DNS64 server. If the IPv6 address cannot be queried, it queries the IPv4 address from the DNS server, syntheses an IPv6 address through the DNS64 server, and returns an IPv6 address to the client. As shown in the figure:
NAT64, DNS64, resolutionofipv4_2x.png
In Mac OS 10.11+ dual network card Mac machine (Ethernet + wireless network card), we can simulate the construction of such a local IPv6 DNS64 / NAT64 network environment to test whether the application supports ipv6-only network, the general principle is as follows:
local_ipv6_dns64_nat64_network_2x.png
References:
Developer.apple.com/library/mac…
Second, how does Apple review support for pure IPv6?
Support ipv6-only network, which means that the application can still run in IPV6 DNS64 / NAT64 network environment. However, considering that the actual network environment is still IPV4 network, the application needs to be able to ensure the availability of both IPV4 and IPV6 environment. At this point, Apple does not scan IPV4 proprietary apis to deny approval, since both IPV4 and IPV6 API calls exist in the code (although to reduce the risk of rejection, it is recommended that IPV4 proprietary apis be replaced with IPV6 compatible apis).
The second point: In iOS9.2 +, the getaddrInfo method is supported to synthesize IPV4 addresses into IPV6 addresses. (In iOS9.2 and OS X 10.11.2, getaddrInfo added the ability to synthesize IPV6 addresses.) In iOS8, when you switch from IPV4 to IPV6, or from IPV6 to IPV4, you can’t monitor the changes in network status. Some developers have asked Apple’s review department about these errors and have been told that they just need to ensure IPV6 compatibility on Apple’s latest systems.
Finally, the third point:. As long as the main flow of the application supports IPV6, it can pass The review of Apple. Considering that it will take some time for us to deploy the IPV6 network, the use of our users will not be affected in a short period of time. However, with the deployment of 4G network IPV6, this part of the module still needs to be gradually arranged for human support.
NSURLConenction or NSURLSession (generally, the server needs to allow, and the client needs to disguise the host in the header). After testing, under the IPV6 network environment, directly using IPV4 address in iOS9 or higher system can still be accessed normally; Cannot be accessed in iOS8.4 or later. Here’s apple’s explanation and advice:
Note: In iOS 9 and OS X 10.11 and later, NSURLSession and CFNetwork automatically synthesize IPv6 addresses in IPv4 text locally on devices running on DNS64 / NAT64 networks. However, you should still try to get rid of the IP address literal code.
Third, how does the application support pure IPv6?
There are several criteria for supporting pure IPv6 :(I will not explain it here, please refer to the reference link below)
1.UseHigh-LevelNetworkingFrameworks; 2. Don ‘tUseIPAddressLiterals; 3.Check Source CodeforIPv6 DNS64/NAT64 Incompatibilities; 4.UseSystemAPIstoSynthesizeIPv6Addresses;
3.1 Does NSURLConnection support IPV6?
The official line left us wondering:
* Using advanced networking apis such as NSURLSession and CFNetwork frameworks where you connect by name, you don’t need to change anything about your application using IPv6 addresses *
NSURLSession and CFNetwork apis do not need to be changed, but NSURLConnection is not mentioned. From the above references, we can see that NSURLSession and NSURLConnection belong to the URL loading system of Cocoa, so we can guess that NSURLConnection supports IPV6 in ios9.
AFNetworking is usually used to send API network requests. Due to historical reasons, the application code basically references AFHTTPRequestOperation class in depth. Therefore, currently all API network requests need to be sent out through NSURLConnection. Therefore, it is necessary to confirm whether the NSURLConnection supports IPV6. After testing, NSURLConnection supports IPV6 on the latest iOS9.
3.2 Since which version of iOS does Cocoa’s URL loading system support IPV6?
Currently, the lowest version of our app still needs to support iOS7. Although apple Only requires the latest version to support ipv6-only, we still need to find out whether the API of the url-loading system supports IPV6 on the earlier version out of a responsible attitude towards our users.
(To solve me, do some experiments) to be continued
3.3 Reachable Whether to support IPV6?
We can see that the application uses a lot of reachability for network state determination, but uses a dedicated IPV4 API inside.
In the Pods: Reachability AF_INETFiles: Reachability mstructsockaddr_inFiles: Reachability. J h, Reachability. M
How should reachability support IPV6?
(1) The latest version of Github’s open source library Reachability is 3.2. Apple has also released an official example of IPV6 Reachability. We have compared the source code and found no difference with Github’s Reachability.
(2) We usually through a 0.0.0.0 (ZeroAddress) to enable network status monitoring, after our test, iN iOS9 above the system IPV4 and IPV6 network environment can be used normally; However, when switching between IPV4 and IPV6 on iOS8, the network status change cannot be monitored, probably because apple does not support IPV6 in iOS8. (But this still satisfies Apple’s requirement to support IPV6 networks on the latest versions of the system).
(3) while everyone is asking Reachability to add support for IPV6, apple has made a special treatment of Zero addresses in iOS9.
ReachabilityForInternetConnection: it monitors 0.0.0.0 address,
The reachability is treated as a special token to make it practical
Monitors the general routing status of the device, including IPv4 and IPv6.
- (instancetype)reachabilityForInternetConnection {structsockaddr_in zeroAddress; bzero(&zeroAddress,sizeof(zeroAddress)); zeroAddress.sin_len =sizeof(zeroAddress); zeroAddress.sin_family = AF_INET; return[selfreachabilityWithAddress: (conststructsockaddr *) &zeroAddress]; }
In summary, keda can support IPV6 and IPV4 on iOS9 without any modifications, but there are bugs below iOS9, but apple audit does not care.
How does the underlying socket API support both IPV4 and IPV6?
This is an important area for IPV6 support because of the use of network diagnostics components in the application and the heavy use of low-level socket apis. If your application uses long connections, it must use the underlying socket API, which also needs to support IPV6. For details on how sockets support both IPV4 and IPV6, see CocoaAsyncSocket, Google’s open source library.
Let me describe how both IPV4 and IPV6 are supported for our open source network diagnostics component.
Open source address: https:// github.com/Lede-Inc/LDNetDiagnoService_IOS.git
The main functions of this network diagnostics component are as follows:
Local network environment monitoring (local IP + local gateway + local DNS + domain name resolution);
Domain name connectivity is monitored through TCP Connect.
The connection time of the target host is detected through Ping.
The ICMP time of each router node between the device and the target host is monitored by TRACEROUTE.
4.1 IP Address conversion from binary to symbol
Previously we used inet_ntoa () to convert binary to symbolic, and this API can only convert IPV4 addresses. Inet_ntop () is compatible with converting IPV4 and IPV6 addresses. Write a public in6_addr conversion method as follows:
//for IPV6+(NSString*)formatIPV6Address:(structin6_addr)ipv6Addr{NSStringaddress =nil; chardstStr[INET6_ADDRSTRLEN]; charsrcStr[INET6_ADDRSTRLEN]; memcpy(srcStr, &ipv6Addr,sizeof(structin6_addr)); if(inet_ntop(AF_INET6, srcStr, dstStr, INET6_ADDRSTRLEN) ! =NULL){address = [NSStringstringWithUTF8String:dstStr]; }returnaddress; }//for IPV4+(NSString)formatIPV4Address:(structin_addr)ipv4Addr{NSString*address =nil; chardstStr[INET_ADDRSTRLEN]; charsrcStr[INET_ADDRSTRLEN]; memcpy(srcStr, &ipv4Addr,sizeof(structin_addr)); if(inet_ntop(AF_INET, srcStr, dstStr, INET_ADDRSTRLEN) ! =NULL){address = [NSStringstringWithUTF8String:dstStr]; }returnaddress; }
4.2 Obtaining the local IP Address Supports IPV6
It is equivalent to the ifconfig command we input in the terminal to obtain the string, and then parse the ifconfig result string to obtain the IP address of EN0 (WiFi version) and PDP_ip0 (mobile network).
Note:
(1) An IPV6 unicast address starting with FE80 will appear on both the simulator and the real machine, which affects our judgment. Therefore, special treatment is performed here (when the IP address that is not a unicast address is encountered for the first time, it is the local IP address).
(2) In the IPV6 environment, when the real machine tests, the first occurrence is an IPV4 address, so the first encounter unicast address under IPV4 condition does not exit.
- (NSString *)deviceIPAdress{while(temp_addr ! =NULL) {NSLog(@”ifa_name===%@”,[NSString stringWithUTF8String:temp_addr->ifa_name]); // Check if interface is en0 which is the wifi connection on the iPhoneif([[NSString stringWithUTF8String:temp_addr->ifa_name] isEqualToString:@”en0″] || [[NSString StringWithUTF8String: temp_addr – > ifa_name] isEqualToString: @ “pdp_ip0″]) {/ / if the IPV4 addresses, If (temp_addr->ifa_addr->sa_family == AF_INET){// Get NSString from C Stringaddress = [selfformatIPV4Address:(struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr]; } elseif(temp_addr->ifa_addr->sa_family == AF_INET6){address = [selfformatIPV6Address:(struct sockaddr_in6 *)temp_addr->ifa_addr)->sin6_addr]; if(address && ! [address isEqualToString:@””] && ! [address.uppercaseString hasPrefix:@”FE80″])break; }}temp_addr = temp_addr->ifa_next; }}}
4.3 Obtaining the Device Gateway Address The device supports IPV6
AF_INET-> AF_INET6, sockaddr -> sockaddr_in6, also need to pay attention to the following changes, is the address of the copy of the number of bytes. – Removed ROUNDUP processing (always missing 4 bytes, resulting in a wrong offset), refer to the source code library.
/* net.route.0.inet.flags.gateway */intmib[] = {CTL_NET, PF_ROUTE,0, AF_INET6, NET_RT_FLAGS, RTF_GATEWAY}; If (sysctl (mib, sizeof (mib)/sizeof (int), buf, & l, 0, 0) < 0) {address = @ “192.168.0.1”; }… //for IPV4for(i =0; i < RTAX_MAX; i++) {if(rt->rtm_addrs & (1<< i)) {sa_tab[i] = sa; sa = (structsockaddr )((char)sa + ROUNDUP(sa->sa_len)); }else{sa_tab[i] =NULL; }}//for IPV6for(i =0; i < RTAX_MAX; i++) {if(rt->rtm_addrs & (1<< i)) {sa_tab[i] = sa; sa = (structsockaddr_in6 )((char)sa + sa->sin6_len); }else{sa_tab[i] =NULL; }}
4.4 Obtaining the DNS Address of the Device Supports IPV6
In IPV4, it can be obtained only through res_ninit initialization, but in IPV6, it can be obtained through the res_getServers () interface.
+(NSArray*)outPutDNSServers{res_state res = malloc(sizeof(struct__res_state)); intresult = res_ninit(res); NSMutableArray*servers = [[NSMutableArrayalloc] init]; if(result ==0) {unionres_9_sockaddr_union addr_union = malloc(res->nscount sizeof(unionres_9_sockaddr_union)); res_getservers(res, addr_union, res->nscount); for(inti =0; i < res->nscount; i++) {if(addr_union[i].sin.sin_family == AF_INET) {charip[INET_ADDRSTRLEN]; inet_ntop(AF_INET, &(addr_union[i].sin.sin_addr), ip, INET_ADDRSTRLEN); NSStringdnsIP = [NSStringstringWithUTF8String:ip]; [servers addObject:dnsIP]; NSLog(@”IPv4 DNS IP: %@”, dnsIP); }elseif(addr_union[i].sin6.sin6_family == AF_INET6) {charip[INET6_ADDRSTRLEN]; inet_ntop(AF_INET6, &(addr_union[i].sin6.sin6_addr), ip, INET6_ADDRSTRLEN); NSStringdnsIP = [NSStringstringWithUTF8String:ip]; [servers addObject:dnsIP]; NSLog(@”IPv6 DNS IP: %@”, dnsIP); }else{NSLog(@”Undefined family.”); }}}res_nclose(res); free(res); return[NSArrayarrayWithArray:servers]; }
4.4 Obtaining a DOMAIN Name DNS Address Supports IPV6
On IPV4, we get it from gethostName, and on IPV6, we get it from gethostByname2.
//ipv4phot = gethostbyname(hostN); //ipv6phot = gethostbyname2(hostN, AF_INET6);
4.5 Ping Schemes support IPV6
Apple’s official address for IPV6 ping is HTTPS:
//developer.apple.com/library/mac/samplecode/SimplePing/Introduction/Intro.html
Just a note of caution:
(1) The returned packet removes the IPHeader part, and the HEADER part of IPV6 does not return the TTL (time to live) field;
(2) IPV6 ICMP packets are not checkSum processed.
4.6 traceRoute Supports IPV6
In fact, a socket is created to simulate the sending of ICMP packets to calculate the time.
There are two key points to note:
(1) In IPV6, the IP_TTL field is removed and the hop number IPV6_UNICAST_HOPS is used to represent it;
(2) Sendto is compatible with both IPV4 and IPV6, but requires the last parameter to specify the size of the destination IP address; The previous parameter only specifies the starting address of the IP address. Do not use a uniform sizeof (struct sockaddr) because both sockaddr_in and sockaddr are 16 bytes, and both can be used, but sockaddr_in6 has a data structure of 28 bytes. Sendto will always return -1 if not explicitly specified. ErroNo reports an error with 22 invalid parameters.
The key code is as follows :(refer to open source component for complete code)
// Build a generic IP address structure: stuck sockaddrNSStringipAddr0 = [serverDNSs objectAtIndex:0]; // set server host socket address NSDataaddrData =nil; BOOLisIPV6 =NO; if([ipAddr0 rangeOfString:@”:”].location ==NSNotFound) {isIPV6 =NO; structsockaddr_in nativeAddr4; Memset (& nativeAddr4, 0, sizeof (nativeAddr4)); nativeAddr4.sin_len =sizeof(nativeAddr4); nativeAddr4.sin_family = AF_INET; nativeAddr4.sin_port = htons(udpPort); inet_pton(AF_INET, ipAddr0.UTF8String, &nativeAddr4.sin_addr.s_addr); addrData = [NSDatadataWithBytes:&nativeAddr4 length:sizeof(nativeAddr4)]; }else{isIPV6 =YES; structsockaddr_in6 nativeAddr6; Memset (& nativeAddr6, 0, sizeof (nativeAddr6)); nativeAddr6.sin6_len =sizeof(nativeAddr6); nativeAddr6.sin6_family = AF_INET6; nativeAddr6.sin6_port = htons(udpPort); inet_pton(AF_INET6, ipAddr0.UTF8String, &nativeAddr6.sin6_addr); addrData = [NSDatadataWithBytes:&nativeAddr6 length:sizeof(nativeAddr6)]; }structsockaddr *destination; destination = (structsockaddr *)[addrData bytes]; Socketif ((recv_sock = socket(destination->sa_family, SOCK_DGRAM, isIPV6? IPPROTO_ICMPV6:IPPROTO_ICMP)) <0)if((send_sock = socket(destination->sa_family, SOCK_DGRAM,0)) <0)// Set sender socket ttlif((isIPV6? setsockopt(send_sock,IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl,sizeof(ttl)):setsockopt(send_sock, IPPROTO_IP, IP_TTL, &TTL,sizeof(TTL))) <0) ssize_t sentLen = sendto(send_sock, cmsg,sizeof(cmsg),0,(structsockaddr *)destination,isIPV6? sizeof(structsockaddr_in6):sizeof(structsockaddr_in));
In this paper, for the third party transfer, the original link: www.jianshu.com/p/a6bab07c4…