iOS app support IPV6, that's the thing.

Source: Internet
Author: User
Tags htons


Original ConnectionIt 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. :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:

    • Reference: 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: The support ipv6-only network here says, in fact, let the application in IPV6 Dns64/nat64 network environment still can 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 ( However, in order to reduce the risk of audit rejection, it is recommended to replace the IPV4 proprietary API with IPV6 's compatible API)。 Second 2nd: Apple's official statement iOS9 began to support the transition to IPV6, where ios9.2+ supported the IPV4 address synthesis IPV6 address by getaddrinfo method ( The ability to synthesize IPV6 addresses is added to getaddrinfo in IOS 9.2 and OS X 10.11.2)。 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, the answer is to guarantee IPV6 compatibility on Apple's newest system .last 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. Add 4th: If the application has been using the IPV4 address directly through the nsurlconenction or Nsurlsession for network requests (generally requires the server to allow, and the client needs to disguise host in the header), tested, IPV6 network environment, Systems that use IPV4 addresses directly on iOS9 and above still have normal access, and are not accessible in iOS8.4 and below; Apple's explanations and suggestions are this:


Note:in IOS 9 and OS X 10.11 and later, Nsurlsession and cfnetwork automatically synthesize IPv6 addresses from IPV4 Lite RALs locally on devices operating on Dns64/nat64 networks. However, you should still work to rid your code of IP address literals.


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 makes us wonder: using high-level networking APIs such as Nsurlsession and the Cfnetwork frameworks and you connect By name, you should not need to the change anything for your apps to work with IPV6 addresses only said Nsurlsession and Cfnetwork APIs There is no need to change, 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 user responsibility, we still need to figure out whether the API on the lower version of the URL Loading system supports IPV6. (To fix Me, make some experiments) to be Continued ~ ~ ~

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 tha T 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. Let me say how we support both IPV4 and IPV6 for our open Source network diagnostic 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 symbolicpreviously 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 Local IP acquisition support IPV6
Equivalent to 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 (Wifi), pdp_ip0 (mobile network). Note: (1) IPV6 unicast address starting with FE80 will affect our judgment on both the emulator and the real machine, so special processing is performed here (when the first time encounters an IP address that is not a unicast address, it is the local machine. IP address). (2) In the IPV6 environment, when the real machine test, the first one appears is an IPV4 address, so the first time the IP address is encountered, the 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"])
            {
                / / If it is an IPV4 address, direct conversion
                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];
                }

                //If it is an IPV6 address
                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 IPV6in 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 xss=removed xss=removed>rtm_addrs & (1 << i xss=removed xss=removed>sa_len));
                } else {
                    sa_tab[i] = NULL;
                }
            }

  //for IPV6
     for (i = 0; i < RTAX>rtm_addrs & (1 << i xss=removed xss=removed>sin6_len);
                } else {
                    sa_tab[i] = NULL;
                }
            }
4.4 Domain DNS address acquisition support IPV6under the IPV4 network we get through the gethostname, and in the IPV6 environment, through the new gethostbyname2 function.
 

+(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.5 Ping Scheme supports IPV6Apple's official offers the latest ping scheme to support IPV6, with the following address: https://developer.apple.com/library/mac/samplecode/SimplePing/ Introduction/intro.html just need to note is: (1) The returned packet removed the Ipheader part, IPV6 header part also does not return the TTL (Time to Live) field; (2) IPV6 ICMP messages are not processed checksum;4.6 traceroute Solution support IPV6in fact, through the creation of socket sockets to simulate the transmission of ICMP packets, to calculate time-consuming, two key points to note: (1) IPV6 removed Ip_ttl field, use the hop number ipv6_unicast_hops to represent; (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)
 

Constructs a generic IP address structure stuck sockaddr 
nsstring *ipaddr0 = [Serverdnss objectatindex:0]; 
 Set the server host's socket address 
nsdata *addrdata = nil; 
BOOL isIPV6 = NO;
if ([IpAddr0 rangeofstring:@ ":"].location = = nsnotfound) {
 i
 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 socket
if ((recv_sock = socket(destination->sa_family, SOCK_DGRAM, isIPV6?IPPROTO_ICMPV6:IPPROTO_ICMP)) < 0 xss=removed>sa_family, SOCK_DGRAM, 0)) &lt; 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))) &lt; 0)
//The successful return value is 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.