Exemplo n.º 1
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);
}
Exemplo n.º 2
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);
}