Exemple #1
0
isc_boolean_t
dns_aclelement_match(isc_netaddr_t *reqaddr,
		     dns_name_t *reqsigner,
		     dns_aclelement_t *e,
		     dns_aclenv_t *env,
		     dns_aclelement_t **matchelt)
{
	dns_acl_t *inner = NULL;
	isc_netaddr_t *addr;
	isc_netaddr_t v4addr;
	int indirectmatch;
	isc_result_t result;

	switch (e->type) {
	case dns_aclelementtype_ipprefix:
		if (env == NULL ||
		    env->match_mapped == ISC_FALSE ||
		    reqaddr->family != AF_INET6 ||
		    !IN6_IS_ADDR_V4MAPPED(&reqaddr->type.in6))
			addr = reqaddr;
		else {
			isc_netaddr_fromv4mapped(&v4addr, reqaddr);
			addr = &v4addr;
		}

		if (isc_netaddr_eqprefix(addr,
					 &e->u.ip_prefix.address, 
					 e->u.ip_prefix.prefixlen))
			goto matched;
		break;
		
	case dns_aclelementtype_keyname:
		if (reqsigner != NULL &&
		    dns_name_equal(reqsigner, &e->u.keyname))
			goto matched;
		break;
		
	case dns_aclelementtype_nestedacl:
		inner = e->u.nestedacl;
	nested:
		result = dns_acl_match(reqaddr, reqsigner,
				       inner,
				       env,
				       &indirectmatch, matchelt);
		INSIST(result == ISC_R_SUCCESS);

		/*
		 * Treat negative matches in indirect ACLs as
		 * "no match".
		 * That way, a negated indirect ACL will never become 
		 * a surprise positive match through double negation.
		 * XXXDCL this should be documented.
		 */
		if (indirectmatch > 0)
			goto matchelt_set;
		
		/*
		 * A negative indirect match may have set *matchelt,
		 * but we don't want it set when we return.
		 */
		if (matchelt != NULL)
			*matchelt = NULL;
		break;
		
	case dns_aclelementtype_any:
	matched:
		if (matchelt != NULL)
			*matchelt = e;
	matchelt_set:
		return (ISC_TRUE);
			
	case dns_aclelementtype_localhost:
		if (env != NULL && env->localhost != NULL) {
			inner = env->localhost;
			goto nested;
		} else {
			break;
		}
		
	case dns_aclelementtype_localnets:
		if (env != NULL && env->localnets != NULL) {
			inner = env->localnets;
			goto nested;
		} else {
			break;
		}
		
	default:
		INSIST(0);
		break;
	}

	return (ISC_FALSE);
}	
Exemple #2
0
/*
 * Determine whether a given address or signer matches a given ACL.
 * For a match with a positive ACL element or iptable radix entry,
 * return with a positive value in match; for a match with a negated ACL
 * element or radix entry, return with a negative value in match.
 */
