/* * 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); }
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); }