iOS app support IPV6, that's the thing.

Source: Internet
Author: User
Tags htons


This article reprinted to http://www.jianshu.com/p/a6bab07c4062


It was an Apple yawn and it was a storm in the iOS industry. Since early May Apple has expressly stated that all developers submitting a new version after June 1 will need to support Ipv6-only's network, and everyone is starting to look at how to support IPV6 and which modules in the application do not currently support IPV6.


First, ipv6-only support is what?


The first IPV6, is the expansion of the IPV4 address space. At present, when we use the iOS device to connect to the WiFi, 4G, 3G and other networks, the device is assigned to the address is IPV4 address, but as operators and enterprises gradually deployed IPV6 Dns64/nat64 Network, the device assigned address will become IPV6 address, These networks are known as ipv6-only networks and can still be used to get the content provided by the IPV4 address. The client requests the domain name resolution to the server, first through the DNS64 server to query the address of the IPV6, if the query is not, then to the DNS server to query the IPV4 address, the DNS64 server to synthesize a IPV6 address, and eventually return a IPV6 address to the client. :



Nat64-dns64-resolutionofipv4_2x.png


In Mac OS 10.11+ dual-nic Mac Machine (Ethernet port + Wireless card), we can test whether the application supports Ipv6-only network by simulating the network environment of such a local IPv6 dns64/nat64, the approximate principle is as follows:



Local_ipv6_dns64_nat64_network_2x.png
    • Resources:
      • https://developer.apple.com/library/mac/documentation/NetworkingInternetWeb/Conceptual/NetworkingOverview/ understandingandpreparingfortheipv6transition/understandingandpreparingfortheipv6transition.html#//apple_ref/ Doc/uid/tp40010220-ch213-sw1
Second, how does Apple audit support ipv6-only?


First 1th: This is said to support Ipv6-only network, in fact, let the application in the IPV6 Dns64/nat64 network environment can still run normally. But considering that our actual network environment is still a IPV4 network, the application needs to be able to ensure availability in both IPV4 and IPV6 environments. From this point, Apple does not scan IPV4 's proprietary API to deny auditing because the IPV4 API and IPV6 API calls both exist in the code.



Second 2nd: Apple's official statement iOS9 began to support the transition to IPV6, where ios9.2+ supported IPV4 address synthesis IPV6 addresses. The reachability library provided in the IOS8 system, when switching from IPV4 to IPV6 network, or from IPV6 network to IPV4, is unable to monitor the network status changes. Some developers also ask Apple's audit department for these bugs, and the answer is that they only need to ensure IPV6 compatibility on Apple's newest system .



finally 3rd: as long as the application of mainstream support IPV6, through the Apple audit can. For modules that do not support IPV6, it takes a while for our IPV6 network to be deployed and will not affect the use of our users for a short period of time. But with the deployment of the 4G network IPV6, this part of the module still needs to be gradually arranged to support the manpower.


Third, how can application support Ipv6-only?


For how to support the Ipv6-only, the official gave the following criteria: (This is not explained here, you can see the reference link above)


 
1. Use High-Level Networking Frameworks;
2. Don’t Use IP Address Literals;
3. Check Source Code for IPv6 DNS64/NAT64 Incompatibilities;
4. Use System APIs to Synthesize IPv6 Addresses;
Does 3.1 nsurlconnection support IPV6?


The official remark made us wonder:
Using high-level networking APIs such as Nsurlsession and the Cfnetwork frameworks and you connect by name, you should not Need to change anything for your apps to work with IPV6 addresses



Only the nsurlsession and Cfnetwork APIs do not need to be changed, but there is no mention of nsurlconnection. From the references above, we see that nsurlsession, nsurlconnection, and Cocoa's URL loading system, can guess Nsurlconnection is iOS9 on IPV6.



Application inside the API network request, everyone will generally choose afnetworking to send the request, because of historical reasons, the application of the code is basically a deep reference to the Afhttprequestoperation class, So at present, the API network requests need to send through nsurlconnection, so we must confirm whether Nsurlconnection supports IPV6. After testing, Nsurlconnection is supporting IPV6 on the latest iOS9 systems.


3.2 Cocoa URL Loading system support IPV6 from which version of iOS?


Currently our minimum version of the application also needs to support iOS7, although Apple only requires the latest version to support Ipv6-only, but in the sense of being responsible for the user, we still need to figure out whether the API Loading system on the lower version supports IPV6.



(To fix me, make some experiments) ~ ~ ~


3.3 reachability Do I need to modify the support IPV6?


We can find out that the application has used a lot of reachability for network state judgment, but it uses IPV4 's dedicated API.


In Pods: Reachability
AF_INET Files: Reachability.m
Struct sockaddr_in Files: Reachability.h , Reachability.m


