query.c

来自「非常好的dns解析软件」· C语言 代码 · 共 2,425 行 · 第 1/5 页

C
2,425
字号
	rdataset_base = additionalctx->rdataset;	client = additionalctx->client;	REQUIRE(NS_CLIENT_VALID(client));	eresult = ISC_R_SUCCESS;	fname = NULL;	rdataset = NULL;	sigrdataset = NULL;	db = NULL;	cdb = NULL;	version = NULL;	cversion = NULL;	node = NULL;	cnode = NULL;	added_something = ISC_FALSE;	need_addname = ISC_FALSE;	zone = NULL;	needadditionalcache = ISC_FALSE;	additionaltype = dns_rdatasetadditional_fromauth;	dns_name_init(&cfname, NULL);	CTRACE("query_addadditional2");	/*	 * We treat type A additional section processing as if it	 * were "any address type" additional section processing.	 * To avoid multiple lookups, we do an 'any' database	 * lookup and iterate over the node.	 * XXXJT: this approach can cause a suboptimal result when the cache	 * DB only has partial address types and the glue DB has remaining	 * ones.	 */	type = dns_rdatatype_any;	/*	 * Get some resources.	 */	dbuf = query_getnamebuf(client);	if (dbuf == NULL)		goto cleanup;	fname = query_newname(client, dbuf, &b);	if (fname == NULL)		goto cleanup;	dns_name_setbuffer(&cfname, &b); /* share the buffer */	/* Check additional cache */	result = dns_rdataset_getadditional(rdataset_base, additionaltype,					    type, client->view->acache, &zone,					    &cdb, &cversion, &cnode, &cfname,					    client->message, client->now);	if (result != ISC_R_SUCCESS)		goto findauthdb;	if (zone == NULL) {		CTRACE("query_addadditional2: auth zone not found");		goto try_cache;	}	/* Is the cached DB up-to-date? */	result = query_iscachevalid(zone, cdb, NULL, cversion);	if (result != ISC_R_SUCCESS) {		CTRACE("query_addadditional2: old auth additional cache");		query_discardcache(client, rdataset_base, additionaltype,				   type, &zone, &cdb, &cversion, &cnode,				   &cfname);		goto findauthdb;	}	if (cnode == NULL) {		/*		 * We have a negative cache.  We don't have to check the zone		 * ACL, since the result (not using this zone) would be same		 * regardless of the result.		 */		CTRACE("query_addadditional2: negative auth additional cache");		dns_db_closeversion(cdb, &cversion, ISC_FALSE);		dns_db_detach(&cdb);		dns_zone_detach(&zone);		goto try_cache;	}	result = query_validatezonedb(client, name, qtype, DNS_GETDB_NOLOG,				      zone, cdb, NULL);	if (result != ISC_R_SUCCESS) {		query_discardcache(client, rdataset_base, additionaltype,				   type, &zone, &cdb, &cversion, &cnode,				   &cfname);		goto try_cache;	}	/* We've got an active cache. */	CTRACE("query_addadditional2: auth additional cache");	dns_db_closeversion(cdb, &cversion, ISC_FALSE);	db = cdb;	node = cnode;	dns_name_clone(&cfname, fname);	query_keepname(client, fname, dbuf);	goto foundcache;	/*	 * Look for a zone database that might contain authoritative	 * additional data.	 */ findauthdb:	result = query_getzonedb(client, name, qtype, DNS_GETDB_NOLOG,				 &zone, &db, &version);	if (result != ISC_R_SUCCESS) {		/* Cache the negative result */		(void)dns_rdataset_setadditional(rdataset_base, additionaltype,						 type, client->view->acache,						 NULL, NULL, NULL, NULL,						 NULL);		goto try_cache;	}	CTRACE("query_addadditional2: db_find");	/*	 * Since we are looking for authoritative data, we do not set	 * the GLUEOK flag.  Glue will be looked for later, but not	 * necessarily in the same database.	 */	node = NULL;	result = dns_db_find(db, name, version, type, client->query.dboptions,			     client->now, &node, fname, NULL, NULL);	if (result == ISC_R_SUCCESS)		goto found;	/* Cache the negative result */	(void)dns_rdataset_setadditional(rdataset_base, additionaltype,					 type, client->view->acache, zone, db,					 version, NULL, fname);	if (node != NULL)		dns_db_detachnode(db, &node);	version = NULL;	dns_db_detach(&db);	/*	 * No authoritative data was found.  The cache is our next best bet.	 */ try_cache:	additionaltype = dns_rdatasetadditional_fromcache;	result = query_getcachedb(client, name, qtype, &db, DNS_GETDB_NOLOG);	if (result != ISC_R_SUCCESS)		/*		 * Most likely the client isn't allowed to query the cache.		 */		goto try_glue;	result = dns_db_find(db, name, version, type,			     client->query.dboptions | DNS_DBFIND_GLUEOK,			     client->now, &node, fname, NULL, NULL);	if (result == ISC_R_SUCCESS)		goto found;	if (node != NULL)		dns_db_detachnode(db, &node);	dns_db_detach(&db); try_glue:	/*	 * No cached data was found.  Glue is our last chance.	 * RFC1035 sayeth:	 *	 *	NS records cause both the usual additional section	 *	processing to locate a type A record, and, when used	 *	in a referral, a special search of the zone in which	 *	they reside for glue information.	 *	 * This is the "special search".  Note that we must search	 * the zone where the NS record resides, not the zone it	 * points to, and that we only do the search in the delegation	 * case (identified by client->query.gluedb being set).	 */	if (client->query.gluedb == NULL)		goto cleanup;	/*	 * Don't poision caches using the bailiwick protection model.	 */	if (!dns_name_issubdomain(name, dns_db_origin(client->query.gluedb)))		goto cleanup;	/* Check additional cache */	additionaltype = dns_rdatasetadditional_fromglue;	result = dns_rdataset_getadditional(rdataset_base, additionaltype,					    type, client->view->acache, NULL,					    &cdb, &cversion, &cnode, &cfname,					    client->message, client->now);	if (result != ISC_R_SUCCESS)		goto findglue;	result = query_iscachevalid(zone, cdb, client->query.gluedb, cversion);	if (result != ISC_R_SUCCESS) {		CTRACE("query_addadditional2: old glue additional cache");		query_discardcache(client, rdataset_base, additionaltype,				   type, &zone, &cdb, &cversion, &cnode,				   &cfname);		goto findglue;	}	if (cnode == NULL) {		/* We have a negative cache. */		CTRACE("query_addadditional2: negative glue additional cache");		dns_db_closeversion(cdb, &cversion, ISC_FALSE);		dns_db_detach(&cdb);		goto cleanup;	}	/* Cache hit. */	CTRACE("query_addadditional2: glue additional cache");	dns_db_closeversion(cdb, &cversion, ISC_FALSE);	db = cdb;	node = cnode;	dns_name_clone(&cfname, fname);	query_keepname(client, fname, dbuf);	goto foundcache; findglue:	dns_db_attach(client->query.gluedb, &db);	result = dns_db_find(db, name, version, type,			     client->query.dboptions | DNS_DBFIND_GLUEOK,			     client->now, &node, fname, NULL, NULL);	if (!(result == ISC_R_SUCCESS ||	      result == DNS_R_ZONECUT ||	      result == DNS_R_GLUE)) {		/* cache the negative result */		(void)dns_rdataset_setadditional(rdataset_base, additionaltype,						 type, client->view->acache,						 NULL, db, version, NULL,						 fname);		goto cleanup;	} found:	/*	 * We have found a DB node to iterate over from a DB.	 * We are going to look for address RRsets (i.e., A and AAAA) in the DB	 * node we've just found.  We'll then store the complete information	 * in the additional data cache.	 */	dns_name_clone(fname, &cfname);	query_keepname(client, fname, dbuf);	needadditionalcache = ISC_TRUE;	rdataset = query_newrdataset(client);	if (rdataset == NULL)		goto cleanup;	sigrdataset = query_newrdataset(client);	if (sigrdataset == NULL)		goto cleanup;	/*	 * Find A RRset with sig RRset.  Even if we don't find a sig RRset	 * for a client using DNSSEC, we'll continue the process to make a	 * complete list to be cached.  However, we need to cancel the	 * caching when something unexpected happens, in order to avoid	 * caching incomplete information.	 */	result = dns_db_findrdataset(db, node, version, dns_rdatatype_a, 0,				     client->now, rdataset, sigrdataset);	/*	 * If we can't promote glue/pending from the cache to secure	 * then drop it.	 */	if (result == ISC_R_SUCCESS &&	    additionaltype == dns_rdatasetadditional_fromcache &&	    (rdataset->trust == dns_trust_pending ||	     rdataset->trust == dns_trust_glue) &&	    !validate(client, db, fname, rdataset, sigrdataset)) {		dns_rdataset_disassociate(rdataset);		if (dns_rdataset_isassociated(sigrdataset))			dns_rdataset_disassociate(sigrdataset);		result = ISC_R_NOTFOUND;	}	if (result == DNS_R_NCACHENXDOMAIN)		goto setcache;	if (result == DNS_R_NCACHENXRRSET) {		dns_rdataset_disassociate(rdataset);		/*		 * Negative cache entries don't have sigrdatasets.		 */		INSIST(! dns_rdataset_isassociated(sigrdataset));	}	if (result == ISC_R_SUCCESS) {		/* Remember the result as a cache */		ISC_LIST_APPEND(cfname.list, rdataset, link);		if (dns_rdataset_isassociated(sigrdataset)) {			ISC_LIST_APPEND(cfname.list, sigrdataset, link);			sigrdataset = query_newrdataset(client);		}		rdataset = query_newrdataset(client);		if (sigrdataset == NULL || rdataset == NULL) {			/* do not cache incomplete information */			goto foundcache;		}	}	/* Find AAAA RRset with sig RRset */	result = dns_db_findrdataset(db, node, version, dns_rdatatype_aaaa,				     0, client->now, rdataset, sigrdataset);	/*	 * If we can't promote glue/pending from the cache to secure	 * then drop it.	 */	if (result == ISC_R_SUCCESS &&	    additionaltype == dns_rdatasetadditional_fromcache &&	    (rdataset->trust == dns_trust_pending ||	     rdataset->trust == dns_trust_glue) &&	    !validate(client, db, fname, rdataset, sigrdataset)) {		dns_rdataset_disassociate(rdataset);		if (dns_rdataset_isassociated(sigrdataset))			dns_rdataset_disassociate(sigrdataset);		result = ISC_R_NOTFOUND;	}	if (result == ISC_R_SUCCESS) {		ISC_LIST_APPEND(cfname.list, rdataset, link);		rdataset = NULL;		if (dns_rdataset_isassociated(sigrdataset)) {			ISC_LIST_APPEND(cfname.list, sigrdataset, link);			sigrdataset = NULL;		}	} setcache:	/*	 * Set the new result in the cache if required.  We do not support	 * caching additional data from a cache DB.	 */	if (needadditionalcache == ISC_TRUE &&	    (additionaltype == dns_rdatasetadditional_fromauth ||	     additionaltype == dns_rdatasetadditional_fromglue)) {		(void)dns_rdataset_setadditional(rdataset_base, additionaltype,						 type, client->view->acache,						 zone, db, version, node,						 &cfname);	} foundcache:	need_sigrrset = ISC_FALSE;	mname0 = NULL;	for (crdataset = ISC_LIST_HEAD(cfname.list);	     crdataset != NULL;	     crdataset = crdataset_next) {		dns_name_t *mname;		crdataset_next = ISC_LIST_NEXT(crdataset, link);		mname = NULL;		if (crdataset->type == dns_rdatatype_a ||		    crdataset->type == dns_rdatatype_aaaa) {			if (!query_isduplicate(client, fname, crdataset->type,					       &mname)) {				if (mname != NULL) {					/*					 * A different type of this name is					 * already stored in the additional					 * section.  We'll reuse the name.					 * Note that this should happen at most					 * once.  Otherwise, fname->link could					 * leak below.					 */					INSIST(mname0 == NULL);					query_releasename(client, &fname);					fname = mname;					mname0 = mname;				} else					need_addname = ISC_TRUE;				ISC_LIST_UNLINK(cfname.list, crdataset, link);				ISC_LIST_APPEND(fname->list, crdataset, link);				added_something = ISC_TRUE;				need_sigrrset = ISC_TRUE;			} else				need_sigrrset = ISC_FALSE;		} else if (crdataset->type == dns_rdatatype_rrsig &&			   need_sigrrset && WANTDNSSEC(client)) {			ISC_LIST_UNLINK(cfname.list, crdataset, link);			ISC_LIST_APPEND(fname->list, crdataset, link);			added_something = ISC_TRUE; /* just in case */			need_sigrrset = ISC_FALSE;		}	}	CTRACE("query_addadditional2: addname");	/*	 * If we haven't added anything, then we're done.	 */	if (!added_something)		goto cleanup;	/*	 * We may have added our rdatasets to an existing name, if so, then	 * need_addname will be ISC_FALSE.  Whether we used an existing name	 * or a new one, we must set fname to NULL to prevent cleanup.	 */	if (need_addname)		dns_message_addname(client->message, fname,				    DNS_SECTION_ADDITIONAL);	fname = NULL; cleanup:	CTRACE("query_addadditional2: cleanup");	if (rdataset != NULL)		query_putrdataset(client, &rdataset);	if (sigrdataset != NULL)		query_putrdataset(client, &sigrdataset);	while  ((crdataset = ISC_LIST_HEAD(cfname.list)) != NULL) {		ISC_LIST_UNLINK(cfname.list, crdataset, link);		query_putrdataset(client, &crdataset);	}	if (fname != NULL)		query_releasename(client, &fname);	if (node != NULL)		dns_db_detachnode(db, &node);	if (db != NULL)		dns_db_detach(&db);	if (zone != NULL)		dns_zone_detach(&zone);	CTRACE("query_addadditional2: done");	return (eresult);}static inline voidquery_addrdataset(ns_client_t *client, dns_name_t *fname,		  dns_rdataset_t *rdataset){	client_additionalctx_t additionalctx;	/*	 * Add 'rdataset' and any pertinent additional data to	 * 'fname', a name in the response message for 'client'.	 */	CTRACE("query_addrdataset");	ISC_LIST_APPEND(fname->list, rdataset, link);	if (client->view->order != NULL)		rdataset->attributes |= dns_order_find(client->view->order,						       fname, rdataset->type,						       rdataset->rdclass);	rdataset->attributes |= DNS_RDATASETATTR_LOADORDER;	if (NOADDITIONAL(client))		return;	/*	 * Add additional data.	 *	 * We don't care if dns_rdataset_additionaldata() fails.	 */	additionalctx.client = client;	additionalctx.rdataset = rdataset;	(void)dns_rdataset_additionaldata(rdataset, query_addadditional2,					  &additionalctx);	CTRACE("query_addrdataset: done");}static voidquery_addrrset(ns_client_t *client, dns_name_t **namep,	       dns_rdataset_t **rdatasetp, dns_rdataset_t **sigrdatasetp,	       isc_buffer_t *dbuf, dns_section_t section){	dns_name_t *name, *mname;	dns_rdataset_t *rdataset, *mrdataset, *sigrdataset;	isc_result_t result;	/*%	 * To the current response for 'client', add the answer RRset	 * '*rdatasetp' and an optional signature set '*sigrdatasetp', with	 * owner name '*namep', to section 'section', unless they are	 * already there.  Also add any pertinent additional data.	 *	 * If 'dbuf' is not NULL, then '*namep' is the name whose data is	 * stored in 'dbuf'.  In this case, query_addrrset() guarantees that	 * when it returns the name will either have been kept or released.	 */	CTRACE("query_addrrset");	name = *namep;	rdataset = *rdatasetp;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?