10dns是否影响解析 ios

2017-12-14 08:57:19 weixin_33785972 阅读数 440
  • 实验 5:路由器密码恢复【此课时有资料下载】

    本课程从零开始系统性的演示了CCNA的实验操作,并且在实验操作的同时讲解CCNA对应的理论知识点,同时又不局限于大纲的要求,有些工作中比较重要的运用,比如三层交换机、HSRP、IPV6、MSTP等,即使超出大纲范围,也会...

    918人学习 晁海江
    免费试看

背景

最近在做iOS的DNS解析,顺便研究了下iOS端本地的DNS解析方式(localDNS),也就是不依赖Http请求,而是用原始的API进行解析,虽然有HttpDNS但是考虑到成本、第三方服务稳定性的问题,LocalDNS仍然是一个很重要的部分,在iOS系统下,localDNS的解析方式有三种,下面主要对三种方式进行下利弊分析及简单的原理介绍。

方式一

这个也是我一开始在项目中使用的方式。

1:struct hostent	*gethostbyname(const char *);
2:struct hostent	*gethostbyname2(const char *, int);
复制代码

两个函数作用完全一样,返回值一样,但是第一个只能用于IPV4的网络环境,而第二个则IPV4和IPV6都可使用,可以通过第二个参数传入当前的网络环境。

使用方式:
 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);
复制代码

使用gethostbyname方法后会得到一个struct,也就是上文的struct hostent *hptr:

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) */
};
复制代码
参数解析:
  • hostent->h_name 表示的是主机的规范名。例如www.baidu.com的规范名其实是www.a.shifen.com。

  • hostent->h_aliases 表示的是主机的别名www.baidu.com的别名就是他自己。有的时候,有的主机可能有好几个别名,这些,其实都是为了易于用户记忆而为自己的网站多取的名字。

  • hostent->h_addrtype
    表示的是主机ip地址的类型,到底是ipv4(AF_INET),还是pv6(AF_INET6)

  • hostent->h_length
    表示的是主机ip地址的长度

  • hostent->h_addr_lisst 表示的是主机的ip地址,注意,这个是以网络字节序存储的。不要直接用printf带%s参数来打这个东西,会有问题的哇。所以到真正需要打印出这个IP的话,需要调用const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt),来把它转成char。详细使用见上文

缺点:
  • 在进行网络切换的时候小概率卡死,自测十次有一两次左右。

  • 在本地的LocalDns被破坏的时候会必卡死30秒,然后返回nil 。

  • 缓存是个玄学东西,他会对自己解析出来的IP进行缓存(可能是运营商缓存)缓存时间不确定,有可能我即使切换了无数个网络,但是从早到晚同一个域名总是解析出同样的IP,

  • 网上说的比较多的问题

方式二

除了经常用到的gethostbyname(3)和gethostbyaddr(3)函数以外, Linux(以及其它UNIX/UNIX-like系统)还提供了一套用于在底层处理DNS相关问题的函数(这里所说的底层仅是相对gethostbyname和gethostbyaddr两个函数而言). 这套函数被称为地址解析函数(resolver functions)。曾经尝试过这个方式...

int		res_query __P((const char *, int, int, u_char *, int));
函数原型为:
int res_query(const char *dname, int class, int type, unsigned char *answer, int anslen)
复制代码

这个方式需要在项目中添加libresolv.tbd库,因为要依赖于库中的函数去解析。res_query用来发出一个指定类(由参数class指定)和类型(由参数type指定)的DNS询问. dname是要查询的主机名. 返回信息被存储在answser指向的内存区域中. 信息的长度不能大于anslen个字节. 这个函数会创建一个DNS查询报文并把它发送到指定的DNS服务器。

使用方式
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:@""]) {
                    
                    //将提取到的IP地址放到数组中
                    [ipList addObject:ipString];
                }
            }
        }
        CFAbsoluteTime end = CFAbsoluteTimeGetCurrent();
        NSLog(@"11111 === ip === %@ === time cost: %0.3fs", ipList,end - start);
    }
复制代码
参数解析

由于该逻辑是Linux底层提供的代码,苹果用宏做了一次封装,具体的函数含义还需要对Linux内核的理解,这里放一篇参考资料

优点:
  • 在LocalDns被破坏掉的情况下能及时响应不会延迟。
  • 没有缓存,缓存由开发者控制
缺点
  • 在进行网络切换时候3G/4G切wify高概率出现卡死 这一个缺点是比较致命的,所以没有再继续使用。

方式三

苹果原生的DNS解析

