dns工作过程及原理 (linux dns及android dan的实现差异)

前言

本文分析dns工作过程及原理,给一个简单的dns实现代码流程,并针对linux及android

下实现dns的不同,分别分析,供学习dns参考。

一、DNS功能

DNS(Domain Name System,域名系统),dns用于进行域名解析,说白了,就是给出一个

主机名,你给我找出该主机名对应的ip地址。例如:给你www.baidu.com的主机名,你给
我查出对应的ip地址:163.177.151.109。一些主机名还会有别名,如www.baidu.com就
有别名www.a.shifen.com,甚至不止一个别名,或一个别名有2个ip地址。在linux机子
上,运行nslookup(name service lookup)就是进行域名解析。如下面:

~$ nslookup www.baidu.com
Server:         127.0.0.1
Address:        127.0.0.1#53

Non-authoritative answer:
www.baidu.com   canonical name = www.a.shifen.com.
Name:   www.a.shifen.com
Address: 163.177.151.109
Name:   www.a.shifen.com
Address: 163.177.151.110

二、DNS的原理

上面介绍了dns的功能,那要实现dns的功能,dns需要做什么工作?主要就3点:1、记录dns

服务器的ip地址(请求进行域名解析的地方);2、向dns服务器请求进行域名解析(dns
实质工作),3、缓存已经解析过的主机名与ip地址对应关系(这样已缓存的就不需要再向
dns服务器请求解析了)。
一个dns的解析过程如下:
1、 应用程序请求一个主机名解析,如:应用程序跟dns说,我需要知道www.baidu.com
的ip地址,你给我查一下;
2、 Dns先在本地缓存中查询,若查到,返回ip地址给应用,流程结束。若没查到, 进行
下一步;
3、 Dns把需要查询的主机名打包进dns数据包,然后把dns数据包发送到dns服务;
4、 DNS服务器返回查询的主机名的dns数据包;
5、 Dns解析数据包,把主机名对应的ip地址返回给应用程序;
下图为网卡抓到的dns数据包的收发,请求www.baidu.com的ip地址:
这里写图片描述

下图为dns运行流程:
这里写图片描述
上面是从本机看到的情况,实际上在向DNS服务器请求时,所请求的DNS服务器也不一
定知道主机名对应的ip地址,就会向上一级DNS请求,更多资料请自行查找dns协议。

下面代码片段为freescale小系统上的dns处理过程,看起来流程还是比较清晰简单的:

wiced_result_t dns_client_hostname_lookup( const char* hostname, wiced_ip_address_t* address, uint32_t timeout_ms )
{
    /* 省略部分代码*/
     ...

    /* Create socket to send packets */
    if ( wiced_udp_create_socket( &socket, WICED_ANY_PORT, WICED_STA_INTERFACE ) != WICED_SUCCESS )
    {
        return WICED_ERROR;
    }

    while ( ipv4_address_found == WICED_FALSE && remaining_time > 0)
    {
        /* Send DNS query messages */
        for ( a = 0; a < dns_server_address_count; a++ )
        {
            wiced_ip_address_t host_ipv6_address;
            uint16_t           available_space;

            /* 创建dns数据包 */
            if ( wiced_packet_create_udp( &socket, (uint16_t) ( sizeof(dns_message_header_t) + sizeof(dns_question_t) + hostname_length ), &packet, (uint8_t**) &iter.header, &available_space ) != WICED_SUCCESS )
            {
                goto exit;
            }

            /* 省略部分代码*/
            ...

            /* 发送dns数据包 */
            if ( wiced_udp_send( &socket, &dns_server_address_array[a], DNS_PORT, packet ) != WICED_SUCCESS )
            {
                wiced_packet_delete( packet );
                goto exit;
            }

            /* 省略部分代码*/
            ...
        }

        /* Attempt to receive response packets */
        while ( ipv4_address_found == WICED_FALSE && remaining_time > 0 )
        {
            /* 省略部分代码*/
            ...

            /* 接收dns数据包 */
            if ( wiced_udp_receive( &socket, &packet, remaining_time ) == WICED_SUCCESS )
            {
                uint16_t     data_length;
                uint16_t     available_data_length;
                wiced_bool_t answer_found = WICED_FALSE;

                /* Extract the data */
                result = wiced_packet_get_data( packet, 0, (uint8_t**) &iter.header, &data_length, &available_data_length );
                if ( ( result != WICED_SUCCESS ) || ( data_length < sizeof(dns_message_header_t) ) )
                {
                    goto exit;
                }

                /* 解析dns数据包,解析出主机名的ip地址 */
                /* 省略部分代码*/
                ...

                wiced_packet_delete( packet );
            }

            /* 省略部分代码*/
            ...
        }
    }

exit:
    wiced_udp_delete_socket( &socket );

    /* 省略部分代码*/
    ...

    if ( ipv4_address_found == WICED_TRUE )
    {
        *address = resolved_ipv4_address;
        return WICED_SUCCESS;
    }

    /* 省略部分代码*/
    ...

    return WICED_ERROR;
}

