background

Recently, I have been doing iOS DNS resolution, and I have studied the localDNS resolution mode (localDNS) of iOS, which does not rely on Http requests, but uses the original API for resolution. Although there is HttpDNS, considering the cost and the stability of third-party services, LocalDNS is still a very important part. In the iOS system, there are three resolution modes of LocalDNS. The advantages and disadvantages of the three modes are analyzed as follows and their principles are briefly introduced.

Methods a

This is how I started my project.

1: struct hostent *gethostbyname(const char *); 2: struct hostent * gethostByname2 (const char *, int);Copy the code

The two functions have the same function and return the same value, but the first function can only be used on IPV4 networks, while the second function can be used on both IPV4 and IPV6 networks, and can be passed to the current network environment with the second parameter.

Usage:
 CFAbsoluteTime start = CFAbsoluteTimeGetCurrent();
    
    char   *ptr, **pptr;
    struct hostent *hptr;
    char   str[32];
    ptr = "www.meitu.com";
    NSMutableArray * ips = [NSMutableArray array];

     if((hptr = gethostbyname(ptr)) == NULL)
    {
        return;
    }

    for(pptr=hptr->h_addr_list; *pptr! =NULL; pptr++) { NSString * ipStr = [NSString stringWithCString:inet_ntop(hptr->h_addrtype, *pptr, str, sizeof(str)) encoding:NSUTF8StringEncoding]; [ips addObject:ipStr?:@""];
    }

    CFAbsoluteTime end = CFAbsoluteTimeGetCurrent();
    NSLog(@"22222 === ip === %@ === time cost: %0.3fs", ips,end - start);
Copy the code

Struct hostent * HPTR (gethostbyname);

struct hostent { char *h_name; /* official name of host */ char **h_aliases; / *alias list */
	int	h_addrtype;	/* host address type */
	int	h_length;	/* length of address */
	char	**h_addr_list;	/* list of addresses from name server */
#if ! defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE)
#define	h_addr	h_addr_list[0]	/* address, for backward compatibility */
#endif /* (! _POSIX_C_SOURCE || _DARWIN_C_SOURCE) */
};
Copy the code
Parameter analysis:
  • Hostent ->h_name indicates the standard name of the host. For example, the canonical name for www.baidu.com is www.a.shifen.com.

  • Hostent ->h_aliases indicates the alias of the host www.baidu.com. Sometimes, some hosts may have several individual names, these, in fact, are for easy user memory and for their own website name.

  • Hostent -> h_addrType specifies the type of host IP address, whether it is ipv4(AF_INET) or PV6 (AF_INET6).

  • Hostent ->h_length indicates the length of the host IP address

  • Hostent ->h_addr_lisst represents the IP address of the host. Note that this is stored in network byte order. Don’t type this thing with printf with %s, it’s going to be a problem. So to actually print the IP, we need to call const char *inet_ntop(int af, const void * SRC, char * DST, socklen_t CNT) to convert it to char. See above for detailed usage

Disadvantages:
  • In the network switch when the small probability of stuck, self-test ten times there are about one or two.

  • LocalDns is stuck for 30 seconds when corrupted and returns nil.

  • Caching is a metaphysical thing, it will cache its resolved IP (probably the carrier’s cache) for an indefinite period of time, it is possible that even if I switch countless networks, the same domain name will always resolve the same IP from morning to night,

  • There are more problems on the Internet

Way 2

In addition to the frequently used gethostbyName (3) and gethostbyaddr(3) functions, Linux(and other UNIX/UNIX-like systems) also provides a set of functions for handling DNS-related problems at the underlying level (in contrast to the gethostbyname and gethostbyaddr functions). These functions are called resolver functions. Have tried this before…

int res_query __P((const char *, int, int, u_char *, int)); Int res_query(const char *dname, int class, inttype, unsigned char *answer, int anslen)
Copy the code

This approach requires adding the libresolv.tbd library to the project because it depends on the functions in the library for parsing. Res_query is used to issue a DNS query with a specified class (specified by the class argument) and type (specified by the type argument). Dname is the host name to be queried. The returned information is stored in the memory region that answser points to. The length of the message cannot be larger than anslen bytes. This function creates a DNS query message and sends it to the specified DNS server.

