lib/dns/rbtdb.c
/*
 * Search the CDIR block tree of a response policy tree of trees for all of
 * the IP addresses in an A or AAAA rdataset.
 * Among the policies for all IPv4 and IPv6 addresses for a name, choose
 * the longest prefix.  Among those with the longest prefix, the first
 * configured policy.  Among answers for with the longest prefixes for
 * two or more IP addresses in the A and AAAA rdatasets the lexically
 * smallest address.
 */
Search the CDIR block tree of a response policy tree of trees for all of
the IP addresses in an A or AAAA rdataset.
Among the policies for all IPv4 and IPv6 addresses for a name, choose
the longest prefix.  Among those with the longest prefix, the first
configured policy.  Among answers for with the longest prefixes for
two or more IP addresses in the A and AAAA rdatasets the lexically
smallest address.
Search the CDIR block tree of a response policy tree of trees for all of the IP addresses in an A or AAAA rdataset . Among the policies for all IPv4 and IPv6 addresses for a name choose the longest prefix . Among those with the longest prefix the first configured policy . Among answers for with the longest prefixes for two or more IP addresses in the A and AAAA rdatasets the lexically smallest address .
static isc_result_t
rpz_findips(dns_rpz_zone_t *rpz, dns_rpz_type_t rpz_type,
	    dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *version,
	    dns_rdataset_t *ardataset, dns_rpz_st_t *st)
{
	dns_rbtdb_t *rbtdb;
	struct in_addr ina;
	struct in6_addr in6a;
	isc_netaddr_t netaddr;
	dns_fixedname_t selfnamef, qnamef;
	dns_name_t *selfname, *qname;
	dns_rbtnode_t *node;
	dns_rdataset_t zrdataset;
	dns_rpz_cidr_bits_t prefix;
	isc_result_t result;
	dns_rpz_policy_t rpz_policy;
	dns_ttl_t ttl;
	rbtdb = (dns_rbtdb_t *)db;
	REQUIRE(VALID_RBTDB(rbtdb));
	RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
	if (rbtdb->rpz_cidr == NULL) {
		RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
		dns_db_detach(&db);
		dns_zone_detach(&zone);
		return (ISC_R_UNEXPECTED);
	}
	dns_fixedname_init(&selfnamef);
	dns_fixedname_init(&qnamef);
	selfname = dns_fixedname_name(&selfnamef);
	qname = dns_fixedname_name(&qnamef);
	for (result = dns_rdataset_first(ardataset);
	     result == ISC_R_SUCCESS;
	     result = dns_rdataset_next(ardataset)) {
		dns_rdata_t rdata = DNS_RDATA_INIT;
		dns_rdataset_current(ardataset, &rdata);
		switch (rdata.type) {
		case dns_rdatatype_a:
			INSIST(rdata.length == 4);
			memcpy(&ina.s_addr, rdata.data, 4);
			isc_netaddr_fromin(&netaddr, &ina);
			break;
		case dns_rdatatype_aaaa:
			INSIST(rdata.length == 16);
			memcpy(in6a.s6_addr, rdata.data, 16);
			isc_netaddr_fromin6(&netaddr, &in6a);
			break;
		default:
			continue;
		}
		result = dns_rpz_cidr_find(rbtdb->rpz_cidr, &netaddr, rpz_type,
					   selfname, qname, &prefix);
		if (result != ISC_R_SUCCESS)
			continue;
		if (st->m.policy != DNS_RPZ_POLICY_MISS) {
			if (prefix < st->m.prefix)
				continue;
			if (prefix == st->m.prefix &&
			    rpz->num > st->m.rpz->num)
				continue;
		}
		node = NULL;
		result = dns_rbt_findnode(rbtdb->tree, qname, NULL,
					  &node, NULL, 0, NULL, NULL);
		if (result != ISC_R_SUCCESS) {
			char namebuf[DNS_NAME_FORMATSIZE];
			dns_name_format(qname, namebuf, sizeof(namebuf));
			isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
				      DNS_LOGMODULE_CACHE, DNS_RPZ_ERROR_LEVEL,
				      "rpz_findips findnode(%s): %s",
				      namebuf, isc_result_totext(result));
			continue;
		}
		dns_rdataset_init(&zrdataset);
		result = dns_db_findrdataset(db, node, version, ardataset->type,
					     0, 0, &zrdataset, NULL);
		if (result != ISC_R_SUCCESS)
			result = dns_db_findrdataset(db, node, version,
						     dns_rdatatype_cname,
						     0, 0, &zrdataset, NULL);
		if (result == ISC_R_SUCCESS) {
			if (zrdataset.type != dns_rdatatype_cname) {
				rpz_policy = DNS_RPZ_POLICY_RECORD;
			} else {
				rpz_policy = dns_rpz_decode_cname(&zrdataset,
								  selfname);
				if (rpz_policy == DNS_RPZ_POLICY_RECORD)
					result = DNS_R_CNAME;
			}
			ttl = zrdataset.ttl;
		} else {
			rpz_policy = DNS_RPZ_POLICY_RECORD;
			result = DNS_R_NXRRSET;
			ttl = DNS_RPZ_TTL_DEFAULT;
		}
		if (rpz->policy != DNS_RPZ_POLICY_GIVEN &&
		    rpz_policy != DNS_RPZ_POLICY_NO_OP)
			rpz_policy = rpz->policy;
		if (st->m.policy == DNS_RPZ_POLICY_MISS ||
		    prefix > st->m.prefix ||
		    rpz->num <= st->m.rpz->num ||
		    0 > dns_name_compare(qname, st->qname)) {
			if (dns_rdataset_isassociated(st->m.rdataset))
				dns_rdataset_disassociate(st->m.rdataset);
			if (st->m.node != NULL)
				dns_db_detachnode(st->m.db, &st->m.node);
			if (st->m.db != NULL)
				dns_db_detach(&st->m.db);
			if (st->m.zone != NULL)
				dns_zone_detach(&st->m.zone);
			st->m.rpz = rpz;
			st->m.type = rpz_type;
			st->m.prefix = prefix;
			st->m.policy = rpz_policy;
			st->m.ttl = ttl;
			st->m.result = result;
			dns_name_copy(qname, st->qname, NULL);
			if (rpz_policy == DNS_RPZ_POLICY_RECORD &&
			    result != DNS_R_NXRRSET) {
				dns_rdataset_clone(&zrdataset,st->m.rdataset);
				dns_db_attachnode(db, node, &st->m.node);
			}
			dns_db_attach(db, &st->m.db);
			dns_zone_attach(zone, &st->m.zone);
		}
		if (dns_rdataset_isassociated(&zrdataset))
			dns_rdataset_disassociate(&zrdataset);
	}
	RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
	return (ISC_R_SUCCESS);
}
static isc_result_t rpz_findips ( dns_rpz_zone_t * rpz , dns_rpz_type_t rpz_type , dns_zone_t * zone , dns_db_t * db , dns_dbversion_t * version , dns_rdataset_t * ardataset , dns_rpz_st_t * st ) { dns_rbtdb_t * rbtdb ; struct in_addr ina ; struct in6_addr in6a ; isc_netaddr_t netaddr ; dns_fixedname_t selfnamef , qnamef ; dns_name_t * selfname , * qname ; dns_rbtnode_t * node ; dns_rdataset_t zrdataset ; dns_rpz_cidr_bits_t prefix ; isc_result_t result ; dns_rpz_policy_t rpz_policy ; dns_ttl_t ttl ; rbtdb = ( dns_rbtdb_t * ) db ; REQUIRE ( VALID_RBTDB ( rbtdb ) ) ; RWLOCK ( & rbtdb -> tree_lock , isc_rwlocktype_read ) ; if ( rbtdb -> rpz_cidr == NULL ) { RWUNLOCK ( & rbtdb -> tree_lock , isc_rwlocktype_read ) ; dns_db_detach ( & db ) ; dns_zone_detach ( & zone ) ; return ( ISC_R_UNEXPECTED ) ; } dns_fixedname_init ( & selfnamef ) ; dns_fixedname_init ( & qnamef ) ; selfname = dns_fixedname_name ( & selfnamef ) ; qname = dns_fixedname_name ( & qnamef ) ; for ( result = dns_rdataset_first ( ardataset ) ; result == ISC_R_SUCCESS ; result = dns_rdataset_next ( ardataset ) ) { dns_rdata_t rdata = DNS_RDATA_INIT ; dns_rdataset_current ( ardataset , & rdata ) ; switch ( rdata . type ) { case dns_rdatatype_a : INSIST ( rdata . length == 4 ) ; memcpy ( & ina . s_addr , rdata . data , 4 ) ; isc_netaddr_fromin ( & netaddr , & ina ) ; break ; case dns_rdatatype_aaaa : INSIST ( rdata . length == 16 ) ; memcpy ( in6a . s6_addr , rdata . data , 16 ) ; isc_netaddr_fromin6 ( & netaddr , & in6a ) ; break ; default : continue ; } result = dns_rpz_cidr_find ( rbtdb -> rpz_cidr , & netaddr , rpz_type , selfname , qname , & prefix ) ; if ( result != ISC_R_SUCCESS ) continue ; if ( st -> m . policy != DNS_RPZ_POLICY_MISS ) { if ( prefix < st -> m . prefix ) continue ; if ( prefix == st -> m . prefix && rpz -> num > st -> m . rpz -> num ) continue ; } node = NULL ; result = dns_rbt_findnode ( rbtdb -> tree , qname , NULL , & node , NULL , 0 , NULL , NULL ) ; if ( result != ISC_R_SUCCESS ) { char namebuf [ DNS_NAME_FORMATSIZE ] ; dns_name_format ( qname , namebuf , sizeof ( namebuf ) ) ; isc_log_write ( dns_lctx , DNS_LOGCATEGORY_DATABASE , DNS_LOGMODULE_CACHE , DNS_RPZ_ERROR_LEVEL , " " , namebuf , isc_result_totext ( result ) ) ; continue ; } dns_rdataset_init ( & zrdataset ) ; result = dns_db_findrdataset ( db , node , version , ardataset -> type , 0 , 0 , & zrdataset , NULL ) ; if ( result != ISC_R_SUCCESS ) result = dns_db_findrdataset ( db , node , version , dns_rdatatype_cname , 0 , 0 , & zrdataset , NULL ) ; if ( result == ISC_R_SUCCESS ) { if ( zrdataset . type != dns_rdatatype_cname ) { rpz_policy = DNS_RPZ_POLICY_RECORD ; } else { rpz_policy = dns_rpz_decode_cname ( & zrdataset , selfname ) ; if ( rpz_policy == DNS_RPZ_POLICY_RECORD ) result = DNS_R_CNAME ; } ttl = zrdataset . ttl ; } else { rpz_policy = DNS_RPZ_POLICY_RECORD ; result = DNS_R_NXRRSET ; ttl = DNS_RPZ_TTL_DEFAULT ; } if ( rpz -> policy != DNS_RPZ_POLICY_GIVEN && rpz_policy != DNS_RPZ_POLICY_NO_OP ) rpz_policy = rpz -> policy ; if ( st -> m . policy == DNS_RPZ_POLICY_MISS || prefix > st -> m . prefix || rpz -> num <= st -> m . rpz -> num || 0 > dns_name_compare ( qname , st -> qname ) ) { if ( dns_rdataset_isassociated ( st -> m . rdataset ) ) dns_rdataset_disassociate ( st -> m . rdataset ) ; if ( st -> m . node != NULL ) dns_db_detachnode ( st -> m . db , & st -> m . node ) ; if ( st -> m . db != NULL ) dns_db_detach ( & st -> m . db ) ; if ( st -> m . zone != NULL ) dns_zone_detach ( & st -> m . zone ) ; st -> m . rpz = rpz ; st -> m . type = rpz_type ; st -> m . prefix = prefix ; st -> m . policy = rpz_policy ; st -> m . ttl = ttl ; st -> m . result = result ; dns_name_copy ( qname , st -> qname , NULL ) ; if ( rpz_policy == DNS_RPZ_POLICY_RECORD && result != DNS_R_NXRRSET ) { dns_rdataset_clone ( & zrdataset , st -> m . rdataset ) ; dns_db_attachnode ( db , node , & st -> m . node ) ; } dns_db_attach ( db , & st -> m . db ) ; dns_zone_attach ( zone , & st -> m . zone ) ; } if ( dns_rdataset_isassociated ( & zrdataset ) ) dns_rdataset_disassociate ( & zrdataset ) ; } RWUNLOCK ( & rbtdb -> tree_lock , isc_rwlocktype_read ) ; return ( ISC_R_SUCCESS ) ; }
Search the CDIR block tree of a response policy tree of trees for all of
 the IP addresses in an A or AAAA rdataset.
Search the CDIR block tree of a response policy tree of trees for all of the IP addresses in an A or AAAA rdataset .
/*
		 * Choose the policy with the longest matching prefix.
		 * Between policies with the same prefix, choose the first
		 * configured.
		 */ /*
		 * We have rpz_st an entry with a prefix at least as long as
		 * the prefix of the entry we had before.  Find the node
		 * corresponding to CDIR tree entry.
		 */ /*
		 * First look for a simple rewrite of the IP address.
		 * If that fails, look for a CNAME.  If we cannot find
		 * a CNAME or the CNAME is neither of the special forms
		 * "*" or ".", treat it like a real CNAME.
		 */ /*
		 * Use an overriding action specified in the configuration file
		 */ /*
		 * We know the new prefix is at least as long as the current.
		 * Prefer the new answer if the new prefix is longer.
		 * Prefer the zone configured first if the prefixes are equal.
		 * With two actions from the same zone, prefer the action
		 * on the "smallest" name.
		 */