bind 9.16 回根查询流程(非本地权威查询,无本地cache缓存,须回根的完整查询)

1。 从网卡受到数据,进入task事件处理的业务入口函数:ns__client_request

2。 -》调用ns_query_start(client, handle); 目前查询请求只允许一个,多个直接返回错误

	/*
	 * Get the question name.
	 */
	result = dns_message_firstname(message, DNS_SECTION_QUESTION);
	if (result != ISC_R_SUCCESS) {
		query_error(client, result, __LINE__);
		return;
	}
	dns_message_currentname(message, DNS_SECTION_QUESTION,
				&client->query.qname);
	client->query.origqname = client->query.qname;
	result = dns_message_nextname(message, DNS_SECTION_QUESTION);
	if (result != ISC_R_NOMORE) {
		if (result == ISC_R_SUCCESS) {
			/*
			 * There's more than one QNAME in the question
			 * section.
			 */
			query_error(client, DNS_R_FORMERR, __LINE__);
		} else {
			query_error(client, result, __LINE__);
		}
		return;
	}

3。 经过一系列的初始化,调用到(void)query_setup(client, qtype);

	/*
	 * Check SERVFAIL cache
	 */
	result = ns__query_sfcache(&qctx);
	if (result != ISC_R_COMPLETE) {
		qctx_destroy(&qctx);
		return (result);
	}

如上是querysetup部分的代码,考虑为负向缓存部分

继续执行,则会调用

4。 result = ns__query_start(&qctx);,此部分以后将使用qctx进行,qctx是query_setup的一个临时结构,则在此函数下的所有堆栈均使用此临时结构

	/*
	 * If we require a server cookie then send back BADCOOKIE
	 * before we have done too much work.
	 */
	if (!TCP(qctx->client) && qctx->view->requireservercookie &&
	    WANTCOOKIE(qctx->client) && !HAVECOOKIE(qctx->client))
	{
		qctx->client->message->flags &= ~DNS_MESSAGEFLAG_AA;
		qctx->client->message->flags &= ~DNS_MESSAGEFLAG_AD;
		qctx->client->message->rcode = dns_rcode_badcookie;
		return (ns_query_done(qctx));
	}

	if (qctx->view->checknames &&
	    !dns_rdata_checkowner(qctx->client->query.qname,
				  qctx->client->message->rdclass, qctx->qtype,
				  false))

初步对查询请求进行合法验证,是否携带cokie,查询域名是否合法

查找可以使用的db,是本地权威?还是缓存?将查询db赋值给本qctx,同时职位is_zone,来标记是本地权威还是本地缓存

	result = query_getdb(qctx->client, qctx->client->query.qname,
			     qctx->qtype, qctx->options, &qctx->zone, &qctx->db,
			     &qctx->version, &qctx->is_zone);

 

5。 调用函数result = query_lookup(qctx);,进入下一步的查询

	result = dns_db_findext(qctx->db, rpzqname, qctx->version, qctx->type,
				dboptions, qctx->client->now, &qctx->node,
				qctx->fname, &cm, &ci, qctx->rdataset,
				qctx->sigrdataset);

在如上代码中,进行本查询域名的定位查找,此处可能是本地缓存数据库,也可能是cache数据库,或这查到具体的rdataset或者查询到所归属的domail region

如上函数调用的下一级内容是:就是具体的查询算法

tatic isc_result_t
cache_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version,
	   dns_rdatatype_t type, unsigned int options, isc_stdtime_t now,
	   dns_dbnode_t **nodep, dns_name_t *foundname,
	   dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset) {

 

6。 在如上函数中查找完毕db后,会进入到如下函数处理

result = query_gotanswer(qctx, result);

	switch (result) {
	case ISC_R_SUCCESS:
		return (query_prepresponse(qctx));
	case DNS_R_GLUE:
	case DNS_R_ZONECUT:
		INSIST(qctx->is_zone);
		qctx->authoritative = false;
		return (query_prepresponse(qctx));
	case ISC_R_NOTFOUND:
		return (query_notfound(qctx));

当本种dns查询时,result是notfound情况,所以下一步进入query_notfound,本函数无后续处理,直接返回堆栈

7。 如上进入query_notfound(query_ctx_t *qctx) ,因为初次查询,还没有查询国root,所以

	if (qctx->view->hints != NULL) {
		dns_clientinfomethods_t cm;
		dns_clientinfo_t ci;
		dns_clientinfomethods_init(&cm, ns_client_sourceip);
		dns_clientinfo_init(&ci, qctx->client, NULL);
		dns_db_attach(qctx->view->hints, &qctx->db);
		result = dns_db_findext(qctx->db, dns_rootname, NULL,
					dns_rdatatype_ns, 0, qctx->client->now,
					&qctx->node, qctx->fname, &cm, &ci,
					qctx->rdataset, qctx->sigrdataset);

如上qctx->view->hints is NULL,会再次查询db,将root的ns查询出来,若无错误,则直接进入根代理查询

return (query_delegation(qctx));

8。 query_delegation(query_ctx_t *qctx) 代理查询,经过一系列查询,将进入代理递归流程

	result = query_delegation_recurse(qctx);

在经过层层判断,会运行到如下代码:

	} else {
		/*
		 * Any other recursion.
		 */
		result = ns_query_recurse(qctx->client, qctx->qtype, qname,
					  qctx->fname, qctx->rdataset,
					  qctx->resuming);

如上就是查询递归

9。 isc_result_t

ns_query_recurse(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qname,

dns_name_t *qdomain, dns_rdataset_t *nameservers,

bool resuming) 就是递归查询

此部分就是开始执行向下层数据发出层进行调度

最终是运行到代码

	result = dns_resolver_createfetch(
		client->view->resolver, qname, qtype, qdomain, nameservers,
		NULL, peeraddr, client->message->id, client->query.fetchoptions,
		0, NULL, client->task, fetch_callback, client, rdataset,
		sigrdataset, &client->query.fetch);

本函数后面之后一场判断,清理堆栈内存残留,其余直接返回调用堆栈

到目前为之一直都是一次时间驱动,从始到现在都是函数堆栈

10。 进入函数

isc_result_t
dns_resolver_createfetch(dns_resolver_t *res, const dns_name_t *name,
			 dns_rdatatype_t type, const dns_name_t *domain,
			 dns_rdataset_t *nameservers,
			 dns_forwarders_t *forwarders,
			 const isc_sockaddr_t *client, dns_messageid_t id,
			 unsigned int options, unsigned int depth,
			 isc_counter_t *qc, isc_task_t *task,
			 isc_taskaction_t action, void *arg,
			 dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
			 dns_fetch_t **fetchp) {

本函数是时间驱动的创建函数,不管udp还是tcp都需要异步进行

因为是初次查询,所以进入到如下处理部分

	if (new_fctx) {
		if (result == ISC_R_SUCCESS) {
			/*
			 * Launch this fctx.
			 */
			event = &fctx->control_event;
			ISC_EVENT_INIT(event, sizeof(*event), 0, NULL,
				       DNS_EVENT_FETCHCONTROL, fctx_start, fctx,
				       NULL, NULL, NULL);
			isc_task_send(res->buckets[bucketnum].task, &event);
		} else {

如上是新建一个事件,开始执行,事件的执行函数是fctx_start,进行处理

然后再发送到通信事件部分处理

			isc_task_send(res->buckets[bucketnum].task, &event);

如上是整个业务流程,下面会在另一篇文章中进行解析通信部分的处理,也就是下一个事件

 

 

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值