Boolean CFHostStartInfoResolution (CFHostRef theHost, CFHostInfoType info, CFStreamError *error);
复制代码
使用方法:
    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)
            {
                //获取IP地址
                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);
复制代码
参数解析:
/*
 *  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 type will be released.
 *  
 *  Mac OS X threading:
 *	Thread safe
 *  
 *  Parameters:
 *	
 *	theHost:  //需要被解决的CFHostRef的对象
 *	  The CFHostRef which should be resolved. Must be non-NULL. If
 *	  this reference is not a valid CFHostRef, the behavior is
 *	  undefined.
 *	
 *	info: 返回值的类型 数组/Data/string..
 *	  The enum representing the type of information to be retrieved. 
 *	  If the value is not a valid type, the behavior is undefined.
 *	
 *	error: 错误
 *	  A reference to a CFStreamError structure which will be filled
 *	  with any error information should an error occur.  May be set
 *	  to NULL if error information is not wanted.
 *  
 *  Result: 解析结果成功还是失败
 *	Returns TRUE on success and FALSE on failure.  In asynchronous
 *	mode, this function will return immediately.  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);
复制代码
优点:
  • 在网络切换时候不会卡顿。
缺点:
  • 在本地DNS被破坏的情况下会出现卡死的现象(卡30s)

总结:

以上三个方法除了第二个方法会在网络切换时候卡死不可用之外,其他两个方法都是可选择的,关于那个本地LocalDns破坏会卡死的问题看来是无法避免,不过开发者可以自行通过ping等方式来判断LocalDns的正确性,在被破坏的情况下使用httpDns来进行解析即可。具体的Demo可以到这里查看 我的简书同步跟新

2015-03-12 20:44:05 u010140921 阅读数 2534
  • 实验 5:路由器密码恢复【此课时有资料下载】

    本课程从零开始系统性的演示了CCNA的实验操作,并且在实验操作的同时讲解CCNA对应的理论知识点,同时又不局限于大纲的要求,有些工作中比较重要的运用,比如三层交换机、HSRP、IPV6、MSTP等,即使超出大纲范围,也会...

    918人学习 晁海江
    免费试看
#import  <CFNetwork/CFHost.h>
#import <netinet/in.h>
#import <netdb.h>  
#import <SystemConfiguration/SystemConfiguration.h>

#pragma mark -
#pragma mark DNS解析和网络测试
-(NSString*) getAddressFromArray:(CFArrayRef) addresses
{
    struct sockaddr  *addr;
    char             ipAddress[INET6_ADDRSTRLEN];
    CFIndex          index, count;
    int              err;

    assert(addresses != NULL);


    count = CFArrayGetCount(addresses);
    for (index = 0; index < count; index++) {
        addr = (struct sockaddr *)CFDataGetBytePtr(CFArrayGetValueAtIndex(addresses, index));
        assert(addr != NULL);

        /* getnameinfo coverts an IPv4 or IPv6 address into a text string. */
        err = getnameinfo(addr, addr->sa_len, ipAddress, INET6_ADDRSTRLEN, NULL, 0, NI_NUMERICHOST);
        if (err == 0) {
            NSLog(@"解析到ip地址:%s\n", ipAddress);
        } else {
            NSLog(@"地址格式转换错误:%d\n", err);
        }
    }
    return    [[NSString alloc] initWithFormat:@"%s",ipAddress];//这里只返回最后一个,一般认为只有一个地址
}


-(bool)getReachability:(CFDataRef) data withNameOrAddress:(CFStringRef) nameOrAddress
{
    SCNetworkConnectionFlags  *flags;
    CFIndex                   length;
    char                      *input;
    Boolean                   success;

    assert(data != NULL);
    assert(nameOrAddress != NULL);

    /* CFStringGetMaximumSizeForEncoding determines max bytes a string of specified length will take up if encoded. */
    length = CFStringGetMaximumSizeForEncoding(CFStringGetLength(nameOrAddress), kCFStringEncodingASCII);
    input = malloc(length + 1);
    assert(input != NULL);

    success = CFStringGetCString(nameOrAddress, input, length + 1, kCFStringEncodingASCII);
    assert(success);

    flags = (SCNetworkConnectionFlags *)CFDataGetBytePtr(data);
    assert (flags != NULL);

    /* If you only have a PPP interface enabled, the flags will be 0 because of a bug. <rdar://problem/3627771> */
    if (*flags == 0) NSLog(@"%s -> Reachability Unknown\n", input);

    if (*flags & kSCNetworkFlagsTransientConnection)  NSLog(@"%s -> Transient Connection\n",  input);
    if (*flags & kSCNetworkFlagsReachable)           {
        NSLog(@"%s -> Reachable\n",             input);
        success = YES;
    }else {
        success = NO;
    }
    if (*flags & kSCNetworkFlagsConnectionRequired)   NSLog(@"%s -> Connection Required\n",   input);
    if (*flags & kSCNetworkFlagsConnectionAutomatic)  NSLog(@"%s -> Connection Automatic\n",  input);
    if (*flags & kSCNetworkFlagsInterventionRequired) NSLog(@"%s -> Intervention Required\n", input);
    if (*flags & kSCNetworkFlagsIsLocalAddress)       NSLog(@"%s -> Is Local Address\n",      input);
    if (*flags & kSCNetworkFlagsIsDirect)             NSLog(@"%s -> Is Direct\n",             input);

    free(input);
    return success;
}

