lib/dns/validator.c
/*%
 * Looks for the requested name and type in the view (zones and cache).
 *
 * When looking for a DLV record also checks to make sure the NSEC record
 * returns covers the query name as part of aggressive negative caching.
 *
 * Returns:
 * \li	ISC_R_SUCCESS
 * \li	ISC_R_NOTFOUND
 * \li	DNS_R_NCACHENXDOMAIN
 * \li	DNS_R_NCACHENXRRSET
 * \li	DNS_R_NXRRSET
 * \li	DNS_R_NXDOMAIN
 * \li	DNS_R_BROKENCHAIN
 */
%
Looks for the requested name and type in the view (zones and cache).

When looking for a DLV record also checks to make sure the NSEC record
returns covers the query name as part of aggressive negative caching.


% Looks for the requested name and type in the view ( zones and cache ) . When looking for a DLV record also checks to make sure the NSEC record returns covers the query name as part of aggressive negative caching .
static inline isc_result_t
view_find(dns_validator_t *val, dns_name_t *name, dns_rdatatype_t type) {
	dns_fixedname_t fixedname;
	dns_name_t *foundname;
	dns_rdata_nsec_t nsec;
	dns_rdata_t rdata = DNS_RDATA_INIT;
	isc_result_t result;
	unsigned int options;
	isc_time_t now;
	char buf1[DNS_NAME_FORMATSIZE];
	char buf2[DNS_NAME_FORMATSIZE];
	char buf3[DNS_NAME_FORMATSIZE];
	char namebuf[DNS_NAME_FORMATSIZE];
	char typebuf[DNS_RDATATYPE_FORMATSIZE];
	if (dns_rdataset_isassociated(&val->frdataset))
		dns_rdataset_disassociate(&val->frdataset);
	if (dns_rdataset_isassociated(&val->fsigrdataset))
		dns_rdataset_disassociate(&val->fsigrdataset);
	if (val->view->zonetable == NULL)
		return (ISC_R_CANCELED);
	if (isc_time_now(&now) == ISC_R_SUCCESS &&
	    dns_resolver_getbadcache(val->view->resolver, name, type, &now)) {
		dns_name_format(name, namebuf, sizeof(namebuf));
		dns_rdatatype_format(type, typebuf, sizeof(typebuf));
		validator_log(val, ISC_LOG_INFO, "bad cache hit (%s/%s)",
			      namebuf, typebuf);
		return (DNS_R_BROKENCHAIN);
	}
	options = DNS_DBFIND_PENDINGOK;
	if (type == dns_rdatatype_dlv)
		options |= DNS_DBFIND_COVERINGNSEC;
	dns_fixedname_init(&fixedname);
	foundname = dns_fixedname_name(&fixedname);
	result = dns_view_find(val->view, name, type, 0, options,
			       ISC_FALSE, NULL, NULL, foundname,
			       &val->frdataset, &val->fsigrdataset);
	if (result == DNS_R_NXDOMAIN) {
		if (dns_rdataset_isassociated(&val->frdataset))
			dns_rdataset_disassociate(&val->frdataset);
		if (dns_rdataset_isassociated(&val->fsigrdataset))
			dns_rdataset_disassociate(&val->fsigrdataset);
	} else if (result == DNS_R_COVERINGNSEC) {
		validator_log(val, ISC_LOG_DEBUG(3), "DNS_R_COVERINGNSEC");
		INSIST(type == dns_rdatatype_dlv);
		if (val->frdataset.trust != dns_trust_secure) {
			validator_log(val, ISC_LOG_DEBUG(3),
				      "covering nsec: trust %s",
				      dns_trust_totext(val->frdataset.trust));
			goto notfound;
		}
		result = dns_rdataset_first(&val->frdataset);
		if (result != ISC_R_SUCCESS)
			goto notfound;
		dns_rdataset_current(&val->frdataset, &rdata);
		if (dns_nsec_typepresent(&rdata, dns_rdatatype_ns) &&
		    !dns_nsec_typepresent(&rdata, dns_rdatatype_soa)) {
			if (dns_name_issubdomain(name, foundname)) {
				validator_log(val, ISC_LOG_DEBUG(3),
					      "covering nsec: for parent");
				goto notfound;
			}
		}
		result = dns_rdata_tostruct(&rdata, &nsec, NULL);
		if (result != ISC_R_SUCCESS)
			goto notfound;
		if (dns_name_compare(foundname, &nsec.next) >= 0) {
			if (!dns_name_issubdomain(name, &nsec.next)) {
				dns_rdata_freestruct(&nsec);
				validator_log(val, ISC_LOG_DEBUG(3),
					      "covering nsec: not in zone");
				goto notfound;
			}
		} else if (dns_name_compare(name, &nsec.next) >= 0) {
			dns_rdata_freestruct(&nsec);
			validator_log(val, ISC_LOG_DEBUG(3),
				      "covering nsec: not in range");
			goto notfound;
		}
		if (isc_log_wouldlog(dns_lctx,ISC_LOG_DEBUG(3))) {
			dns_name_format(name, buf1, sizeof buf1);
			dns_name_format(foundname, buf2, sizeof buf2);
			dns_name_format(&nsec.next, buf3, sizeof buf3);
			validator_log(val, ISC_LOG_DEBUG(3),
				      "covering nsec found: '%s' '%s' '%s'",
				      buf1, buf2, buf3);
		}
		if (dns_rdataset_isassociated(&val->frdataset))
			dns_rdataset_disassociate(&val->frdataset);
		if (dns_rdataset_isassociated(&val->fsigrdataset))
			dns_rdataset_disassociate(&val->fsigrdataset);
		dns_rdata_freestruct(&nsec);
		result = DNS_R_NCACHENXDOMAIN;
	} else if (result != ISC_R_SUCCESS &&
		   result != DNS_R_NCACHENXDOMAIN &&
		   result != DNS_R_NCACHENXRRSET &&
		   result != DNS_R_EMPTYNAME &&
		   result != DNS_R_NXRRSET &&
		   result != ISC_R_NOTFOUND) {
		goto  notfound;
	}
	return (result);
 notfound:
	if (dns_rdataset_isassociated(&val->frdataset))
		dns_rdataset_disassociate(&val->frdataset);
	if (dns_rdataset_isassociated(&val->fsigrdataset))
		dns_rdataset_disassociate(&val->fsigrdataset);
	return (ISC_R_NOTFOUND);
}
static inline isc_result_t view_find ( dns_validator_t * val , dns_name_t * name , dns_rdatatype_t type ) { dns_fixedname_t fixedname ; dns_name_t * foundname ; dns_rdata_nsec_t nsec ; dns_rdata_t rdata = DNS_RDATA_INIT ; isc_result_t result ; unsigned int options ; isc_time_t now ; char buf1 [ DNS_NAME_FORMATSIZE ] ; char buf2 [ DNS_NAME_FORMATSIZE ] ; char buf3 [ DNS_NAME_FORMATSIZE ] ; char namebuf [ DNS_NAME_FORMATSIZE ] ; char typebuf [ DNS_RDATATYPE_FORMATSIZE ] ; if ( dns_rdataset_isassociated ( & val -> frdataset ) ) dns_rdataset_disassociate ( & val -> frdataset ) ; if ( dns_rdataset_isassociated ( & val -> fsigrdataset ) ) dns_rdataset_disassociate ( & val -> fsigrdataset ) ; if ( val -> view -> zonetable == NULL ) return ( ISC_R_CANCELED ) ; if ( isc_time_now ( & now ) == ISC_R_SUCCESS && dns_resolver_getbadcache ( val -> view -> resolver , name , type , & now ) ) { dns_name_format ( name , namebuf , sizeof ( namebuf ) ) ; dns_rdatatype_format ( type , typebuf , sizeof ( typebuf ) ) ; validator_log ( val , ISC_LOG_INFO , " " , namebuf , typebuf ) ; return ( DNS_R_BROKENCHAIN ) ; } options = DNS_DBFIND_PENDINGOK ; if ( type == dns_rdatatype_dlv ) options |= DNS_DBFIND_COVERINGNSEC ; dns_fixedname_init ( & fixedname ) ; foundname = dns_fixedname_name ( & fixedname ) ; result = dns_view_find ( val -> view , name , type , 0 , options , ISC_FALSE , NULL , NULL , foundname , & val -> frdataset , & val -> fsigrdataset ) ; if ( result == DNS_R_NXDOMAIN ) { if ( dns_rdataset_isassociated ( & val -> frdataset ) ) dns_rdataset_disassociate ( & val -> frdataset ) ; if ( dns_rdataset_isassociated ( & val -> fsigrdataset ) ) dns_rdataset_disassociate ( & val -> fsigrdataset ) ; } else if ( result == DNS_R_COVERINGNSEC ) { validator_log ( val , ISC_LOG_DEBUG ( 3 ) , " " ) ; INSIST ( type == dns_rdatatype_dlv ) ; if ( val -> frdataset . trust != dns_trust_secure ) { validator_log ( val , ISC_LOG_DEBUG ( 3 ) , " " , dns_trust_totext ( val -> frdataset . trust ) ) ; goto notfound ; } result = dns_rdataset_first ( & val -> frdataset ) ; if ( result != ISC_R_SUCCESS ) goto notfound ; dns_rdataset_current ( & val -> frdataset , & rdata ) ; if ( dns_nsec_typepresent ( & rdata , dns_rdatatype_ns ) && ! dns_nsec_typepresent ( & rdata , dns_rdatatype_soa ) ) { if ( dns_name_issubdomain ( name , foundname ) ) { validator_log ( val , ISC_LOG_DEBUG ( 3 ) , " " ) ; goto notfound ; } } result = dns_rdata_tostruct ( & rdata , & nsec , NULL ) ; if ( result != ISC_R_SUCCESS ) goto notfound ; if ( dns_name_compare ( foundname , & nsec . next ) >= 0 ) { if ( ! dns_name_issubdomain ( name , & nsec . next ) ) { dns_rdata_freestruct ( & nsec ) ; validator_log ( val , ISC_LOG_DEBUG ( 3 ) , " " ) ; goto notfound ; } } else if ( dns_name_compare ( name , & nsec . next ) >= 0 ) { dns_rdata_freestruct ( & nsec ) ; validator_log ( val , ISC_LOG_DEBUG ( 3 ) , " " ) ; goto notfound ; } if ( isc_log_wouldlog ( dns_lctx , ISC_LOG_DEBUG ( 3 ) ) ) { dns_name_format ( name , buf1 , sizeof buf1 ) ; dns_name_format ( foundname , buf2 , sizeof buf2 ) ; dns_name_format ( & nsec . next , buf3 , sizeof buf3 ) ; validator_log ( val , ISC_LOG_DEBUG ( 3 ) , " " , buf1 , buf2 , buf3 ) ; } if ( dns_rdataset_isassociated ( & val -> frdataset ) ) dns_rdataset_disassociate ( & val -> frdataset ) ; if ( dns_rdataset_isassociated ( & val -> fsigrdataset ) ) dns_rdataset_disassociate ( & val -> fsigrdataset ) ; dns_rdata_freestruct ( & nsec ) ; result = DNS_R_NCACHENXDOMAIN ; } else if ( result != ISC_R_SUCCESS && result != DNS_R_NCACHENXDOMAIN && result != DNS_R_NCACHENXRRSET && result != DNS_R_EMPTYNAME && result != DNS_R_NXRRSET && result != ISC_R_NOTFOUND ) { goto notfound ; } return ( result ) ; notfound : if ( dns_rdataset_isassociated ( & val -> frdataset ) ) dns_rdataset_disassociate ( & val -> frdataset ) ; if ( dns_rdataset_isassociated ( & val -> fsigrdataset ) ) dns_rdataset_disassociate ( & val -> fsigrdataset ) ; return ( ISC_R_NOTFOUND ) ; }
%
 Looks for the requested name and type in the view (zones and cache).
% Looks for the requested name and type in the view ( zones and cache ) .
/*
		 * Check if the returned NSEC covers the name.
		 */ /* Parent NSEC record. */ /* End of zone chain. */ /*
				 * XXXMPA We could look for a parent NSEC
				 * at nsec.next and if found retest with
				 * this NSEC.
				 */ /*
			 * XXXMPA We could check if this NSEC is at a zone
			 * apex and if the qname is not below it and look for
			 * a parent NSEC with the same name.  This requires
			 * that we can cache both NSEC records which we
			 * currently don't support.
			 */