acl.c revision b0bf1ad5b0b1d29b4cdf5de9789405aec5e0844c
1b5a34533410ff4eaff0e5b5b110221a97e29cfcAutomatic Updater * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC")
dafcb997e390efa4423883dafd100c975c4095d6Mark Andrews * Copyright (C) 1999-2002 Internet Software Consortium.
ec5347e2c775f027573ce5648b910361aa926c01Automatic Updater * Permission to use, copy, modify, and/or distribute this software for any
8804fd9936acd703073c4a75072852c38738a990Brian Wellington * purpose with or without fee is hereby granted, provided that the above
8804fd9936acd703073c4a75072852c38738a990Brian Wellington * copyright notice and this permission notice appear in all copies.
dafcb997e390efa4423883dafd100c975c4095d6Mark Andrews * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
dafcb997e390efa4423883dafd100c975c4095d6Mark Andrews * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
dafcb997e390efa4423883dafd100c975c4095d6Mark Andrews * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
dafcb997e390efa4423883dafd100c975c4095d6Mark Andrews * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
dafcb997e390efa4423883dafd100c975c4095d6Mark Andrews * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
dafcb997e390efa4423883dafd100c975c4095d6Mark Andrews * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
dafcb997e390efa4423883dafd100c975c4095d6Mark Andrews * PERFORMANCE OF THIS SOFTWARE.
ec5347e2c775f027573ce5648b910361aa926c01Automatic Updater/* $Id: acl.c,v 1.49 2008/09/26 21:12:02 each Exp $ */
8804fd9936acd703073c4a75072852c38738a990Brian Wellington * Create a new ACL, including an IP table and an array with room
8804fd9936acd703073c4a75072852c38738a990Brian Wellington * for 'n' ACL elements. The elements are uninitialized and the
8804fd9936acd703073c4a75072852c38738a990Brian Wellington * length is 0.
8804fd9936acd703073c4a75072852c38738a990Brian Wellingtondns_acl_create(isc_mem_t *mctx, int n, dns_acl_t **target) {
8804fd9936acd703073c4a75072852c38738a990Brian Wellington * Work around silly limitation of isc_mem_get().
8804fd9936acd703073c4a75072852c38738a990Brian Wellington result = isc_refcount_init(&acl->refcount, 1);
8804fd9936acd703073c4a75072852c38738a990Brian Wellington result = dns_iptable_create(mctx, &acl->iptable);
8804fd9936acd703073c4a75072852c38738a990Brian Wellington * Must set magic early because we use dns_acl_detach() to clean up.
8804fd9936acd703073c4a75072852c38738a990Brian Wellington acl->elements = isc_mem_get(mctx, n * sizeof(dns_aclelement_t));
8804fd9936acd703073c4a75072852c38738a990Brian Wellington memset(acl->elements, 0, n * sizeof(dns_aclelement_t));
8804fd9936acd703073c4a75072852c38738a990Brian Wellington * Create a new ACL and initialize it with the value "any" or "none",
8804fd9936acd703073c4a75072852c38738a990Brian Wellington * depending on the value of the "neg" parameter.
8804fd9936acd703073c4a75072852c38738a990Brian Wellington * "any" is a positive iptable entry with bit length 0.
e3e3bafa138a20558a2253470effc01702fc6dfdBrian Wellington * "none" is the same as "!any".
8804fd9936acd703073c4a75072852c38738a990Brian Wellingtondns_acl_anyornone(isc_mem_t *mctx, isc_boolean_t neg, dns_acl_t **target) {
8804fd9936acd703073c4a75072852c38738a990Brian Wellington result = dns_iptable_addprefix(acl->iptable, NULL, 0, ISC_TF(!neg));
8804fd9936acd703073c4a75072852c38738a990Brian Wellington * Create a new ACL that matches everything.
8804fd9936acd703073c4a75072852c38738a990Brian Wellingtondns_acl_any(isc_mem_t *mctx, dns_acl_t **target) {
13090db2b1c210b8386793ff0cbbb0b4348c1ecaBrian Wellington return (dns_acl_anyornone(mctx, ISC_FALSE, target));
13090db2b1c210b8386793ff0cbbb0b4348c1ecaBrian Wellington * Create a new ACL that matches nothing.
13090db2b1c210b8386793ff0cbbb0b4348c1ecaBrian Wellingtondns_acl_none(isc_mem_t *mctx, dns_acl_t **target) {
8804fd9936acd703073c4a75072852c38738a990Brian Wellington return (dns_acl_anyornone(mctx, ISC_TRUE, target));
e3e3bafa138a20558a2253470effc01702fc6dfdBrian Wellington * If pos is ISC_TRUE, test whether acl is set to "{ any; }"
e3e3bafa138a20558a2253470effc01702fc6dfdBrian Wellington * If pos is ISC_FALSE, test whether acl is set to "{ none; }"
e3e3bafa138a20558a2253470effc01702fc6dfdBrian Wellingtondns_acl_isanyornone(dns_acl_t *acl, isc_boolean_t pos)
e3e3bafa138a20558a2253470effc01702fc6dfdBrian Wellington /* Should never happen but let's be safe */
8804fd9936acd703073c4a75072852c38738a990Brian Wellington if (acl->length != 0 || acl->node_count != 1)
8804fd9936acd703073c4a75072852c38738a990Brian Wellington if (acl->iptable->radix->head->prefix->bitlen == 0 &&
8804fd9936acd703073c4a75072852c38738a990Brian Wellington acl->iptable->radix->head->data[0] != NULL &&
8804fd9936acd703073c4a75072852c38738a990Brian Wellington *(isc_boolean_t *) (acl->iptable->radix->head->data[0]) == pos)
8804fd9936acd703073c4a75072852c38738a990Brian Wellington * Test whether acl is set to "{ any; }"
13090db2b1c210b8386793ff0cbbb0b4348c1ecaBrian Wellington return (dns_acl_isanyornone(acl, ISC_TRUE));
13090db2b1c210b8386793ff0cbbb0b4348c1ecaBrian Wellington * Test whether acl is set to "{ none; }"
13090db2b1c210b8386793ff0cbbb0b4348c1ecaBrian Wellington return (dns_acl_isanyornone(acl, ISC_FALSE));
13090db2b1c210b8386793ff0cbbb0b4348c1ecaBrian Wellington * Determine whether a given address or signer matches a given ACL.
8804fd9936acd703073c4a75072852c38738a990Brian Wellington * For a match with a positive ACL element or iptable radix entry,
8804fd9936acd703073c4a75072852c38738a990Brian Wellington * return with a positive value in match; for a match with a negated ACL
8804fd9936acd703073c4a75072852c38738a990Brian Wellington * element or radix entry, return with a negative value in match.
8804fd9936acd703073c4a75072852c38738a990Brian Wellington unsigned int i;
8804fd9936acd703073c4a75072852c38738a990Brian Wellington REQUIRE(matchelt == NULL || *matchelt == NULL);
a56f5ada432128085e4a06815328023ee0c9610dMark Andrews if (env == NULL || env->match_mapped == ISC_FALSE ||
8804fd9936acd703073c4a75072852c38738a990Brian Wellington isc_netaddr_fromv4mapped(&v4addr, reqaddr);
a56f5ada432128085e4a06815328023ee0c9610dMark Andrews /* Always match with host addresses. */
a56f5ada432128085e4a06815328023ee0c9610dMark Andrews /* Assume no match. */
13090db2b1c210b8386793ff0cbbb0b4348c1ecaBrian Wellington /* Search radix. */
8804fd9936acd703073c4a75072852c38738a990Brian Wellington result = isc_radix_search(acl->iptable->radix, &node, &pfx);
8804fd9936acd703073c4a75072852c38738a990Brian Wellington /* Found a match. */
8804fd9936acd703073c4a75072852c38738a990Brian Wellington if (result == ISC_R_SUCCESS && node != NULL) {
8804fd9936acd703073c4a75072852c38738a990Brian Wellington match_num = node->node_num[ISC_IS6(family)];
13090db2b1c210b8386793ff0cbbb0b4348c1ecaBrian Wellington if (*(isc_boolean_t *) node->data[ISC_IS6(family)] == ISC_TRUE)
13090db2b1c210b8386793ff0cbbb0b4348c1ecaBrian Wellington /* Now search non-radix elements for a match with a lower node_num. */
8804fd9936acd703073c4a75072852c38738a990Brian Wellington /* Already found a better match? */
8804fd9936acd703073c4a75072852c38738a990Brian Wellington if (match_num != -1 && match_num < e->node_num) {
8804fd9936acd703073c4a75072852c38738a990Brian Wellington if (dns_aclelement_match(reqaddr, reqsigner,
2674e1a455d4f71de09b2b60e7a8304b9a305588Mark Andrews if (match_num == -1 || e->node_num < match_num) {
13090db2b1c210b8386793ff0cbbb0b4348c1ecaBrian Wellington * Merge the contents of one ACL into another. Call dns_iptable_merge()
13090db2b1c210b8386793ff0cbbb0b4348c1ecaBrian Wellington * for the IP tables, then concatenate the element arrays.
13090db2b1c210b8386793ff0cbbb0b4348c1ecaBrian Wellington * If pos is set to false, then the nested ACL is to be negated. This
8804fd9936acd703073c4a75072852c38738a990Brian Wellington * means reverse the sense of each *positive* element or IP table node,
8804fd9936acd703073c4a75072852c38738a990Brian Wellington * but leave negatives alone, so as to prevent a double-negative causing
8804fd9936acd703073c4a75072852c38738a990Brian Wellington * an unexpected postive match in the parent ACL.
8804fd9936acd703073c4a75072852c38738a990Brian Wellingtondns_acl_merge(dns_acl_t *dest, dns_acl_t *source, isc_boolean_t pos)
368b37b616234fce3d23099eb180f1dd38e1fb62Mark Andrews /* Resize the element array if needed. */
8804fd9936acd703073c4a75072852c38738a990Brian Wellington if (dest->length + source->length > dest->alloc) {
8804fd9936acd703073c4a75072852c38738a990Brian Wellington /* Copy in the original elements */
8804fd9936acd703073c4a75072852c38738a990Brian Wellington /* Release the memory for the old elements array */
8804fd9936acd703073c4a75072852c38738a990Brian Wellington * Now copy in the new elements, increasing their node_num
8804fd9936acd703073c4a75072852c38738a990Brian Wellington * values so as to keep the new ACL consistent. If we're
8804fd9936acd703073c4a75072852c38738a990Brian Wellington * negating, then negate positive elements, but keep negative
8804fd9936acd703073c4a75072852c38738a990Brian Wellington * elements the same for security reasons.
8804fd9936acd703073c4a75072852c38738a990Brian Wellington if (source->elements[i].node_num > max_node)
a56f5ada432128085e4a06815328023ee0c9610dMark Andrews /* Copy type. */
a56f5ada432128085e4a06815328023ee0c9610dMark Andrews dest->elements[nelem + i].type = source->elements[i].type;
8804fd9936acd703073c4a75072852c38738a990Brian Wellington /* Adjust node numbering. */
8804fd9936acd703073c4a75072852c38738a990Brian Wellington source->elements[i].node_num + dest->node_count;
8804fd9936acd703073c4a75072852c38738a990Brian Wellington /* Duplicate nested acl. */
8804fd9936acd703073c4a75072852c38738a990Brian Wellington if (source->elements[i].type == dns_aclelementtype_nestedacl &&
e3e3bafa138a20558a2253470effc01702fc6dfdBrian Wellington dns_acl_attach(source->elements[i].nestedacl,
13090db2b1c210b8386793ff0cbbb0b4348c1ecaBrian Wellington /* Duplicate key name. */
13090db2b1c210b8386793ff0cbbb0b4348c1ecaBrian Wellington if (source->elements[i].type == dns_aclelementtype_keyname) {
13090db2b1c210b8386793ff0cbbb0b4348c1ecaBrian Wellington dns_name_init(&dest->elements[nelem+i].keyname, NULL);
13090db2b1c210b8386793ff0cbbb0b4348c1ecaBrian Wellington result = dns_name_dup(&source->elements[i].keyname,
8804fd9936acd703073c4a75072852c38738a990Brian Wellington /* reverse sense of positives if this is a negative acl */
8804fd9936acd703073c4a75072852c38738a990Brian Wellington if (!pos && source->elements[i].negative == ISC_FALSE) {
8804fd9936acd703073c4a75072852c38738a990Brian Wellington dest->elements[nelem + i].negative = ISC_TRUE;
8804fd9936acd703073c4a75072852c38738a990Brian Wellington * Merge the iptables. Make sure the destination ACL's
8804fd9936acd703073c4a75072852c38738a990Brian Wellington * node_count value is set correctly afterward.
8804fd9936acd703073c4a75072852c38738a990Brian Wellington result = dns_iptable_merge(dest->iptable, source->iptable, pos);
8804fd9936acd703073c4a75072852c38738a990Brian Wellington * Like dns_acl_match, but matches against the single ACL element 'e'
8804fd9936acd703073c4a75072852c38738a990Brian Wellington * rather than a complete ACL, and returns ISC_TRUE iff it matched.
8804fd9936acd703073c4a75072852c38738a990Brian Wellington * To determine whether the match was prositive or negative, the
8804fd9936acd703073c4a75072852c38738a990Brian Wellington * caller should examine e->negative. Since the element 'e' may be
8804fd9936acd703073c4a75072852c38738a990Brian Wellington * a reference to a named ACL or a nested ACL, a matching element
8804fd9936acd703073c4a75072852c38738a990Brian Wellington * returned through 'matchelt' is not necessarily 'e' itself.
8804fd9936acd703073c4a75072852c38738a990Brian Wellingtondns_aclelement_match(const isc_netaddr_t *reqaddr,
13090db2b1c210b8386793ff0cbbb0b4348c1ecaBrian Wellington switch (e->type) {
f3ca27e9fe307b55e35ea8d7b37351650630e5a3Andreas Gustafsson if (env == NULL || env->localnets == NULL)
8804fd9936acd703073c4a75072852c38738a990Brian Wellington /* Should be impossible. */
8804fd9936acd703073c4a75072852c38738a990Brian Wellington result = dns_acl_match(reqaddr, reqsigner, inner, env,
8804fd9936acd703073c4a75072852c38738a990Brian Wellington * Treat negative matches in indirect ACLs as "no match".
8804fd9936acd703073c4a75072852c38738a990Brian Wellington * That way, a negated indirect ACL will never become a
8804fd9936acd703073c4a75072852c38738a990Brian Wellington * surprise positive match through double negation.
8804fd9936acd703073c4a75072852c38738a990Brian Wellington * XXXDCL this should be documented.
8804fd9936acd703073c4a75072852c38738a990Brian Wellington * A negative indirect match may have set *matchelt, but we don't
8804fd9936acd703073c4a75072852c38738a990Brian Wellington * want it set when we return.
8804fd9936acd703073c4a75072852c38738a990Brian Wellingtondns_acl_attach(dns_acl_t *source, dns_acl_t **target) {
8804fd9936acd703073c4a75072852c38738a990Brian Wellington isc_refcount_increment(&source->refcount, NULL);
8804fd9936acd703073c4a75072852c38738a990Brian Wellington unsigned int i;
8804fd9936acd703073c4a75072852c38738a990Brian Wellington if (de->type == dns_aclelementtype_keyname) {
8804fd9936acd703073c4a75072852c38738a990Brian Wellington } else if (de->type == dns_aclelementtype_nestedacl) {
8804fd9936acd703073c4a75072852c38738a990Brian Wellington isc_mem_put(dacl->mctx, dacl, sizeof(*dacl));
8804fd9936acd703073c4a75072852c38738a990Brian Wellington unsigned int refs;
8804fd9936acd703073c4a75072852c38738a990Brian Wellington isc_refcount_decrement(&acl->refcount, &refs);
8804fd9936acd703073c4a75072852c38738a990Brian Wellingtonstatic isc_once_t insecure_prefix_once = ISC_ONCE_INIT;
8804fd9936acd703073c4a75072852c38738a990Brian Wellington RUNTIME_CHECK(isc_mutex_init(&insecure_prefix_lock) == ISC_R_SUCCESS);
e3e3bafa138a20558a2253470effc01702fc6dfdBrian Wellington * Called via isc_radix_walk() to find IP table nodes that are
if (!secure) {
switch (family) {
case AF_INET:
case AF_INET6:
if (insecure)
return(ISC_TRUE);
for (i = 0; i < a->length; i++) {
if (e->negative)
switch (e->type) {
return (ISC_TRUE);
return (ISC_TRUE);
INSIST(0);
return (ISC_TRUE);
return (ISC_FALSE);
goto cleanup_nothing;
goto cleanup_localhost;
return (ISC_R_SUCCESS);
return (result);