isc_result_t dns_acl_match(isc_netaddr_t *reqaddr, dns_name_t *reqsigner, dns_acl_t *acl, dns_aclenv_t *env, int *match, dns_aclelement_t **matchelt) { unsigned int i; REQUIRE(reqaddr != NULL); REQUIRE(matchelt == NULL || *matchelt == NULL); for (i = 0; i < acl->length; i++) { dns_aclelement_t *e = &acl->elements[i]; if (dns_aclelement_match(reqaddr, reqsigner, e, env, matchelt)) { *match = e->negative ? -((int)i+1) : ((int)i+1); return (ISC_R_SUCCESS); } } /* No match. */ *match = 0; return (ISC_R_SUCCESS); }
int ns_sortlist_addrorder1(const isc_netaddr_t *addr, const void *arg) { const dns_aclelement_t *matchelt = (const dns_aclelement_t *) arg; if (dns_aclelement_match(addr, NULL, matchelt, &ns_g_server->aclenv, NULL)) { return (0); } else { return (INT_MAX); } }
ns_sortlisttype_t ns_sortlist_setup(dns_acl_t *acl, isc_netaddr_t *clientaddr, const void **argp) { unsigned int i; if (acl == NULL) goto dont_sort; for (i = 0; i < acl->length; i++) { /* * 'e' refers to the current 'top level statement' * in the sortlist (see ARM). */ dns_aclelement_t *e = &acl->elements[i]; dns_aclelement_t *try_elt; dns_aclelement_t *order_elt = NULL; const dns_aclelement_t *matched_elt = NULL; if (e->type == dns_aclelementtype_nestedacl) { dns_acl_t *inner = e->nestedacl; if (inner->length == 0) try_elt = e; else if (inner->length > 2) goto dont_sort; else if (inner->elements[0].negative) goto dont_sort; else { try_elt = &inner->elements[0]; if (inner->length == 2) order_elt = &inner->elements[1]; } } else { /* * BIND 8 allows bare elements at the top level * as an undocumented feature. */ try_elt = e; } if (dns_aclelement_match(clientaddr, NULL, try_elt, &ns_g_server->aclenv, &matched_elt)) { if (order_elt != NULL) { if (order_elt->type == dns_aclelementtype_nestedacl) { *argp = order_elt->nestedacl; return (NS_SORTLISTTYPE_2ELEMENT); } else if (order_elt->type == dns_aclelementtype_localhost && ns_g_server->aclenv.localhost != NULL) { *argp = ns_g_server->aclenv.localhost; return (NS_SORTLISTTYPE_2ELEMENT); } else if (order_elt->type == dns_aclelementtype_localnets && ns_g_server->aclenv.localnets != NULL) { *argp = ns_g_server->aclenv.localnets; return (NS_SORTLISTTYPE_2ELEMENT); } else { /* * BIND 8 allows a bare IP prefix as * the 2nd element of a 2-element * sortlist statement. */ *argp = order_elt; return (NS_SORTLISTTYPE_1ELEMENT); } } else { INSIST(matched_elt != NULL); *argp = matched_elt; return (NS_SORTLISTTYPE_1ELEMENT); } } } /* No match; don't sort. */ dont_sort: *argp = NULL; return (NS_SORTLISTTYPE_NONE); }
/* * 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); }