query.c

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

C
2,425
字号
	     section++) {		result = dns_message_findname(client->message, section,					      name, type, 0, &mname, NULL);		if (result == ISC_R_SUCCESS) {			/*			 * We've already got this RRset in the response.			 */			CTRACE("query_isduplicate: true: done");			return (ISC_TRUE);		} else if (result == DNS_R_NXRRSET) {			/*			 * The name exists, but the rdataset does not.			 */			if (section == DNS_SECTION_ADDITIONAL)				break;		} else			RUNTIME_CHECK(result == DNS_R_NXDOMAIN);		mname = NULL;	}	/*	 * If the dns_name_t we're looking up is already in the message,	 * we don't want to trigger the caller's name replacement logic.	 */	if (name == mname)		mname = NULL;	*mnamep = mname;	CTRACE("query_isduplicate: false: done");	return (ISC_FALSE);}static isc_result_tquery_addadditional(void *arg, dns_name_t *name, dns_rdatatype_t qtype) {	ns_client_t *client = arg;	isc_result_t result, eresult;	dns_dbnode_t *node;	dns_db_t *db;	dns_name_t *fname, *mname;	dns_rdataset_t *rdataset, *sigrdataset, *trdataset;	isc_buffer_t *dbuf;	isc_buffer_t b;	dns_dbversion_t *version;	isc_boolean_t added_something, need_addname;	dns_zone_t *zone;	dns_rdatatype_t type;	REQUIRE(NS_CLIENT_VALID(client));	REQUIRE(qtype != dns_rdatatype_any);	if (!WANTDNSSEC(client) && dns_rdatatype_isdnssec(qtype))		return (ISC_R_SUCCESS);	CTRACE("query_addadditional");	/*	 * Initialization.	 */	eresult = ISC_R_SUCCESS;	fname = NULL;	rdataset = NULL;	sigrdataset = NULL;	trdataset = NULL;	db = NULL;	version = NULL;	node = NULL;	added_something = ISC_FALSE;	need_addname = ISC_FALSE;	zone = NULL;	/*	 * 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.	 */	if (qtype == dns_rdatatype_a)		type = dns_rdatatype_any;	else		type = qtype;	/*	 * Get some resources.	 */	dbuf = query_getnamebuf(client);	if (dbuf == NULL)		goto cleanup;	fname = query_newname(client, dbuf, &b);	rdataset = query_newrdataset(client);	if (fname == NULL || rdataset == NULL)		goto cleanup;	if (WANTDNSSEC(client)) {		sigrdataset = query_newrdataset(client);		if (sigrdataset == NULL)			goto cleanup;	}	/*	 * Look for a zone database that might contain authoritative	 * additional data.	 */	result = query_getzonedb(client, name, qtype, DNS_GETDB_NOLOG,				 &zone, &db, &version);	if (result != ISC_R_SUCCESS)		goto try_cache;	CTRACE("query_addadditional: 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, rdataset,			     sigrdataset);	if (result == ISC_R_SUCCESS)		goto found;	if (dns_rdataset_isassociated(rdataset))		dns_rdataset_disassociate(rdataset);	if (sigrdataset != NULL && dns_rdataset_isassociated(sigrdataset))		dns_rdataset_disassociate(sigrdataset);	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:	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;	/*	 * Attempt to validate glue.	 */	if (sigrdataset == NULL) {		sigrdataset = query_newrdataset(client);		if (sigrdataset == NULL)			goto cleanup;	}	result = dns_db_find(db, name, version, type,			     client->query.dboptions | DNS_DBFIND_GLUEOK,			     client->now, &node, fname, rdataset,			     sigrdataset);	if (result == DNS_R_GLUE &&	    validate(client, db, fname, rdataset, sigrdataset))		result = ISC_R_SUCCESS;	if (!WANTDNSSEC(client))		query_putrdataset(client, &sigrdataset);	if (result == ISC_R_SUCCESS)		goto found;	if (dns_rdataset_isassociated(rdataset))		dns_rdataset_disassociate(rdataset);	if (sigrdataset != NULL && dns_rdataset_isassociated(sigrdataset))		dns_rdataset_disassociate(sigrdataset);	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;	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, rdataset,			     sigrdataset);	if (!(result == ISC_R_SUCCESS ||	      result == DNS_R_ZONECUT ||	      result == DNS_R_GLUE))		goto cleanup; found:	/*	 * We have found a potential additional data rdataset, or	 * at least a node to iterate over.	 */	query_keepname(client, fname, dbuf);	/*	 * If we have an rdataset, add it to the additional data	 * section.	 */	mname = NULL;	if (dns_rdataset_isassociated(rdataset) &&	    !query_isduplicate(client, fname, type, &mname)) {		if (mname != NULL) {			query_releasename(client, &fname);			fname = mname;		} else			need_addname = ISC_TRUE;		ISC_LIST_APPEND(fname->list, rdataset, link);		trdataset = rdataset;		rdataset = NULL;		added_something = ISC_TRUE;		/*		 * Note: we only add SIGs if we've added the type they cover,		 * so we do not need to check if the SIG rdataset is already		 * in the response.		 */		if (sigrdataset != NULL &&		    dns_rdataset_isassociated(sigrdataset))		{			ISC_LIST_APPEND(fname->list, sigrdataset, link);			sigrdataset = NULL;		}	}	if (qtype == dns_rdatatype_a) {		/*		 * We now go looking for A and AAAA records, along with		 * their signatures.		 *		 * XXXRTH  This code could be more efficient.		 */		if (rdataset != NULL) {			if (dns_rdataset_isassociated(rdataset))				dns_rdataset_disassociate(rdataset);		} else {			rdataset = query_newrdataset(client);			if (rdataset == NULL)				goto addname;		}		if (sigrdataset != NULL) {			if (dns_rdataset_isassociated(sigrdataset))				dns_rdataset_disassociate(sigrdataset);		} else if (WANTDNSSEC(client)) {			sigrdataset = query_newrdataset(client);			if (sigrdataset == NULL)				goto addname;		}		result = dns_db_findrdataset(db, node, version,					     dns_rdatatype_a, 0,					     client->now, rdataset,					     sigrdataset);		if (result == DNS_R_NCACHENXDOMAIN)			goto addname;		if (result == DNS_R_NCACHENXRRSET) {			dns_rdataset_disassociate(rdataset);			/*			 * Negative cache entries don't have sigrdatasets.			 */			INSIST(sigrdataset == NULL ||			       ! dns_rdataset_isassociated(sigrdataset));		}		if (result == ISC_R_SUCCESS) {			mname = NULL;			if (!query_isduplicate(client, fname,					       dns_rdatatype_a, &mname)) {				if (mname != NULL) {					query_releasename(client, &fname);					fname = mname;				} else					need_addname = ISC_TRUE;				ISC_LIST_APPEND(fname->list, rdataset, link);				added_something = ISC_TRUE;				if (sigrdataset != NULL &&				    dns_rdataset_isassociated(sigrdataset))				{					ISC_LIST_APPEND(fname->list,							sigrdataset, link);					sigrdataset =						query_newrdataset(client);				}				rdataset = query_newrdataset(client);				if (rdataset == NULL)					goto addname;				if (WANTDNSSEC(client) && sigrdataset == NULL)					goto addname;			} else {				dns_rdataset_disassociate(rdataset);				if (sigrdataset != NULL &&				    dns_rdataset_isassociated(sigrdataset))					dns_rdataset_disassociate(sigrdataset);			}		}		result = dns_db_findrdataset(db, node, version,					     dns_rdatatype_aaaa, 0,					     client->now, rdataset,					     sigrdataset);		if (result == DNS_R_NCACHENXDOMAIN)			goto addname;		if (result == DNS_R_NCACHENXRRSET) {			dns_rdataset_disassociate(rdataset);			INSIST(sigrdataset == NULL ||			       ! dns_rdataset_isassociated(sigrdataset));		}		if (result == ISC_R_SUCCESS) {			mname = NULL;			if (!query_isduplicate(client, fname,					       dns_rdatatype_aaaa, &mname)) {				if (mname != NULL) {					query_releasename(client, &fname);					fname = mname;				} else					need_addname = ISC_TRUE;				ISC_LIST_APPEND(fname->list, rdataset, link);				added_something = ISC_TRUE;				if (sigrdataset != NULL &&				    dns_rdataset_isassociated(sigrdataset))				{					ISC_LIST_APPEND(fname->list,							sigrdataset, link);					sigrdataset = NULL;				}				rdataset = NULL;			}		}	} addname:	CTRACE("query_addadditional: 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;	/*	 * In a few cases, we want to add additional data for additional	 * data.  It's simpler to just deal with special cases here than	 * to try to create a general purpose mechanism and allow the	 * rdata implementations to do it themselves.	 *	 * This involves recursion, but the depth is limited.  The	 * most complex case is adding a SRV rdataset, which involves	 * recursing to add address records, which in turn can cause	 * recursion to add KEYs.	 */	if (type == dns_rdatatype_srv && trdataset != NULL) {		/*		 * If we're adding SRV records to the additional data		 * section, it's helpful if we add the SRV additional data		 * as well.		 */		eresult = dns_rdataset_additionaldata(trdataset,						      query_addadditional,						      client);	} cleanup:	CTRACE("query_addadditional: cleanup");	query_putrdataset(client, &rdataset);	if (sigrdataset != NULL)		query_putrdataset(client, &sigrdataset);	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_addadditional: done");	return (eresult);}static inline voidquery_discardcache(ns_client_t *client, dns_rdataset_t *rdataset_base,		   dns_rdatasetadditional_t additionaltype,		   dns_rdatatype_t type, dns_zone_t **zonep, dns_db_t **dbp,		   dns_dbversion_t **versionp, dns_dbnode_t **nodep,		   dns_name_t *fname){	dns_rdataset_t *rdataset;	while  ((rdataset = ISC_LIST_HEAD(fname->list)) != NULL) {		ISC_LIST_UNLINK(fname->list, rdataset, link);		query_putrdataset(client, &rdataset);	}	if (*versionp != NULL)		dns_db_closeversion(*dbp, versionp, ISC_FALSE);	if (*nodep != NULL)		dns_db_detachnode(*dbp, nodep);	if (*dbp != NULL)		dns_db_detach(dbp);	if (*zonep != NULL)		dns_zone_detach(zonep);	(void)dns_rdataset_putadditional(client->view->acache, rdataset_base,					 additionaltype, type);}static inline isc_result_tquery_iscachevalid(dns_zone_t *zone, dns_db_t *db, dns_db_t *db0,		   dns_dbversion_t *version){	isc_result_t result = ISC_R_SUCCESS;	dns_dbversion_t *version_current = NULL;	dns_db_t *db_current = db0;	if (db_current == NULL) {		result = dns_zone_getdb(zone, &db_current);		if (result != ISC_R_SUCCESS)			return (result);	}	dns_db_currentversion(db_current, &version_current);	if (db_current != db || version_current != version) {		result = ISC_R_FAILURE;		goto cleanup;	} cleanup:	dns_db_closeversion(db_current, &version_current, ISC_FALSE);	if (db0 == NULL && db_current != NULL)		dns_db_detach(&db_current);	return (result);}static isc_result_tquery_addadditional2(void *arg, dns_name_t *name, dns_rdatatype_t qtype) {	client_additionalctx_t *additionalctx = arg;	dns_rdataset_t *rdataset_base;	ns_client_t *client;	isc_result_t result, eresult;	dns_dbnode_t *node, *cnode;	dns_db_t *db, *cdb;	dns_name_t *fname, *mname0, cfname;	dns_rdataset_t *rdataset, *sigrdataset;	dns_rdataset_t *crdataset, *crdataset_next;	isc_buffer_t *dbuf;	isc_buffer_t b;	dns_dbversion_t *version, *cversion;	isc_boolean_t added_something, need_addname, needadditionalcache;	isc_boolean_t need_sigrrset;	dns_zone_t *zone;	dns_rdatatype_t type;	dns_rdatasetadditional_t additionaltype;	if (qtype != dns_rdatatype_a) {		/*		 * This function is optimized for "address" types.  For other		 * types, use a generic routine.		 * XXX: ideally, this function should be generic enough.		 */		return (query_addadditional(additionalctx->client,					    name, qtype));	}	/*	 * Initialization.	 */

⌨️ 快捷键说明

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