-(void) serverResoluton{

    CFStringRef             hostName = (CFStringRef)self.serverInfo.serverAddress; 
    CFHostRef            host;
    CFStreamError        error;
    Boolean              success;
    CFArrayRef             addressArray;
    CFDataRef             ReachableData;

    assert(hostName != NULL);

    /* Creates a new host object with the given name. */
    host = CFHostCreateWithName(kCFAllocatorDefault, hostName);
    assert(host != NULL);

    success = CFHostStartInfoResolution(host, kCFHostAddresses, &error);
    if (!success) {
        NSLog(@"CFHostStartInfoResolution 返回错误 (%d, %ld)", error.domain, error.error);//如果解析地址失败,使用直接指定IP
        NSLog(@"启用直接指定IP:%@",self.serverInfo.serverIPAddress);
        self.serverInfo.serverAddress = self.serverInfo.serverIPAddress;
    }else {
        addressArray = CFHostGetAddressing(host, nil);
        [self.serverInfo.serverAddress release];
        self.serverInfo.serverAddress = [[NSString alloc] initWithFormat:@"%@",[self getAddressFromArray:addressArray]];
        NSLog(@"替换地址为:%@", self.serverInfo.serverAddress);
    }

    //使用新地址来确认可连接性
    hostName = (CFStringRef)self.serverInfo.serverAddress;
    host = CFHostCreateWithName(kCFAllocatorDefault, hostName);
    success = CFHostStartInfoResolution(host, kCFHostReachability, &error);
    if (!success) {
        NSLog(@"CFHostStartInfoResolution 返回错误 (%d, %ld)", error.domain, error.error);
        //暂不知到这里会在什么情况下发生
    }else {
        ReachableData = CFHostGetReachability(host, nil);
        success = [self getReachability:ReachableData withNameOrAddress:(CFStringRef)hostName];
        if (!success) {
            [self.serverInfo.serverAddress release];
            self.serverInfo.serverAddress = self.serverInfo.serverAddressBak;//在这里添加备用服务器
        }
    }    

}

转自:http://www.cppblog.com/brucejini/archive/2011/01/27/139437.html

2018-01-03 02:41:15 weixin_33770878 阅读数 143
  • 实验 5:路由器密码恢复【此课时有资料下载】

    本课程从零开始系统性的演示了CCNA的实验操作,并且在实验操作的同时讲解CCNA对应的理论知识点,同时又不局限于大纲的要求,有些工作中比较重要的运用,比如三层交换机、HSRP、IPV6、MSTP等,即使超出大纲范围,也会...

    918人学习 晁海江
    免费试看

介绍两种收集来的本地DNS解析的方式

- (NSArray*)DNSBySystem:(NSString *)dominName{
    Boolean result = '\0',bResolved;
    CFHostRef hostRef;
    CFArrayRef addresses = NULL;
    NSString *finalString = nil;
    char tempChar[1000];
    NSMutableArray *ipResults = [NSMutableArray arrayWithCapacity:10];
    strcpy(tempChar,(char *)[dominName UTF8String]);
    CFStringRef hostNameRef = CFStringCreateWithCString(kCFAllocatorDefault, tempChar, kCFStringEncodingASCII);
    hostRef = CFHostCreateWithName(kCFAllocatorDefault, hostNameRef);
    if (hostRef) {
        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)
            {
                //DNS解析结果cpy到char数组里
                char ip[16];
                strcpy(ip, inet_ntoa(remoteAddr->sin_addr));
                finalString = [NSString stringWithCString:ip encoding:NSUTF8StringEncoding];
                [ipResults addObject:finalString];
            }
        }
    }
    CFRelease(hostNameRef);
    CFRelease(hostRef);
    return ipResults;
}
复制代码

上面这种方法在IPv6环境下解析有点问题,IPv4下无问题。下面这种方法两种环境下都适用

