iOS app support IPV6

Source: Internet
Author: User
Tags sin htons
Said for a long time ipv6, rub, seems to have never encountered it

 

Come again and write down the problems colleagues encountered

 

What is IPV6-Only support?
First of all, 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, but as operators and enterprises gradually deploy IPV6 DNS64 / NAT64 networks, the addresses assigned to devices will change IPV6 addresses, and these networks are the so-called IPV6-Only networks, and can still get content provided by IPV4 addresses through this network. The client requests domain name resolution from the server. First, it queries the IPv6 address through the DNS64 Server. If not, it queries the DNS server for the IPv4 address, synthesizes an IPV6 address through the DNS64 Server, and finally returns an IPV6 address to the client . :


NAT64-DNS64-ResolutionOfIPv4_2x.png
In Mac OS 10.11+ Mac machine with dual network cards (Ethernet port + wireless network card), we can test whether the application supports the IPV6-Only network by simulating the construction of such a local IPv6 DNS64 / NAT64 network environment. The general principle is as follows:


local_ipv6_dns64_nat64_network_2x.png
References:
https://developer.apple.com/library/mac/documentation/NetworkingInternetWeb/Conceptual/NetworkingOverview/UnderstandingandPreparingfortheIPv6Transition/UnderstandingandPreparingfortheIPv6Transition.html#//apple_ref/doc/uid/TP40010220-CH213-SW1
2. How does Apple audit support IPV6-Only?
First of all, the first point: Supporting IPV6-Only network here means that the application can still run normally under IPv6 DNS64 / NAT64 network environment. However, considering that our current actual network environment is still an IPV4 network, the application needs to be able to guarantee the availability under both IPV4 and IPV6 environments. From this point, Apple will not scan IPV4's proprietary API to reject the audit, because both the IPV4 API and IPV6 API calls will exist in the code at the same time (however, in order to reduce the risk of audit rejection, it is recommended to There are APIs that are replaced by IPV6 compatible APIs).

Second point: Apple officially states that iOS9 has started to transition to IPV6 support. In iOS9.2 +, the ability to synthesize IPv6 addresses was added to getaddrinfo in iOS 9.2 and OS X 10.11.2 is supported. ). The Reachability library provided under the iOS8 system, when switching from IPV4 to IPV6 network, or from IPV6 network to IPV4, it is impossible to monitor the change of network status. There are also some developers who asked Apple's review department for these bugs, and the answer given was that they only needed to ensure IPV6 compatibility on Apple's latest system.

Last and third point: As long as the main process of the application supports IPV6, it can pass Apple's review. For modules that do not support IPV6, considering that our actual IPV6 network deployment will take some time, it will not affect the use of our users in a short time. However, with the deployment of 4G network IPV6, this part of the module still needs to gradually arrange manpower for support.

Added the fourth point: if the application has always used the IPV4 address to make network requests through NSURLConenction or NSURLSession (usually requires the server to allow, and the client needs to disguise the host in the header); after testing, under the IPV6 network environment, use the IPV4 address directly in iOS9 And above systems can still be accessed normally; they cannot be accessed normally under iOS 8.4 and below; Apple's explanation and recommendations are this:

Note: In iOS 9 and OS X 10.11 and later, NSURLSession and CFNetwork automatically synthesize IPv6 addresses from IPv4 literals locally on devices operating on DNS64 / NAT64 networks. However, you should still work to rid your code of IP address literals.

How does the application support IPV6-Only?
Regarding how to support IPV6-Only, the following standards are officially provided: (I will not explain them here, you can just look at the reference link above)

1. Use High-Level Networking Frameworks;
2. Do n’t Use IP Address Literals;
3. Check Source Code for IPv6 DNS64 / NAT64 Incompatibilities;
4. Use System APIs to Synthesize IPv6 Addresses;
3.1 Does NSURLConnection support IPv6?
This official statement 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 change anything for your app to work with IPv6 addresses

It only said that the APIs of NSURLSession and CFNetwork do not need to be changed, but NSURLConnection is not mentioned. From the above reference materials, we see that NSURLSession and NSURLConnection both belong to Cocoa's url loading system. It can be guessed that NSURLConnection supports IPV6 on ios9.

For the API network request in the application, everyone generally chooses AFNetworking to send the request. Due to historical reasons, the application code basically references the AFHTTPRequestOperation class in depth, so the current API network requests need to be sent out through NSURLConnection, so you must confirm whether NSURLConnection supports IPV6. After testing, NSURLConnection supports IPV6 on the latest iOS9 system.

3.2 Which version of iOS does Cocoa's URL Loading System support for IPv6?
At present, the minimum version of our application also needs to support iOS7. Although Apple only requires the latest version to support IPV6-Only, we still need to figure out whether the API of URL Loading System supports IPV6 on the lower version.

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

3.3 Does Reachability need to be modified to support IPv6?
We can find that Reachability is used in the application for network status judgment, but IPV4's dedicated API is used in it.

