DNS Search Domain(搜索域)

前言

DNS应该很多人都比较了解,但是对于搜索域可能并不清楚其具体作用,本篇文章以Android T 为例,先介绍Search Domain的概念,然后介绍下安卓上的实现。

Search Domain简介

Search Domain是一项用于简化DNS解析的配置,其用途一般如下

  1. 简化域名输入
    当用户在浏览器中输入主机名而不是完全限定域名(FQDN: Fully qualified domain name)时,Search Domain可以帮助自动补全域名。
    例如,搜索域设置为public1.114dns.com,请求的域名为example时,系统会将其补全为example.public1.114dns.com
  2. 加速内部域名访问
    对于具有多个内部域名的企业网络,设置搜索域会使得内部域名访问更为容易。用户只需输入主机名,而无需输入完整的内部域名

搜索域的配置通常由DHCP完成,也可由用户手动设置。不同的系统和设备可能设置方式会有差异,但是目前常用的系统都会提供配置入口。

Search Domain技术细节

如下

  1. 搜索域配置
    可以指定一个或多个,配置方法略。
  2. 搜索过程
    当用户输入一个域名或主机名时,系统的DNS解析器会首先从DNS服务器请求。如果没有找到,系统会根据配置的搜索域开始搜索过程。
  3. 搜索域附加
    搜索过程依次尝试每个搜索域(搜索顺序依赖于我们配置的顺序),直到找到匹配的结果或者遍历完所有的搜索域。
  4. 结果缓存
    一般系统DNS的本地缓存时间都是以DNS response的TTL值为准。

Android T上的实现

具体的DNS请求流程不做详细介绍。
简单来说,是Client端发送DNS请求消息给netd进程中的dnsresolver模块,dnsresolver负责真正的请求。大体函数调用流程如下:
DnsProxyListener::GetAddrInfoHandler::run() -> resolv_getaddrinfo() -> explore_fqdn() -> dns_getaddrinfo() -> res_searchN()

res_searchN()

res_searchN() 通过 res_querydomainN() 方法发起DNS请求,主体代码如下

static int res_searchN(const char* name, res_target* target, ResState* res, int* herrno) {
	// ... ...
	int got_nodata = 0, got_servfail = 0, tried_as_is = 0;
	// ... ...
	if (dots >= res->ndots) {
	    ret = res_querydomainN(name, NULL, target, res, herrno);
	    if (ret > 0) return (ret);
	    saved_herrno = *herrno;
	    tried_as_is++;
	}
	
	if ((!dots || (dots && !trailing_dot)) && !isMdnsResolution(res->flags)) {
		for (const auto& domain : res->search_domains) {
	        ret = res_querydomainN(name, domain.c_str(), target, res, herrno);
	        if (ret > 0) return ret;
	    	// ... ...
	    }
	    // ... ...
	}

    if (!tried_as_is) {
        ret = res_querydomainN(name, NULL, target, res, herrno);
        if (ret > 0) return ret;
    }
// ... ...
}

res_searchN()方法可以分成3段"

  1. 判断hostname是否有.号,比如baidu.com或者www.baidu.com
    如果是,则先直接请求dns服务器;如果否或者失败那么会继续第2步
    注意,这里传递的第二个参数domains为null: res_querydomainN(name, NULL, target, res, herrno);
  2. 使用搜索域
    当然,这里不仅仅判断dot,如果是.local的mDNS,也不会使用搜索域。
    如果成功,直接返回,如果失败,继续第3步
  3. tried_as_is == 0
    使用原始输入再尝试一次。
    一般的话,如果我们输入www.baidu.com,第一步就能返回。如果网络不通并且设置了搜索域,在第一步失败后,还会继续执行第二步搜索过程。

res_querydomainN()

res_querydomainN的一些细节

static int res_querydomainN(const char* name, const char* domain, res_target* target, ResState* res,
                            int* herrno) {
    char nbuf[MAXDNAME];
    const char* longname = nbuf;
    size_t n, d;

    assert(name != NULL);

    if (domain == NULL) {
        // Check for trailing '.'; copy without '.' if present.
        n = strlen(name);
        if (n + 1 > sizeof(nbuf)) {
            *herrno = NO_RECOVERY;
            return -1;
        }
        if (n > 0 && name[--n] == '.') {
            strncpy(nbuf, name, n);
            nbuf[n] = '\0';
        } else
            longname = name;
    } else {
        n = strlen(name);
        d = strlen(domain);
        if (n + 1 + d + 1 > sizeof(nbuf)) {
            *herrno = NO_RECOVERY;
            return -1;
        }
        snprintf(nbuf, sizeof(nbuf), "%s.%s", name, domain);
    }
    return res_queryN_wrapper(longname, target, res, herrno);
}

当domian不为NULL时,将name和domain进行了拼接,最终Name是<name>.<domain>

总结

Andoroid的DNS有超时重试机制,可以dumpsys dnsresolver查看,默认是5s和2次。也就是5s超时,最大尝试2次

假如设置的DNS服务器为 114.114.114.114, Search Domain 为 public1.114dns.com, public2.114dns.com。
当DNS请求www.baidu.com时

  1. 首先向114.114.114.114发起DNS请求,name为 www.baidu.com。
    如果第一次请求超时,那么会继续尝试第二次;其他原因失败的话会直接返回。
  2. 搜索过程
    由于我们设置了两个搜索域,那么首先向114.114.114.114发起www.baidu.com.public1.114dns.com的DNS请求,如果两次尝试均失败;则继续发起www.baidu.com.public2.114dns.com的DNS请求

整体的耗时是什么样子的,最差情况下
dns_server_counts * timeout * retry_count + search_domain_counts * dns_server_counts * timeout * retry_count
= (1 + search_domain_counts) * dns_server_counts * timeout * retry_count
如果search_domain_counts=2,dns_server_counts=1,timeout=5s,retry_count=2,那么最差情况下的总耗时为 (1+2)25*2=60s.

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值