三、Linux的dns实现

网上搜索Linux dns时,都是一些linux dns怎么配置的,配置host.conf,

resolv.conf文件,配置完后,重启一下network就好了,至于为什么配置这些文件,dns
又是在哪里执行的,都没有说明。
在Linux上执行nslookup(name service lookup)或ping(ping主机名,如:ping
www.baidu.com)都会执行dns的动作。执行dns时都是调用gethostbyname函数,
gethostbyname函数,传入主机名,dns执行成功后,返回主机名对应的ip地址。
而gethostbyname函数的实现是在c库中完成的,也就是dns的整个执行过程都是由c库实
现,c库中dns实现过程与上一节介绍的流程原理是相同的,只是还多了一些配置文件用于
设置参数、dns ip地址什么的,就是前面提到的host.conf,resolv.conf文件,这就是为什
么Linux的dns只需要配置host.conf,resolv.conf文件,不需要再做其它工作的原因,因为
c库已经替你完成dns的实际工作。在Linux嵌入式系统中,若发现dns不能正常工作,那就
看一下host.conf,resolv.conf等文件是否配置正确,还有就是dns运行使用的c库在机子上
有没有。
想了解c库怎么实现dns的,请自行下载c库源码分析:http://www.gnu.org/software/libc/

四、Android的dns实现

Android也是搭建在Linux之上,而在Android下就没见到host.conf,resolv.conf这

些文件,但Android的dns也是能正常工作的。这是因为Android重写了libc库的dns实现
部分,重写的dns代码在android\bionic\libc\dns目录。重写后的dns,请求dns的接口,
有gethostbyname(兼容以前的c库接口)及android_gethostbynamefornet(给
android使用)接口,但根据不同的dns请求发起者,走的流程有点不一样,其中还涉及到
了netd的处理。Android java层请求dns时,是通过netd进行,netd调用
android_gethostbynamefornet接口。而Android下编译的ping程序是不通过netd而直
接调用gethostbyname接口,但最终还是要走到netd,由netd调用
android_gethostbynamefornet接口。Android下dns的请求流程如下图:
这里写图片描述

gethostbyname_internal中判断是否为netd调用下来的依据是,

getenv(“ANDROID_DNS_MODE”)返回是否不为NULL并且值为“local”,而netd启动
时会设置setenv(“ANDROID_DNS_MODE”, “local”, 1),而ping程序不会。

五、Linux的dns缓存

Linux的dns,在配置resolv.conf文件的时候,第一个dns ip地址配置为nameserver 

127.0.0.1,也就是从本地dns缓存中查找,查找不到时再根据第二个、第三个dns ip地址
进行dns请求。

六、第三方dns库

有时候我们不想使用编译工具中libc自带的dns库,也可以移植第三

方的dns库,如c-ares dns库,该dns库支持多种平台。例如:linux
平台上,它与linux的配置完全兼容,可以在现有的linux dns配置文
件上,直接编译c-ares库放到机子上即可使用。

  • 5
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值