In Pods: Reachability
AF_INET Files: Reachability.m
struct sockaddr_in Files: Reachability.h, Reachability.m
So how should Reachability support IPV6?
(1) The latest version of Reachability, Github's open source library, is 3.2. Apple also released an official example of Reachability that supports IPV6. We compared the source code and there is no difference between Reachability on Github.
(2) We usually use a 0.0.0.0 (ZeroAddress) to enable network status monitoring. After our tests, IPV4 and IPV6 network environments can be used normally on iOS9 and above systems; however, IPV4 and IPV6 are switched between each other on iOS8 It is not possible to monitor the change of network status at this time, it may be because Apple has not provided relevant support for IPV6 on iOS8. (But this still meets Apple's requirements for networks that support IPV6 on the latest system version).
(3) When everyone is asking for Reachability to add support for IPV6, in fact, Apple has specially dealt with Zero Address on iOS9 and above. 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];
}
In summary, Reachability does not need to be modified, and it can support IPV6 and IPV4 on iOS9, but there will be bugs under iOS9, but Apple's review does not care.

How does the underlying socket API support both IPV4 and IPV6?
Because the network diagnostic components are used in the application, and the underlying socket API is used extensively, this is the highlight of IPV6 support. If your application uses long connections, it will inevitably use the underlying socket API, which also needs to support IPV6. For how Socket supports both IPV4 and IPV6, please refer to Google's open source library CocoaAsyncSocket.

Let's talk about our open source network diagnostic component, how to support both IPV4 and IPV6.
Open source address: https://github.com/Lede-Inc/LDNetDiagnoService_IOS.git
The main functions of this network diagnostic component are as follows:

Monitoring of local network environment (local IP + local gateway + local DNS + domain name resolution);
Monitoring the connectivity of the domain name through TCP Connect;
Monitoring the connection time to the target host through Ping;
Monitoring the ICMP time of each router node between the device and the target host through traceRoute;
4.1 IP address conversion from binary to symbol
Previously, we used binary to symbol through inet_ntoa (). This API can only translate IPV4 addresses. And inet_ntop () is compatible to translate IPV4 and IPV6 addresses. Write a public 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 = [NSS
tring 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 Acquisition Support IPV6
It is equivalent to entering the ifconfig command in the terminal to obtain the string, and then parsing the ifconfig result string to obtain the IP addresses of en0 (Wifi) and pdp_ip0 (mobile network).

note:
(1) The IPV6 unicast address beginning with FE80 will affect our judgment on both the simulator and the real machine, so special processing is performed here (when the first encounter with an IP address that is not a unicast address is the local IP address ).
(2) In the IPV6 environment, when the real machine is tested, the first one that appears is an IPV4 address, so it does not exit when it encounters a unicast address for the first time under the condition of IPV4.

+ (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, translate directly
                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 Obtaining Support for IPv6
In fact, the source code of the gateway address obtained by IPV4 was modified. In the initial opening, AF_INET-> AF_INET6, sockaddr-> sockaddr_in6, and the following modifications need to be paid attention to, which is the number of address bytes copied. Removed the processing of ROUNDUP. (The parsed address is always 4 bytes less, and the result is that the offset is wrong, tangled for a long time). For details, refer to the source code 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 Acquisition Support IPV6
In IPV4, it only needs to be initialized through res_ninit, but in IPV6 environment, it can be obtained through the res_getservers () interface.

+ (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 name DNS address acquisition support IPv6
In the IPV4 network, we obtain it through gethostname, and in the IPV6 environment, we obtain it through the new gethostbyname2 function.

// ipv4
phot = gethostbyname (hostN);

// ipv6
 phot = gethostbyname2 (hostN, AF_INET6);
4.5 ping scheme supports IPV6
Apple's official provides the latest ping scheme that supports IPv6. The reference address is as follows:
https://developer.apple.com/library/mac/samplecode/SimplePing/Introduction/Intro.html

Just note that:
(1) The returned packet removes the IPHeader part, and the header part of IPV6 does not return the Time to Live (TTL) field;
(2) IPV6 ICMP messages are not processed by checkSum;

4.6 traceRoute solution supports IPv6
In fact, the creation of a socket is used to simulate the sending of ICMP messages to calculate the time consumption.
Two key points need attention:
(1) Remove the IP_TTL field from IPV6 and use the hop count IPV6_UNICAST_HOPS instead.
(2) The sendto method is compatible with IPV4 and IPV6, but requires the last parameter to specify the size of the target IP address; because the previous parameter only specifies the starting address of the IP address. Do not use the unified sizeof (struct sockaddr), because sockaddr_in and sockaddr are both 16 bytes, they can be used universally, but the data structure of sockaddr_in6 is 28 bytes. If you do not specify it explicitly, sendto method will Returns -1, erroNo reports 22 Invali
d argument error.

The key code is as follows: (complete code refer to open source components)

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

// Successful return value is equal to the length of the message sent
ssize_t sentLen = sendto (send_sock, cmsg, sizeof (cmsg), 0,
(struct sockaddr *) destination,
isIPV6? sizeof (struct sockaddr_in6): sizeof (struct sockaddr_in));
 http://www.jianshu.com/p/a6bab07c4062 is the original address

iOS app supports IPV6
Related Article

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.