use
CFAbsoluteTime start = CFAbsoluteTimeGetCurrent();

    unsigned char auResult[512];
    int nBytesRead = 0;
    
    nBytesRead = res_query("www.meitu.com", ns_c_in, ns_t_a, auResult, sizeof(auResult));
    
    ns_msg handle;
    ns_initparse(auResult, nBytesRead, &handle);
    
    NSMutableArray *ipList = nil;
    int msg_count = ns_msg_count(handle, ns_s_an);
    if (msg_count > 0) {
        ipList = [[NSMutableArray alloc] initWithCapacity:msg_count];
        for(int rrnum = 0; rrnum < msg_count; rrnum++) {
            ns_rr rr;
            if(ns_parserr(&handle, ns_s_an, rrnum, &rr) == 0) {
                char ip1[16];
                strcpy(ip1, inet_ntoa(*(struct in_addr *)ns_rr_rdata(rr)));
                NSString *ipString = [[NSString alloc] initWithCString:ip1 encoding:NSASCIIStringEncoding];
                if(! [ipString isEqualToString:@""[ipList addObject:ipString]; [ipList addObject:ipString]; } } } CFAbsoluteTime end = CFAbsoluteTimeGetCurrent(); NSLog(@"11111 === ip === %@ === time cost: %0.3fs", ipList,end - start);
    }
Copy the code
Argument parsing

Because this logic is the code provided by Linux bottom layer, Apple has done a package with macro, the specific function meaning also needs to understand the Linux kernel, here is a reference

Advantages:
  • Prompt response without delay in case LocalDns is corrupted.
  • There is no cache, the cache is controlled by the developer
disadvantages
  • This shortcoming is more fatal when 3G/4G cut wify when switching network, so it is not continued to use.

Methods three

Apple native DNS resolution

Boolean CFHostStartInfoResolution (CFHostRef theHost, CFHostInfoType info, CFStreamError *error);
Copy the code
Usage:
    Boolean result,bResolved;
    CFHostRef hostRef;
    CFArrayRef addresses = NULL;
    NSMutableArray * ipsArr = [[NSMutableArray alloc] init];

    CFStringRef hostNameRef = CFStringCreateWithCString(kCFAllocatorDefault, "www.meitu.com", kCFStringEncodingASCII);
    
    hostRef = CFHostCreateWithName(kCFAllocatorDefault, hostNameRef);
    CFAbsoluteTime start = CFAbsoluteTimeGetCurrent();
    result = CFHostStartInfoResolution(hostRef, kCFHostAddresses, NULL);
    if (result == TRUE) {
        addresses = CFHostGetAddressing(hostRef, &result);
    }
    bResolved = result == TRUE ? true : false;
    
    if(bResolved)
    {
        struct sockaddr_in* remoteAddr;
        for(int i = 0; i < CFArrayGetCount(addresses); i++)
        {
            CFDataRef saData = (CFDataRef)CFArrayGetValueAtIndex(addresses, i);
            remoteAddr = (struct sockaddr_in*)CFDataGetBytePtr(saData);
            
            if(remoteAddr ! = NULL) {// Get IP address char IP [16]; strcpy(ip, inet_ntoa(remoteAddr->sin_addr)); NSString * ipStr = [NSString stringWithCString:ip encoding:NSUTF8StringEncoding]; [ipsArr addObject:ipStr]; } } } CFAbsoluteTime end = CFAbsoluteTimeGetCurrent(); NSLog(@"33333 === ip === %@ === time cost: %0.3fs", ipsArr,end - start);
    CFRelease(hostNameRef);
    CFRelease(hostRef);
Copy the code
Parameter analysis:
/*
 *  CFHostStartInfoResolution()
 *  
 *  Discussion:
 *	Performs a lookup for the given host.  It will search for the
 *	requested information if there is no other active request. 
 *	Previously cached information of the given typewill be released. * * Mac OS X threading: * Thread safe * * Parameters: * * theHost: // CFHostRef object that needs to be resolved * The CFHostRefwhichshould be resolved. Must be non-NULL. If * this reference is not a valid CFHostRef, The behavior is * undefined. * * info: array of returned values /Data/string.. * The enum representing thetype of information to be retrieved. 
 *	  If the value is not a valid type* * error: error * A reference to A CFStreamError structurewhich will be filled
 *	  with any error information should an error occur.  May be set
 *	  to NULL iferror information is not wanted. * * Result: * Returns TRUE on success and FALSE on failure. In asynchronous * mode, thisfunction will returnimmediately. In synchronous * mode, it will block until the resolve has completed or until the * resolve is cancelled. * */ CFN_EXPORT __nullable CFArrayRef  CFHostGetAddressing(CFHostRef theHost, Boolean * __nullable hasBeenResolved) CF_AVAILABLE(10_3, 2_0);Copy the code
Advantages:
  • There is no lag during network switching.
Disadvantages:
  • – The local DNS will freeze if it is damaged (30s)

Conclusion:

The above three methods are optional except for the second method, which will be blocked during network switchover. The other two methods are optional. It seems inevitable that the local LocalDns will be blocked when the local LocalDns is damaged. In the case of destruction, use httpDns for resolution. Specific Demo can go here to see my Jane book synchronization with new