isc_result_t
dns_acl_match(const isc_netaddr_t *reqaddr,
	      const dns_name_t *reqsigner,
	      const dns_acl_t *acl,
	      const dns_aclenv_t *env,
	      int *match,
	      const dns_aclelement_t **matchelt)
{
	isc_uint16_t bitlen, family;
	isc_prefix_t pfx;
	isc_radix_node_t *node = NULL;
	const isc_netaddr_t *addr;
	isc_netaddr_t v4addr;
	isc_result_t result;
	int match_num = -1;
	unsigned int i;

	REQUIRE(reqaddr != NULL);
	REQUIRE(matchelt == NULL || *matchelt == NULL);

	if (env == NULL || env->match_mapped == ISC_FALSE ||
	    reqaddr->family != AF_INET6 ||
	    !IN6_IS_ADDR_V4MAPPED(&reqaddr->type.in6))
		addr = reqaddr;
	else {
		isc_netaddr_fromv4mapped(&v4addr, reqaddr);
		addr = &v4addr;
	}

	/* Always match with host addresses. */
	family = addr->family;
	bitlen = family == AF_INET6 ? 128 : 32;
	NETADDR_TO_PREFIX_T(addr, pfx, bitlen);

	/* Assume no match. */
	*match = 0;

	/* Search radix. */
	result = isc_radix_search(acl->iptable->radix, &node, &pfx);

	/* Found a match. */
	if (result == ISC_R_SUCCESS && node != NULL) {
		match_num = node->node_num[ISC_IS6(family)];
		if (*(isc_boolean_t *) node->data[ISC_IS6(family)] == ISC_TRUE)
			*match = match_num;
		else
			*match = -match_num;
	}

	/* Now search non-radix elements for a match with a lower node_num. */
	for (i = 0; i < acl->length; i++) {
		dns_aclelement_t *e = &acl->elements[i];

		/* Already found a better match? */
		if (match_num != -1 && match_num < e->node_num) {
			isc_refcount_destroy(&pfx.refcount);
			return (ISC_R_SUCCESS);
		}

		if (dns_aclelement_match(reqaddr, reqsigner,
					 e, env, matchelt)) {
			if (match_num == -1 || e->node_num < match_num) {
				if (e->negative == ISC_TRUE)
					*match = -e->node_num;
				else
					*match = e->node_num;
			}
			isc_refcount_destroy(&pfx.refcount);
			return (ISC_R_SUCCESS);
		}
	}

	isc_refcount_destroy(&pfx.refcount);
	return (ISC_R_SUCCESS);
}
Exemple #3
0
isc_result_t
dns_acl_match2(const isc_netaddr_t *reqaddr,
	       const dns_name_t *reqsigner,
	       const isc_netaddr_t *ecs,
	       isc_uint8_t ecslen,
	       isc_uint8_t *scope,
	       const dns_acl_t *acl,
	       const dns_aclenv_t *env,
	       int *match,
	       const dns_aclelement_t **matchelt)
{
	isc_uint16_t bitlen;
	isc_prefix_t pfx;
	isc_radix_node_t *node = NULL;
	const isc_netaddr_t *addr = reqaddr;
	isc_netaddr_t v4addr;
	isc_result_t result;
	int match_num = -1;
	unsigned int i;

	REQUIRE(reqaddr != NULL);
	REQUIRE(matchelt == NULL || *matchelt == NULL);
	REQUIRE(ecs != NULL || scope == NULL);

	if (env != NULL && env->match_mapped &&
	    addr->family == AF_INET6 &&
	    IN6_IS_ADDR_V4MAPPED(&addr->type.in6))
	{
		isc_netaddr_fromv4mapped(&v4addr, addr);
		addr = &v4addr;
	}

	/* Always match with host addresses. */
	bitlen = (addr->family == AF_INET6) ? 128 : 32;
	NETADDR_TO_PREFIX_T(addr, pfx, bitlen, ISC_FALSE);

	/* Assume no match. */
	*match = 0;

	/* Search radix. */
	result = isc_radix_search(acl->iptable->radix, &node, &pfx);

	/* Found a match. */
	if (result == ISC_R_SUCCESS && node != NULL) {
		int off = ISC_RADIX_OFF(&pfx);
		match_num = node->node_num[off];
		if (*(isc_boolean_t *) node->data[off])
			*match = match_num;
		else
			*match = -match_num;
	}

	isc_refcount_destroy(&pfx.refcount);

	/*
	 * If ecs is not NULL, we search the radix tree again to
	 * see if we find a better match on an ECS node
	 */
	if (ecs != NULL) {
		node = NULL;
		addr = ecs;

		if (env != NULL && env->match_mapped &&
		    addr->family == AF_INET6 &&
		    IN6_IS_ADDR_V4MAPPED(&addr->type.in6))
		{
			isc_netaddr_fromv4mapped(&v4addr, addr);
			addr = &v4addr;
		}

		NETADDR_TO_PREFIX_T(addr, pfx, ecslen, ISC_TRUE);

		result = isc_radix_search(acl->iptable->radix, &node, &pfx);
		if (result == ISC_R_SUCCESS && node != NULL) {
			int off = ISC_RADIX_OFF(&pfx);
			if (match_num == -1 ||
			    node->node_num[off] < match_num)
			{
				match_num = node->node_num[off];
				if (scope != NULL)
					*scope = node->bit;
				if (*(isc_boolean_t *) node->data[off])
					*match = match_num;
				else
					*match = -match_num;
			}
		}

		isc_refcount_destroy(&pfx.refcount);
	}

	/* Now search non-radix elements for a match with a lower node_num. */
	for (i = 0; i < acl->length; i++) {
		dns_aclelement_t *e = &acl->elements[i];

		/* Already found a better match? */
		if (match_num != -1 && match_num < e->node_num) {
			break;
		}

		if (dns_aclelement_match2(reqaddr, reqsigner, ecs, ecslen,
					  scope, e, env, matchelt))
		{
			if (match_num == -1 || e->node_num < match_num) {
				if (e->negative)
					*match = -e->node_num;
				else
					*match = e->node_num;
			}
			break;
		}
	}

	return (ISC_R_SUCCESS);
}