- (NSArray *)dnsByLocal:(NSString *)domain {
    if (domain.length == 0) {
        return nil;
    }
    struct addrinfo hints;
    memset(&hints, 0, sizeof(hints));
    hints.ai_family = PF_INET;
    hints.ai_protocol = IPPROTO_TCP;
    struct addrinfo *addrs, *addr;
    
    int getResult = getaddrinfo([domain UTF8String], NULL, &hints, &addrs);
    if (getResult || addrs == nil) {
        NSLog(@"Warn: DNS with domain:%@ failed:%d", domain, getResult);
        return nil;
    }
    addr = addrs;
    NSMutableArray *result = [NSMutableArray array];
    for (addr = addrs; addr; addr = addr->ai_next) {
        char host[NI_MAXHOST];
        memset(host, 0, NI_MAXHOST);
        getnameinfo(addr->ai_addr, addr->ai_addrlen, host, sizeof(host), NULL, 0, NI_NUMERICHOST);
        if (strlen(host) != 0) {
            [result addObject:[NSString stringWithUTF8String:host]];
        }
    }
    freeaddrinfo(addrs);
    NSLog(@"Info: DNS with domain:%@ -> %@", domain, result);
    return result;
}
复制代码
2014-11-18 09:21:28 u014011807 阅读数 1784
  • 实验 5:路由器密码恢复【此课时有资料下载】

    本课程从零开始系统性的演示了CCNA的实验操作,并且在实验操作的同时讲解CCNA对应的理论知识点,同时又不局限于大纲的要求,有些工作中比较重要的运用,比如三层交换机、HSRP、IPV6、MSTP等,即使超出大纲范围,也会...

    918人学习 晁海江
    免费试看

电脑在对网络进行访问的时候只认识IP,所以电脑在对网络资源进行访问的时候,第一步就是吧要请求的URL转化为IP地址,这里就要用到一个叫DNS的东东。

在说白话一点,利用DNS,我们在访问百度的时候,就吧这个www.baidu.com翻译成了某个,比如192.126.1.0的IP。

下面描述下DNS的几个特点:

(1)DNS是一个分布式数据库,是一个类似域名和IP对应的数据库。

(2)本身是一个树状结构

(3)树状结构中只能由上级寻找下级,下级不能寻找上级

(4)DNS的域名解析过程

4.1 访问网址的时候www.baidu.com 第一步通过本地的local DNS 查看,所访问的资源是不是在本地所管理的Local DNS范围内,如果是,那么将资源的IP地址返回。

4.2 如果local DNS查找不到资源,那么返回到源DNS,目前全球共有13个根源DNS,分布在美国、日本、瑞士等一些国家。

4.3 根DNS然后开始向下一级域名去寻找,比如这里就找到了com,然后一层层直到找到资源位置。当然也可能资源不存在。

4.4 DNS服务器找到这个资源对应的IP,这个最终的服务器被称为授权服务器,然后将这个IP转发给local DNS。

4.5 电脑在请求URL的时候,首先看本地DNS cache中是否有DNS映射缓存数据,然后看本地host是否有缓存数据,如果都没有才会请求local DNS服务器。

2016-08-09 15:36:43 darongzi1314 阅读数 1968
  • 实验 5:路由器密码恢复【此课时有资料下载】

    本课程从零开始系统性的演示了CCNA的实验操作,并且在实验操作的同时讲解CCNA对应的理论知识点,同时又不局限于大纲的要求,有些工作中比较重要的运用,比如三层交换机、HSRP、IPV6、MSTP等,即使超出大纲范围,也会...

    918人学习 晁海江
    免费试看

- (NSString *)getIPAddress:(NSString*)hostname{

    NSString* strIPAddress=@"";

    const char *hostN= [hostname UTF8String];

    struct hostent* phot;

    res_state res = malloc(sizeof(struct __res_state));

    int result = res_ninit(res);

    struct in_addr ip_addr;

    if (result == 0) {

        phot = gethostbyname(hostN);

    }

    if (phot != NULL){

        res_nclose(res);

        free(res);

        memcpy(&ip_addr, phot->h_addr_list[0], 4);

        char ip[20] = {0};

        inet_ntop(AF_INET, &ip_addr, ip, sizeof(ip));

        strIPAddress = [NSString stringWithUTF8String:ip];

        return strIPAddress;

    }else{

        return nil;

    }

}

NSString *ipaddress = [self getIPAddress:str3];

    if (ipaddress.length==0) {

        ipaddress=DNS_URL;//错误处理

    }


ios获取dns信息

阅读数 79

DNS解析过程详解

阅读数 792