How should the reachability support IPV6?
(1) The latest version of GitHub's Open Source Library reachability is 3.2, Apple has a support IPV6 reachability official example, we compare the source code, It's no different from reachability on GitHub.
(2) We usually use a 0.0.0.0 (zeroaddress) to open the network status monitoring, after we test, on the iOS9 above the system IPV4 and IPV6 network environment can be used normally But IPV4 and IPV6 are not able to monitor changes in network status on IOS8, possibly because Apple has not been related to IPV6 support in IOS8. (This still satisfies Apple's requirement to support the IPV6 network on the latest system version).
(3) When everyone is asking reachability to add support for IPV6, in fact, Apple in iOS9 above the zero address has been special treatment, the official statement is this:



Reachabilityforinternetconnection:this monitors the address 0.0.0.0,
Which reachability treats as a special token that causes it to actually
Monitor the general routing status of the device, both IPV4 and IPv6.


+ (instancetype)reachabilityForInternetConnection { struct sockaddr_in zeroAddress;
    bzero(&zeroAddress, sizeof(zeroAddress));
    zeroAddress.sin_len = sizeof(zeroAddress);
    zeroAddress.sin_family = AF_INET; return [self reachabilityWithAddress: (const struct sockaddr *) &zeroAddress];
}


To sum up, reachability do not need to make any changes, on the iOS9 can support IPV6 and IPV4, but there will be a bug in IOS9, but the Apple audit does not care.


Iv. How does the underlying socket API support both IPV4 and IPV6?


Because of the use of Network Diagnostics in the application of components, a large number of use of the underlying socket API, so for IPV6 support, this block is a play. If you use a long connection in your application, it will necessarily use the underlying socket API, which is also required to support IPV6. For how the socket supports both IPV4 and IPV6, you can refer to Google's Open Source Library Cocoaasyncsocket.



Here's how we can support both IPV4 and IPV6 for our Open Source Network Diagnostics component.
Open Source Address: https://github.com/Lede-Inc/LDNetDiagnoService_IOS.git
The main functions of this network diagnostic component are as follows:


    • Local network environment monitoring (native ip+ local gateway + local dns+ domain name resolution);
    • Monitoring the connectivity of domain names via TCP connect;
    • The connection time of the target host is monitored by pinging;
    • ICMP time-consuming for each router node in the middle of the target host through the traceroute monitoring device;
4.1 Conversion of IP address from binary to symbolic


Previously we were using Inet_ntoa () binary to sign, this API can only convert IPV4 address. Inet_ntop () is compatible with the conversion of IPV4 and IPV6 addresses. Write a common in6_addr conversion method as follows:


 
//for IPV6
+(NSString *)formatIPV6Address:(struct in6_addr)ipv6Addr{ NSString *address = nil; char dstStr[INET6_ADDRSTRLEN]; char srcStr[INET6_ADDRSTRLEN];
    memcpy(srcStr, &ipv6Addr, sizeof(struct in6_addr)); if(inet_ntop(AF_INET6, srcStr, dstStr, INET6_ADDRSTRLEN) != NULL){
        address = [NSString stringWithUTF8String:dstStr];
    } return address;
} //for IPV4
+(NSString *)formatIPV4Address:(struct in_addr)ipv4Addr{ NSString *address = nil; char dstStr[INET_ADDRSTRLEN]; char srcStr[INET_ADDRSTRLEN];
    memcpy(srcStr, &ipv4Addr, sizeof(struct in_addr)); if(inet_ntop(AF_INET, srcStr, dstStr, INET_ADDRSTRLEN) != NULL){
        address = [NSString stringWithUTF8String:dstStr];
    } return address;
}
4.2 Native IP Access support IPV6


The equivalent of We enter the Ifconfig command in the terminal to get the string, and then parse the ifconfig result string to get the IP address of en0 (emulator), Pdp_ip0 (real machine).



Attention:
(1) in the simulator and the real machine will appear at FE80 beginning of the IPV6 unicast address affect our judgment, so here for special processing (when the first encounter is not a unicast address of the IP address is the native IP address).
(2) in the IPV6 environment, when the real machine test, the first occurrence is a IPV4 address, so in IPV4 conditions for the first time encountered unicast address 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 iPhone if ([[NSString stringWithUTF8String:temp_addr->ifa_name] isEqualToString:@"en0"] || [[NSString stringWithUTF8String:temp_addr->ifa_name] isEqualToString:@"pdp_ip0"])
            { //如果是IPV4地址,直接转化 if (temp_addr->ifa_addr->sa_family == AF_INET){ // Get NSString from C String
                   address = [self formatIPV4Address:((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr];
                } //如果是IPV6地址 else if (temp_addr->ifa_addr->sa_family == AF_INET6){
                    address = [self formatIPV6Address:((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 Device gateway address get get support IPV6


In fact, in the IPV4 to obtain the gateway address of the source code based on the modification, the first open to Af_inet->af_inet6, sockaddr-sockaddr_in6, but also need to pay attention to the following changes, is the number of copies of the address bytes. Removed the handling of the roundup. (Parse out the address is always less 4 bytes, the result is the offset wrong, tangled half a day), specific reference source library.


 
/* net.route.0.inet.flags.gateway */ int mib[] = {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 IPV4 for (i = 0; i < RTAX_MAX; i++) { if (rt->rtm_addrs & (1 << i)) {
                    sa_tab[i] = sa;
                    sa = (struct sockaddr *)((char *)sa + ROUNDUP(sa->sa_len));
                } else {
                    sa_tab[i] = NULL;
                }
            } //for IPV6 for (i = 0; i < RTAX_MAX; i++) { if (rt->rtm_addrs & (1 << i)) {
                    sa_tab[i] = sa;
                    sa = (struct sockaddr_in6 *)((char *)sa + sa->sin6_len);
                } else {
                    sa_tab[i] = NULL;
                }
            }
4.4 Device DNS address get support IPV6


IPV4 only needs to be initialized by Res_ninit, but it needs to be obtained through the res_getservers () interface in the IPV6 environment.


+(NSArray *)outPutDNSServers{
    res_state res = malloc(sizeof(struct __res_state)); int result = res_ninit(res); NSMutableArray *servers = [[NSMutableArray alloc] init]; if (result == 0) { union res_9_sockaddr_union *addr_union = malloc(res->nscount * sizeof(union res_9_sockaddr_union));
        res_getservers(res, addr_union, res->nscount); for (int i = 0; i < res->nscount; i++) { if (addr_union[i].sin.sin_family == AF_INET) { char ip[INET_ADDRSTRLEN];
                inet_ntop(AF_INET, &(addr_union[i].sin.sin_addr), ip, INET_ADDRSTRLEN); NSString *dnsIP = [NSString stringWithUTF8String:ip];
                [servers addObject:dnsIP]; NSLog(@"IPv4 DNS IP: %@", dnsIP);
            } else if (addr_union[i].sin6.sin6_family == AF_INET6) { char ip[INET6_ADDRSTRLEN];
                inet_ntop(AF_INET6, &(addr_union[i].sin6.sin6_addr), ip, INET6_ADDRSTRLEN); NSString *dnsIP = [NSString stringWithUTF8String:ip];
                [servers addObject:dnsIP]; NSLog(@"IPv6 DNS IP: %@", dnsIP);
            } else { NSLog(@"Undefined family.");
            }
        }
    }
    res_nclose(res);
    free(res); return [NSArray arrayWithArray:servers];
}
4.4 Domain DNS address acquisition support IPV6


Under the IPV4 network we get through the gethostname, and in the IPV6 environment, through the new gethostbyname2 function.


//ipv4phot = gethostbyname(hostN);
//ipv6 phot = gethostbyname2(hostN, AF_INET6);
4.5 Ping Scheme supports IPV6


Apple's official offer is the latest ping scheme to support IPV6, with the following reference addresses:
Https://developer.apple.com/library/mac/samplecode/SimplePing/Introduction/Intro.html



Just to be aware of is:
(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 messages are not processed checksum;


4.6 Traceroute Solution Support IPV6


In fact, by creating a socket socket to simulate the transmission of ICMP packets, to calculate time-consuming;
Two key areas to note:
(1) Remove the Ip_ttl field in IPV6, use the hop number ipv6_unicast_hops to express;
(2) The SendTo method is compatible with support for IPV4 and IPV6, but requires the last parameter to set the size of the destination IP address, because the previous parameter only indicates the start address of the IP address. Do not use the unified sizeof (struct sockaddr), because Sockaddr_in and sockaddr are 16 bytes, both can be common, but the SOCKADDR_IN6 data structure is 28 bytes, if not explicitly specified, The SendTo method will always return -1,errono Invalid argument error.



The key code is as follows: (full code reference open Source component)


/ / Construct a common IP address structure stuck sockaddr

 NSString *ipAddr0 = [serverDNSs objectAtIndex:0];
    / / Set the socket address of the server host
    NSData *addrData = nil;
    BOOL isIPV6 = NO;
    If ([ipAddr0 rangeOfString:@":"].location == NSNotFound) {
        isIPV6 = NO;
        Struct sockaddr_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 = [NSData dataWithBytes:&nativeAddr4 length:sizeof(nativeAddr4)];
    } else {
        isIPV6 = YES;
        Struct sockaddr_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 = [NSData dataWithBytes:&nativeAddr6 length:sizeof(nativeAddr6)];
    }

    Struct sockaddr *destination;
    Destination = (struct sockaddr *)[addrData bytes];

/ / Create a socket
If ((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 the socket of the sender socket ttl
If ((isIPV6?
Setsockopt(send_sock,IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl)):
Setsockopt(send_sock, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl))) < 0)

//Send successful return value equal to the length of the sent message
Ssize_t sentLen = sendto(send_sock, cmsg, sizeof(cmsg), 0,
(struct sockaddr *)destination,
isIPV6?sizeof(struct sockaddr_in6):sizeof(struct sockaddr_in)); 


iOS app support IPV6, that's the thing.


Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.