acl.c revision 573d78f3d53859bc01ce5d5cebbaac9b8b90bfba
499b34cea04a46823d003d4c0520c8b03e8513cbBrian Wellington * Copyright (C) 2004-2009, 2011, 2013 Internet Systems Consortium, Inc. ("ISC")
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence * Copyright (C) 1999-2002 Internet Software Consortium.
9178881e1bf6a4b01db886b355406c8bed61cc2aMichael Graff * Permission to use, copy, modify, and/or distribute this software for any
9178881e1bf6a4b01db886b355406c8bed61cc2aMichael Graff * purpose with or without fee is hereby granted, provided that the above
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence * copyright notice and this permission notice appear in all copies.
15a44745412679c30a6d022733925af70a38b715David Lawrence * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
15a44745412679c30a6d022733925af70a38b715David Lawrence * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
15a44745412679c30a6d022733925af70a38b715David Lawrence * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
15a44745412679c30a6d022733925af70a38b715David Lawrence * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15a44745412679c30a6d022733925af70a38b715David Lawrence * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
15a44745412679c30a6d022733925af70a38b715David Lawrence * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15a44745412679c30a6d022733925af70a38b715David Lawrence * PERFORMANCE OF THIS SOFTWARE.
19c7cce8555ccc0c95455a0c35dedd017d420d05Mark Andrews/* $Id: acl.c,v 1.55 2011/06/17 23:47:49 tbox Exp $ */
7d823f705d9d3a8cb4d43fcf11249515e2845364Andreas Gustafsson * Create a new ACL, including an IP table and an array with room
9178881e1bf6a4b01db886b355406c8bed61cc2aMichael Graff * for 'n' ACL elements. The elements are uninitialized and the
294ae26fb3e1376b4c34c6b8d15737e39cc2cb48Andreas Gustafsson * length is 0.
f9df80f4348ef68043903efa08299480324f4823Michael Graffdns_acl_create(isc_mem_t *mctx, int n, dns_acl_t **target) {
6d4886fa7430889a96dbf9b88a2a4eb6f9d04674Brian Wellington * Work around silly limitation of isc_mem_get().
f9df80f4348ef68043903efa08299480324f4823Michael Graff result = isc_refcount_init(&acl->refcount, 1);
1ed4ba5a1fcb6aecd1c92fdcc75c6b4bbb7cc60fMichael Sawyer result = dns_iptable_create(mctx, &acl->iptable);
f9df80f4348ef68043903efa08299480324f4823Michael Graff * Must set magic early because we use dns_acl_detach() to clean up.
c95a89b433e42ecf9108b6c263f405fecc0d8a65Michael Sawyer acl->elements = isc_mem_get(mctx, n * sizeof(dns_aclelement_t));
c95a89b433e42ecf9108b6c263f405fecc0d8a65Michael Sawyer memset(acl->elements, 0, n * sizeof(dns_aclelement_t));
c95a89b433e42ecf9108b6c263f405fecc0d8a65Michael Sawyer * Create a new ACL and initialize it with the value "any" or "none",
c95a89b433e42ecf9108b6c263f405fecc0d8a65Michael Sawyer * depending on the value of the "neg" parameter.
c95a89b433e42ecf9108b6c263f405fecc0d8a65Michael Sawyer * "any" is a positive iptable entry with bit length 0.
c95a89b433e42ecf9108b6c263f405fecc0d8a65Michael Sawyer * "none" is the same as "!any".
c95a89b433e42ecf9108b6c263f405fecc0d8a65Michael Sawyerdns_acl_anyornone(isc_mem_t *mctx, isc_boolean_t neg, dns_acl_t **target) {
c95a89b433e42ecf9108b6c263f405fecc0d8a65Michael Sawyer result = dns_iptable_addprefix(acl->iptable, NULL, 0, ISC_TF(!neg));
c95a89b433e42ecf9108b6c263f405fecc0d8a65Michael Sawyer * Create a new ACL that matches everything.
c95a89b433e42ecf9108b6c263f405fecc0d8a65Michael Sawyerdns_acl_any(isc_mem_t *mctx, dns_acl_t **target) {
c95a89b433e42ecf9108b6c263f405fecc0d8a65Michael Sawyer return (dns_acl_anyornone(mctx, ISC_FALSE, target));
c95a89b433e42ecf9108b6c263f405fecc0d8a65Michael Sawyer * Create a new ACL that matches nothing.
c95a89b433e42ecf9108b6c263f405fecc0d8a65Michael Sawyerdns_acl_none(isc_mem_t *mctx, dns_acl_t **target) {
c95a89b433e42ecf9108b6c263f405fecc0d8a65Michael Sawyer return (dns_acl_anyornone(mctx, ISC_TRUE, target));
f9df80f4348ef68043903efa08299480324f4823Michael Graff * If pos is ISC_TRUE, test whether acl is set to "{ any; }"
f9df80f4348ef68043903efa08299480324f4823Michael Graff * If pos is ISC_FALSE, test whether acl is set to "{ none; }"
97e7d389d54a9e3a1ba8313ed140b04afabc7081Michael Graffdns_acl_isanyornone(dns_acl_t *acl, isc_boolean_t pos)
f9df80f4348ef68043903efa08299480324f4823Michael Graff /* Should never happen but let's be safe */
f9df80f4348ef68043903efa08299480324f4823Michael Graff if (acl->iptable->radix->head->prefix->bitlen == 0 &&
97e7d389d54a9e3a1ba8313ed140b04afabc7081Michael Graff *(isc_boolean_t *) (acl->iptable->radix->head->data[0]) == pos)
9178881e1bf6a4b01db886b355406c8bed61cc2aMichael Graff * Test whether acl is set to "{ any; }"
9178881e1bf6a4b01db886b355406c8bed61cc2aMichael Graff * Test whether acl is set to "{ none; }"
9178881e1bf6a4b01db886b355406c8bed61cc2aMichael Graff * Determine whether a given address or signer matches a given ACL.
9178881e1bf6a4b01db886b355406c8bed61cc2aMichael Graff * For a match with a positive ACL element or iptable radix entry,
9178881e1bf6a4b01db886b355406c8bed61cc2aMichael Graff * return with a positive value in match; for a match with a negated ACL
9178881e1bf6a4b01db886b355406c8bed61cc2aMichael Graff * element or radix entry, return with a negative value in match.
9178881e1bf6a4b01db886b355406c8bed61cc2aMichael Graff unsigned int i;
f9df80f4348ef68043903efa08299480324f4823Michael Graff REQUIRE(matchelt == NULL || *matchelt == NULL);
97e7d389d54a9e3a1ba8313ed140b04afabc7081Michael Graff if (env == NULL || env->match_mapped == ISC_FALSE ||
97e7d389d54a9e3a1ba8313ed140b04afabc7081Michael Graff /* Always match with host addresses. */
9178881e1bf6a4b01db886b355406c8bed61cc2aMichael Graff /* Assume no match. */
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff /* Search radix. */
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff result = isc_radix_search(acl->iptable->radix, &node, &pfx);
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff /* Found a match. */
3ddd814a97de1d152ba0913c592d6e6dc83d38a6Michael Graff if (result == ISC_R_SUCCESS && node != NULL) {
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff if (*(isc_boolean_t *) node->data[ISC_IS6(family)] == ISC_TRUE)
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff /* Now search non-radix elements for a match with a lower node_num. */
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff /* Already found a better match? */
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff if (match_num != -1 && match_num < e->node_num) {
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff if (match_num == -1 || e->node_num < match_num) {
70fd62761dfe44f2254fb63ac3ded1b02663713fMichael Graff * Merge the contents of one ACL into another. Call dns_iptable_merge()
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff * for the IP tables, then concatenate the element arrays.
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff * If pos is set to false, then the nested ACL is to be negated. This
97e7d389d54a9e3a1ba8313ed140b04afabc7081Michael Graff * means reverse the sense of each *positive* element or IP table node,
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff * but leave negatives alone, so as to prevent a double-negative causing
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff * an unexpected positive match in the parent ACL.
d68838693666ba930ec4143f848c18bff2bfc244Michael Graffdns_acl_merge(dns_acl_t *dest, dns_acl_t *source, isc_boolean_t pos)
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff /* Resize the element array if needed. */
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff if (dest->length + source->length > dest->alloc) {
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff /* Copy in the original elements */
70fd62761dfe44f2254fb63ac3ded1b02663713fMichael Graff /* Release the memory for the old elements array */
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff * Now copy in the new elements, increasing their node_num
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff * values so as to keep the new ACL consistent. If we're
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff * negating, then negate positive elements, but keep negative
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff * elements the same for security reasons.
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff /* Copy type. */
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff dest->elements[nelem + i].type = source->elements[i].type;
f9df80f4348ef68043903efa08299480324f4823Michael Graff /* Adjust node numbering. */
f9df80f4348ef68043903efa08299480324f4823Michael Graff source->elements[i].node_num + dest->node_count;
f9df80f4348ef68043903efa08299480324f4823Michael Graff /* Duplicate nested acl. */
f9df80f4348ef68043903efa08299480324f4823Michael Graff if (source->elements[i].type == dns_aclelementtype_nestedacl &&
1a69a1a78cfaa86f3b68bbc965232b7876d4da2aDavid Lawrence /* Duplicate key name. */
d8705ff90a299e0aa9fc2b4286bc0a71cf221872Bob Halley if (source->elements[i].type == dns_aclelementtype_keyname) {
d8705ff90a299e0aa9fc2b4286bc0a71cf221872Bob Halley dns_name_init(&dest->elements[nelem+i].keyname, NULL);
d8705ff90a299e0aa9fc2b4286bc0a71cf221872Bob Halley result = dns_name_dup(&source->elements[i].keyname,
fe0e3c7707580da885bb6819e4f307986eb60cd0Brian Wellington /* reverse sense of positives if this is a negative acl */
5caab9f99d19ab9ebb0a0ba64c09c8de80e89e29Brian Wellington if (!pos && source->elements[i].negative == ISC_FALSE) {
f9df80f4348ef68043903efa08299480324f4823Michael Graff dest->elements[nelem + i].negative = ISC_TRUE;
6d4886fa7430889a96dbf9b88a2a4eb6f9d04674Brian Wellington * Merge the iptables. Make sure the destination ACL's
1a69a1a78cfaa86f3b68bbc965232b7876d4da2aDavid Lawrence * node_count value is set correctly afterward.
6d4886fa7430889a96dbf9b88a2a4eb6f9d04674Brian Wellington result = dns_iptable_merge(dest->iptable, source->iptable, pos);
d8705ff90a299e0aa9fc2b4286bc0a71cf221872Bob Halley * Like dns_acl_match, but matches against the single ACL element 'e'
f9df80f4348ef68043903efa08299480324f4823Michael Graff * rather than a complete ACL, and returns ISC_TRUE iff it matched.
1a69a1a78cfaa86f3b68bbc965232b7876d4da2aDavid Lawrence * To determine whether the match was positive or negative, the
d8705ff90a299e0aa9fc2b4286bc0a71cf221872Bob Halley * caller should examine e->negative. Since the element 'e' may be
d8705ff90a299e0aa9fc2b4286bc0a71cf221872Bob Halley * a reference to a named ACL or a nested ACL, a matching element
6d4886fa7430889a96dbf9b88a2a4eb6f9d04674Brian Wellington * returned through 'matchelt' is not necessarily 'e' itself.
24694ab18a48bcc9c50304bd8b7eb6b9c7650129Brian Wellingtondns_aclelement_match(const isc_netaddr_t *reqaddr,
efcd38346161b10d60368411cfb2c0d1c22b5fb1Brian Wellington switch (e->type) {
f9df80f4348ef68043903efa08299480324f4823Michael Graff /* Should be impossible. */
fccf7905e8a06067d49ec00c53d4d57a38a71e52Michael Graff result = dns_acl_match(reqaddr, reqsigner, inner, env,
5eb8688b78ddf13d46cd52561301c35d24a5d52aBob Halley * Treat negative matches in indirect ACLs as "no match".
5eb8688b78ddf13d46cd52561301c35d24a5d52aBob Halley * That way, a negated indirect ACL will never become a
5eb8688b78ddf13d46cd52561301c35d24a5d52aBob Halley * surprise positive match through double negation.
5eb8688b78ddf13d46cd52561301c35d24a5d52aBob Halley * XXXDCL this should be documented.
5eb8688b78ddf13d46cd52561301c35d24a5d52aBob Halley * A negative indirect match may have set *matchelt, but we don't
5eb8688b78ddf13d46cd52561301c35d24a5d52aBob Halley * want it set when we return.
0f80bfec687db08a6e6ce945ef1d818da06c7ca9Brian Wellingtondns_acl_attach(dns_acl_t *source, dns_acl_t **target) {
0f80bfec687db08a6e6ce945ef1d818da06c7ca9Brian Wellington isc_refcount_increment(&source->refcount, NULL);
0f80bfec687db08a6e6ce945ef1d818da06c7ca9Brian Wellington unsigned int i;
d1cbf714097e900ed1703529584d3e1a50e8a4a8Brian Wellington INSIST(!ISC_LINK_LINKED(dacl, nextincache));
5caab9f99d19ab9ebb0a0ba64c09c8de80e89e29Brian Wellington if (de->type == dns_aclelementtype_keyname) {
22057930cd2a71e1073781b650c7296739c869a6Brian Wellington } else if (de->type == dns_aclelementtype_nestedacl) {
5caab9f99d19ab9ebb0a0ba64c09c8de80e89e29Brian Wellington isc_mem_putanddetach(&dacl->mctx, dacl, sizeof(*dacl));
d8705ff90a299e0aa9fc2b4286bc0a71cf221872Bob Halley unsigned int refs;
1a69a1a78cfaa86f3b68bbc965232b7876d4da2aDavid Lawrence isc_refcount_decrement(&acl->refcount, &refs);
5eb8688b78ddf13d46cd52561301c35d24a5d52aBob Halleystatic isc_once_t insecure_prefix_once = ISC_ONCE_INIT;
f9df80f4348ef68043903efa08299480324f4823Michael Graff RUNTIME_CHECK(isc_mutex_init(&insecure_prefix_lock) == ISC_R_SUCCESS);
70fd62761dfe44f2254fb63ac3ded1b02663713fMichael Graff * Called via isc_radix_walk() to find IP table nodes that are
70fd62761dfe44f2254fb63ac3ded1b02663713fMichael Graffis_insecure(isc_prefix_t *prefix, void **data) {
70fd62761dfe44f2254fb63ac3ded1b02663713fMichael Graff /* Negated entries are always secure. */
70fd62761dfe44f2254fb63ac3ded1b02663713fMichael Graff secure = * (isc_boolean_t *)data[ISC_IS6(family)];
f9df80f4348ef68043903efa08299480324f4823Michael Graff /* If loopback prefix found, return */
f9df80f4348ef68043903efa08299480324f4823Michael Graff htonl(prefix->add.sin.s_addr) == INADDR_LOOPBACK)
f9df80f4348ef68043903efa08299480324f4823Michael Graff if (bitlen == 128 && IN6_IS_ADDR_LOOPBACK(&prefix->add.sin6))
f9df80f4348ef68043903efa08299480324f4823Michael Graff /* Non-negated, non-loopback */
f9df80f4348ef68043903efa08299480324f4823Michael Graff insecure_prefix_found = ISC_TRUE; /* LOCKED */
f9df80f4348ef68043903efa08299480324f4823Michael Graff * Return ISC_TRUE iff the acl 'a' is considered insecure, that is,
ddd035637d92035a0d9e2bc32a7e2c9cc8a99d3fMichael Graff * if it contains IP addresses other than those of the local host.
97e7d389d54a9e3a1ba8313ed140b04afabc7081Michael Graff * This is intended for applications such as printing warning
ddd035637d92035a0d9e2bc32a7e2c9cc8a99d3fMichael Graff * messages for suspect ACLs; it is not intended for making access
ddd035637d92035a0d9e2bc32a7e2c9cc8a99d3fMichael Graff * control decisions. We make no guarantee that an ACL for which
ddd035637d92035a0d9e2bc32a7e2c9cc8a99d3fMichael Graff * this function returns ISC_FALSE is safe.
ddd035637d92035a0d9e2bc32a7e2c9cc8a99d3fMichael Graff unsigned int i;
ddd035637d92035a0d9e2bc32a7e2c9cc8a99d3fMichael Graff RUNTIME_CHECK(isc_once_do(&insecure_prefix_once,
f9df80f4348ef68043903efa08299480324f4823Michael Graff * Walk radix tree to find out if there are any non-negated,
70fd62761dfe44f2254fb63ac3ded1b02663713fMichael Graff * non-loopback prefixes.
af602636644fdfaabc331bd926b0aabb9432e152Brian Wellington isc_radix_process(a->iptable->radix, is_insecure);
efcd38346161b10d60368411cfb2c0d1c22b5fb1Brian Wellington /* Now check non-radix elements */
efcd38346161b10d60368411cfb2c0d1c22b5fb1Brian Wellington for (i = 0; i < a->length; i++) {
0b764d91c9021259f15b32c4beec852f2888f40cBrian Wellington /* A negated match can never be insecure. */
efcd38346161b10d60368411cfb2c0d1c22b5fb1Brian Wellington switch (e->type) {
f9df80f4348ef68043903efa08299480324f4823Michael Graff /* No insecure elements were found. */
0f80bfec687db08a6e6ce945ef1d818da06c7ca9Brian Wellington * Initialize ACL environment, setting up localhost and localnets ACLs
0f80bfec687db08a6e6ce945ef1d818da06c7ca9Brian Wellingtondns_aclenv_init(isc_mem_t *mctx, dns_aclenv_t *env) {
0f80bfec687db08a6e6ce945ef1d818da06c7ca9Brian Wellington result = dns_acl_create(mctx, 0, &env->localhost);
0f80bfec687db08a6e6ce945ef1d818da06c7ca9Brian Wellington result = dns_acl_create(mctx, 0, &env->localnets);
abaec24086f0cc3d7c0994ca9d2247b40eb6aaedBrian Wellingtondns_aclenv_copy(dns_aclenv_t *t, dns_aclenv_t *s) {
0f80bfec687db08a6e6ce945ef1d818da06c7ca9Brian Wellington dns_acl_attach(s->localhost, &t->localhost);