acl.c revision 573d78f3d53859bc01ce5d5cebbaac9b8b90bfba
9178881e1bf6a4b01db886b355406c8bed61cc2aMichael Graff/*
499b34cea04a46823d003d4c0520c8b03e8513cbBrian Wellington * Copyright (C) 2004-2009, 2011, 2013 Internet Systems Consortium, Inc. ("ISC")
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence * Copyright (C) 1999-2002 Internet Software Consortium.
9178881e1bf6a4b01db886b355406c8bed61cc2aMichael Graff *
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 *
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.
9178881e1bf6a4b01db886b355406c8bed61cc2aMichael Graff */
9178881e1bf6a4b01db886b355406c8bed61cc2aMichael Graff
19c7cce8555ccc0c95455a0c35dedd017d420d05Mark Andrews/* $Id: acl.c,v 1.55 2011/06/17 23:47:49 tbox Exp $ */
9c3531d72aeaad6c5f01efe6a1c82023e1379e4dDavid Lawrence
9178881e1bf6a4b01db886b355406c8bed61cc2aMichael Graff/*! \file */
9178881e1bf6a4b01db886b355406c8bed61cc2aMichael Graff
9178881e1bf6a4b01db886b355406c8bed61cc2aMichael Graff#include <config.h>
9178881e1bf6a4b01db886b355406c8bed61cc2aMichael Graff
9178881e1bf6a4b01db886b355406c8bed61cc2aMichael Graff#include <isc/mem.h>
9178881e1bf6a4b01db886b355406c8bed61cc2aMichael Graff#include <isc/once.h>
1a69a1a78cfaa86f3b68bbc965232b7876d4da2aDavid Lawrence#include <isc/string.h>
6028d1ce0380d0ba7f6c6ecd1ad20b31ddd1becbDavid Lawrence#include <isc/util.h>
364a82f7c25b62967678027043425201a5e5171aBob Halley
c95a89b433e42ecf9108b6c263f405fecc0d8a65Michael Sawyer#include <dns/acl.h>
9178881e1bf6a4b01db886b355406c8bed61cc2aMichael Graff#include <dns/iptable.h>
09f22ac5b09e70bc526015f37168ba33e21ea91fDavid Lawrence
09f22ac5b09e70bc526015f37168ba33e21ea91fDavid Lawrence/*
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.
dc570b92f6cc60def4207733c7a194fbb69a4399Michael Sawyer */
294ae26fb3e1376b4c34c6b8d15737e39cc2cb48Andreas Gustafssonisc_result_t
f9df80f4348ef68043903efa08299480324f4823Michael Graffdns_acl_create(isc_mem_t *mctx, int n, dns_acl_t **target) {
f9df80f4348ef68043903efa08299480324f4823Michael Graff isc_result_t result;
09f22ac5b09e70bc526015f37168ba33e21ea91fDavid Lawrence dns_acl_t *acl;
0f80bfec687db08a6e6ce945ef1d818da06c7ca9Brian Wellington
09f22ac5b09e70bc526015f37168ba33e21ea91fDavid Lawrence /*
6d4886fa7430889a96dbf9b88a2a4eb6f9d04674Brian Wellington * Work around silly limitation of isc_mem_get().
b984520acca2532d048eae929dc0682dd334c7a3Brian Wellington */
9178881e1bf6a4b01db886b355406c8bed61cc2aMichael Graff if (n == 0)
75ec9bc9c7b4f2485647414330122e7b8e188097Andreas Gustafsson n = 1;
ac77fece9a62537a9e0e5852498ebeda7b2978c3Bob Halley
97e7d389d54a9e3a1ba8313ed140b04afabc7081Michael Graff acl = isc_mem_get(mctx, sizeof(*acl));
97e7d389d54a9e3a1ba8313ed140b04afabc7081Michael Graff if (acl == NULL)
ac77fece9a62537a9e0e5852498ebeda7b2978c3Bob Halley return (ISC_R_NOMEMORY);
ac77fece9a62537a9e0e5852498ebeda7b2978c3Bob Halley
ac77fece9a62537a9e0e5852498ebeda7b2978c3Bob Halley acl->mctx = NULL;
ac77fece9a62537a9e0e5852498ebeda7b2978c3Bob Halley isc_mem_attach(mctx, &acl->mctx);
f9df80f4348ef68043903efa08299480324f4823Michael Graff
f9df80f4348ef68043903efa08299480324f4823Michael Graff acl->name = NULL;
f9df80f4348ef68043903efa08299480324f4823Michael Graff
f9df80f4348ef68043903efa08299480324f4823Michael Graff result = isc_refcount_init(&acl->refcount, 1);
f9df80f4348ef68043903efa08299480324f4823Michael Graff if (result != ISC_R_SUCCESS) {
78838d3e0cd62423c23de5503910e01884d2104bBrian Wellington isc_mem_put(mctx, acl, sizeof(*acl));
78838d3e0cd62423c23de5503910e01884d2104bBrian Wellington return (result);
78838d3e0cd62423c23de5503910e01884d2104bBrian Wellington }
78838d3e0cd62423c23de5503910e01884d2104bBrian Wellington
1ed4ba5a1fcb6aecd1c92fdcc75c6b4bbb7cc60fMichael Sawyer result = dns_iptable_create(mctx, &acl->iptable);
1ed4ba5a1fcb6aecd1c92fdcc75c6b4bbb7cc60fMichael Sawyer if (result != ISC_R_SUCCESS) {
f9df80f4348ef68043903efa08299480324f4823Michael Graff isc_mem_put(mctx, acl, sizeof(*acl));
f9df80f4348ef68043903efa08299480324f4823Michael Graff return (result);
f9df80f4348ef68043903efa08299480324f4823Michael Graff }
f9df80f4348ef68043903efa08299480324f4823Michael Graff
97e7d389d54a9e3a1ba8313ed140b04afabc7081Michael Graff acl->elements = NULL;
f9df80f4348ef68043903efa08299480324f4823Michael Graff acl->alloc = 0;
e223094b2248afa2697c531f75e6f84855638becMichael Graff acl->length = 0;
b02262cbcd550c63f85df76edc6fff556ea5e95dMichael Graff acl->has_negatives = ISC_FALSE;
b02262cbcd550c63f85df76edc6fff556ea5e95dMichael Graff
b02262cbcd550c63f85df76edc6fff556ea5e95dMichael Graff ISC_LINK_INIT(acl, nextincache);
b02262cbcd550c63f85df76edc6fff556ea5e95dMichael Graff /*
f9df80f4348ef68043903efa08299480324f4823Michael Graff * Must set magic early because we use dns_acl_detach() to clean up.
c95a89b433e42ecf9108b6c263f405fecc0d8a65Michael Sawyer */
c95a89b433e42ecf9108b6c263f405fecc0d8a65Michael Sawyer acl->magic = DNS_ACL_MAGIC;
c95a89b433e42ecf9108b6c263f405fecc0d8a65Michael Sawyer
c95a89b433e42ecf9108b6c263f405fecc0d8a65Michael Sawyer acl->elements = isc_mem_get(mctx, n * sizeof(dns_aclelement_t));
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence if (acl->elements == NULL) {
c95a89b433e42ecf9108b6c263f405fecc0d8a65Michael Sawyer result = ISC_R_NOMEMORY;
c95a89b433e42ecf9108b6c263f405fecc0d8a65Michael Sawyer goto cleanup;
c95a89b433e42ecf9108b6c263f405fecc0d8a65Michael Sawyer }
c95a89b433e42ecf9108b6c263f405fecc0d8a65Michael Sawyer acl->alloc = n;
c95a89b433e42ecf9108b6c263f405fecc0d8a65Michael Sawyer memset(acl->elements, 0, n * sizeof(dns_aclelement_t));
c95a89b433e42ecf9108b6c263f405fecc0d8a65Michael Sawyer *target = acl;
58c40ca8bda08458804d7f15cf97942dea2a17acMichael Sawyer return (ISC_R_SUCCESS);
58c40ca8bda08458804d7f15cf97942dea2a17acMichael Sawyer
58c40ca8bda08458804d7f15cf97942dea2a17acMichael Sawyer cleanup:
58c40ca8bda08458804d7f15cf97942dea2a17acMichael Sawyer dns_acl_detach(&acl);
58c40ca8bda08458804d7f15cf97942dea2a17acMichael Sawyer return (result);
58c40ca8bda08458804d7f15cf97942dea2a17acMichael Sawyer}
58c40ca8bda08458804d7f15cf97942dea2a17acMichael Sawyer
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence/*
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 Sawyer */
c95a89b433e42ecf9108b6c263f405fecc0d8a65Michael Sawyerstatic isc_result_t
c95a89b433e42ecf9108b6c263f405fecc0d8a65Michael Sawyerdns_acl_anyornone(isc_mem_t *mctx, isc_boolean_t neg, dns_acl_t **target) {
c95a89b433e42ecf9108b6c263f405fecc0d8a65Michael Sawyer isc_result_t result;
c95a89b433e42ecf9108b6c263f405fecc0d8a65Michael Sawyer dns_acl_t *acl = NULL;
c95a89b433e42ecf9108b6c263f405fecc0d8a65Michael Sawyer
c95a89b433e42ecf9108b6c263f405fecc0d8a65Michael Sawyer result = dns_acl_create(mctx, 0, &acl);
c95a89b433e42ecf9108b6c263f405fecc0d8a65Michael Sawyer if (result != ISC_R_SUCCESS)
c95a89b433e42ecf9108b6c263f405fecc0d8a65Michael Sawyer return (result);
c95a89b433e42ecf9108b6c263f405fecc0d8a65Michael Sawyer
c95a89b433e42ecf9108b6c263f405fecc0d8a65Michael Sawyer result = dns_iptable_addprefix(acl->iptable, NULL, 0, ISC_TF(!neg));
c95a89b433e42ecf9108b6c263f405fecc0d8a65Michael Sawyer if (result != ISC_R_SUCCESS) {
c95a89b433e42ecf9108b6c263f405fecc0d8a65Michael Sawyer dns_acl_detach(&acl);
c95a89b433e42ecf9108b6c263f405fecc0d8a65Michael Sawyer return (result);
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence }
c95a89b433e42ecf9108b6c263f405fecc0d8a65Michael Sawyer
c95a89b433e42ecf9108b6c263f405fecc0d8a65Michael Sawyer *target = acl;
c95a89b433e42ecf9108b6c263f405fecc0d8a65Michael Sawyer return (result);
c95a89b433e42ecf9108b6c263f405fecc0d8a65Michael Sawyer}
c95a89b433e42ecf9108b6c263f405fecc0d8a65Michael Sawyer
c95a89b433e42ecf9108b6c263f405fecc0d8a65Michael Sawyer/*
c95a89b433e42ecf9108b6c263f405fecc0d8a65Michael Sawyer * Create a new ACL that matches everything.
c95a89b433e42ecf9108b6c263f405fecc0d8a65Michael Sawyer */
c95a89b433e42ecf9108b6c263f405fecc0d8a65Michael Sawyerisc_result_t
c95a89b433e42ecf9108b6c263f405fecc0d8a65Michael Sawyerdns_acl_any(isc_mem_t *mctx, dns_acl_t **target) {
c95a89b433e42ecf9108b6c263f405fecc0d8a65Michael Sawyer return (dns_acl_anyornone(mctx, ISC_FALSE, target));
c95a89b433e42ecf9108b6c263f405fecc0d8a65Michael Sawyer}
c95a89b433e42ecf9108b6c263f405fecc0d8a65Michael Sawyer
c95a89b433e42ecf9108b6c263f405fecc0d8a65Michael Sawyer/*
c95a89b433e42ecf9108b6c263f405fecc0d8a65Michael Sawyer * Create a new ACL that matches nothing.
c95a89b433e42ecf9108b6c263f405fecc0d8a65Michael Sawyer */
c95a89b433e42ecf9108b6c263f405fecc0d8a65Michael Sawyerisc_result_t
c95a89b433e42ecf9108b6c263f405fecc0d8a65Michael Sawyerdns_acl_none(isc_mem_t *mctx, dns_acl_t **target) {
c95a89b433e42ecf9108b6c263f405fecc0d8a65Michael Sawyer return (dns_acl_anyornone(mctx, ISC_TRUE, target));
c95a89b433e42ecf9108b6c263f405fecc0d8a65Michael Sawyer}
f9df80f4348ef68043903efa08299480324f4823Michael Graff
f9df80f4348ef68043903efa08299480324f4823Michael Graff/*
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; }"
f9df80f4348ef68043903efa08299480324f4823Michael Graff */
f9df80f4348ef68043903efa08299480324f4823Michael Graffstatic isc_boolean_t
97e7d389d54a9e3a1ba8313ed140b04afabc7081Michael Graffdns_acl_isanyornone(dns_acl_t *acl, isc_boolean_t pos)
f9df80f4348ef68043903efa08299480324f4823Michael Graff{
f9df80f4348ef68043903efa08299480324f4823Michael Graff /* Should never happen but let's be safe */
f9df80f4348ef68043903efa08299480324f4823Michael Graff if (acl == NULL ||
9178881e1bf6a4b01db886b355406c8bed61cc2aMichael Graff acl->iptable == NULL ||
97e7d389d54a9e3a1ba8313ed140b04afabc7081Michael Graff acl->iptable->radix == NULL ||
97e7d389d54a9e3a1ba8313ed140b04afabc7081Michael Graff acl->iptable->radix->head == NULL ||
fccf7905e8a06067d49ec00c53d4d57a38a71e52Michael Graff acl->iptable->radix->head->prefix == NULL)
f9df80f4348ef68043903efa08299480324f4823Michael Graff return (ISC_FALSE);
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff
9178881e1bf6a4b01db886b355406c8bed61cc2aMichael Graff if (acl->length != 0 || acl->node_count != 1)
9178881e1bf6a4b01db886b355406c8bed61cc2aMichael Graff return (ISC_FALSE);
f9df80f4348ef68043903efa08299480324f4823Michael Graff
f9df80f4348ef68043903efa08299480324f4823Michael Graff if (acl->iptable->radix->head->prefix->bitlen == 0 &&
f9df80f4348ef68043903efa08299480324f4823Michael Graff acl->iptable->radix->head->data[0] != NULL &&
97e7d389d54a9e3a1ba8313ed140b04afabc7081Michael Graff acl->iptable->radix->head->data[0] ==
9178881e1bf6a4b01db886b355406c8bed61cc2aMichael Graff acl->iptable->radix->head->data[1] &&
97e7d389d54a9e3a1ba8313ed140b04afabc7081Michael Graff *(isc_boolean_t *) (acl->iptable->radix->head->data[0]) == pos)
97e7d389d54a9e3a1ba8313ed140b04afabc7081Michael Graff return (ISC_TRUE);
9178881e1bf6a4b01db886b355406c8bed61cc2aMichael Graff
9178881e1bf6a4b01db886b355406c8bed61cc2aMichael Graff return (ISC_FALSE); /* All others */
9178881e1bf6a4b01db886b355406c8bed61cc2aMichael Graff}
9178881e1bf6a4b01db886b355406c8bed61cc2aMichael Graff
9178881e1bf6a4b01db886b355406c8bed61cc2aMichael Graff/*
9178881e1bf6a4b01db886b355406c8bed61cc2aMichael Graff * Test whether acl is set to "{ any; }"
f9df80f4348ef68043903efa08299480324f4823Michael Graff */
f9df80f4348ef68043903efa08299480324f4823Michael Graffisc_boolean_t
9178881e1bf6a4b01db886b355406c8bed61cc2aMichael Graffdns_acl_isany(dns_acl_t *acl)
9178881e1bf6a4b01db886b355406c8bed61cc2aMichael Graff{
9178881e1bf6a4b01db886b355406c8bed61cc2aMichael Graff return (dns_acl_isanyornone(acl, ISC_TRUE));
9178881e1bf6a4b01db886b355406c8bed61cc2aMichael Graff}
9178881e1bf6a4b01db886b355406c8bed61cc2aMichael Graff
9178881e1bf6a4b01db886b355406c8bed61cc2aMichael Graff/*
9178881e1bf6a4b01db886b355406c8bed61cc2aMichael Graff * Test whether acl is set to "{ none; }"
9178881e1bf6a4b01db886b355406c8bed61cc2aMichael Graff */
97e7d389d54a9e3a1ba8313ed140b04afabc7081Michael Graffisc_boolean_t
9178881e1bf6a4b01db886b355406c8bed61cc2aMichael Graffdns_acl_isnone(dns_acl_t *acl)
97e7d389d54a9e3a1ba8313ed140b04afabc7081Michael Graff{
9178881e1bf6a4b01db886b355406c8bed61cc2aMichael Graff return (dns_acl_isanyornone(acl, ISC_FALSE));
9178881e1bf6a4b01db886b355406c8bed61cc2aMichael Graff}
9178881e1bf6a4b01db886b355406c8bed61cc2aMichael Graff
9178881e1bf6a4b01db886b355406c8bed61cc2aMichael Graff/*
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 */
9178881e1bf6a4b01db886b355406c8bed61cc2aMichael Graffisc_result_t
9178881e1bf6a4b01db886b355406c8bed61cc2aMichael Graffdns_acl_match(const isc_netaddr_t *reqaddr,
9178881e1bf6a4b01db886b355406c8bed61cc2aMichael Graff const dns_name_t *reqsigner,
1a69a1a78cfaa86f3b68bbc965232b7876d4da2aDavid Lawrence const dns_acl_t *acl,
9178881e1bf6a4b01db886b355406c8bed61cc2aMichael Graff const dns_aclenv_t *env,
9178881e1bf6a4b01db886b355406c8bed61cc2aMichael Graff int *match,
8c55a67a6d185de7036e39da30561a5c1637d22bAndreas Gustafsson const dns_aclelement_t **matchelt)
9178881e1bf6a4b01db886b355406c8bed61cc2aMichael Graff{
9178881e1bf6a4b01db886b355406c8bed61cc2aMichael Graff isc_uint16_t bitlen, family;
9178881e1bf6a4b01db886b355406c8bed61cc2aMichael Graff isc_prefix_t pfx;
9178881e1bf6a4b01db886b355406c8bed61cc2aMichael Graff isc_radix_node_t *node = NULL;
9178881e1bf6a4b01db886b355406c8bed61cc2aMichael Graff const isc_netaddr_t *addr;
9178881e1bf6a4b01db886b355406c8bed61cc2aMichael Graff isc_netaddr_t v4addr;
9178881e1bf6a4b01db886b355406c8bed61cc2aMichael Graff isc_result_t result;
9178881e1bf6a4b01db886b355406c8bed61cc2aMichael Graff int match_num = -1;
9178881e1bf6a4b01db886b355406c8bed61cc2aMichael Graff unsigned int i;
9178881e1bf6a4b01db886b355406c8bed61cc2aMichael Graff
9178881e1bf6a4b01db886b355406c8bed61cc2aMichael Graff REQUIRE(reqaddr != NULL);
f9df80f4348ef68043903efa08299480324f4823Michael Graff REQUIRE(matchelt == NULL || *matchelt == NULL);
1a69a1a78cfaa86f3b68bbc965232b7876d4da2aDavid Lawrence
97e7d389d54a9e3a1ba8313ed140b04afabc7081Michael Graff if (env == NULL || env->match_mapped == ISC_FALSE ||
f9df80f4348ef68043903efa08299480324f4823Michael Graff reqaddr->family != AF_INET6 ||
f9df80f4348ef68043903efa08299480324f4823Michael Graff !IN6_IS_ADDR_V4MAPPED(&reqaddr->type.in6))
9178881e1bf6a4b01db886b355406c8bed61cc2aMichael Graff addr = reqaddr;
9178881e1bf6a4b01db886b355406c8bed61cc2aMichael Graff else {
9178881e1bf6a4b01db886b355406c8bed61cc2aMichael Graff isc_netaddr_fromv4mapped(&v4addr, reqaddr);
9178881e1bf6a4b01db886b355406c8bed61cc2aMichael Graff addr = &v4addr;
1a69a1a78cfaa86f3b68bbc965232b7876d4da2aDavid Lawrence }
9178881e1bf6a4b01db886b355406c8bed61cc2aMichael Graff
97e7d389d54a9e3a1ba8313ed140b04afabc7081Michael Graff /* Always match with host addresses. */
97e7d389d54a9e3a1ba8313ed140b04afabc7081Michael Graff family = addr->family;
97e7d389d54a9e3a1ba8313ed140b04afabc7081Michael Graff bitlen = family == AF_INET6 ? 128 : 32;
97e7d389d54a9e3a1ba8313ed140b04afabc7081Michael Graff NETADDR_TO_PREFIX_T(addr, pfx, bitlen);
97e7d389d54a9e3a1ba8313ed140b04afabc7081Michael Graff
9178881e1bf6a4b01db886b355406c8bed61cc2aMichael Graff /* Assume no match. */
f9df80f4348ef68043903efa08299480324f4823Michael Graff *match = 0;
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff /* Search radix. */
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff result = isc_radix_search(acl->iptable->radix, &node, &pfx);
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff /* Found a match. */
3ddd814a97de1d152ba0913c592d6e6dc83d38a6Michael Graff if (result == ISC_R_SUCCESS && node != NULL) {
1a69a1a78cfaa86f3b68bbc965232b7876d4da2aDavid Lawrence match_num = node->node_num[ISC_IS6(family)];
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff if (*(isc_boolean_t *) node->data[ISC_IS6(family)] == ISC_TRUE)
4556681e191b7c1654639895ce719d98f2822ee2Michael Graff *match = match_num;
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff else
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff *match = -match_num;
6e49e91bd08778d7eae45a2229dcf41ed97cc636David Lawrence }
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff /* Now search non-radix elements for a match with a lower node_num. */
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff for (i = 0; i < acl->length; i++) {
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff dns_aclelement_t *e = &acl->elements[i];
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff /* Already found a better match? */
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff if (match_num != -1 && match_num < e->node_num) {
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff isc_refcount_destroy(&pfx.refcount);
1a69a1a78cfaa86f3b68bbc965232b7876d4da2aDavid Lawrence return (ISC_R_SUCCESS);
4556681e191b7c1654639895ce719d98f2822ee2Michael Graff }
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff if (dns_aclelement_match(reqaddr, reqsigner,
97e7d389d54a9e3a1ba8313ed140b04afabc7081Michael Graff e, env, matchelt)) {
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff if (match_num == -1 || e->node_num < match_num) {
4556681e191b7c1654639895ce719d98f2822ee2Michael Graff if (e->negative == ISC_TRUE)
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff *match = -e->node_num;
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff else
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff *match = e->node_num;
1a69a1a78cfaa86f3b68bbc965232b7876d4da2aDavid Lawrence }
70fd62761dfe44f2254fb63ac3ded1b02663713fMichael Graff isc_refcount_destroy(&pfx.refcount);
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff return (ISC_R_SUCCESS);
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff }
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff }
1a69a1a78cfaa86f3b68bbc965232b7876d4da2aDavid Lawrence
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff isc_refcount_destroy(&pfx.refcount);
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff return (ISC_R_SUCCESS);
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff}
70fd62761dfe44f2254fb63ac3ded1b02663713fMichael Graff
70fd62761dfe44f2254fb63ac3ded1b02663713fMichael Graff/*
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 *
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 Graff */
d68838693666ba930ec4143f848c18bff2bfc244Michael Graffisc_result_t
d68838693666ba930ec4143f848c18bff2bfc244Michael Graffdns_acl_merge(dns_acl_t *dest, dns_acl_t *source, isc_boolean_t pos)
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff{
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff isc_result_t result;
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff unsigned int newalloc, nelem, i;
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff int max_node = 0, nodes;
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff /* Resize the element array if needed. */
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff if (dest->length + source->length > dest->alloc) {
5e589b5356a4125b5af32605dead82ab8b467c88Mark Andrews void *newmem;
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff newalloc = dest->alloc + source->alloc;
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff if (newalloc < 4)
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff newalloc = 4;
1a69a1a78cfaa86f3b68bbc965232b7876d4da2aDavid Lawrence
70fd62761dfe44f2254fb63ac3ded1b02663713fMichael Graff newmem = isc_mem_get(dest->mctx,
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff newalloc * sizeof(dns_aclelement_t));
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff if (newmem == NULL)
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff return (ISC_R_NOMEMORY);
1a69a1a78cfaa86f3b68bbc965232b7876d4da2aDavid Lawrence
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff /* Copy in the original elements */
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff memcpy(newmem, dest->elements,
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff dest->length * sizeof(dns_aclelement_t));
70fd62761dfe44f2254fb63ac3ded1b02663713fMichael Graff
70fd62761dfe44f2254fb63ac3ded1b02663713fMichael Graff /* Release the memory for the old elements array */
70fd62761dfe44f2254fb63ac3ded1b02663713fMichael Graff isc_mem_put(dest->mctx, dest->elements,
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff dest->alloc * sizeof(dns_aclelement_t));
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff dest->elements = newmem;
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff dest->alloc = newalloc;
97e7d389d54a9e3a1ba8313ed140b04afabc7081Michael Graff }
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff /*
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 */
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff nelem = dest->length;
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff dest->length += source->length;
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff for (i = 0; i < source->length; i++) {
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff if (source->elements[i].node_num > max_node)
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff max_node = source->elements[i].node_num;
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff /* Copy type. */
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff dest->elements[nelem + i].type = source->elements[i].type;
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff
f9df80f4348ef68043903efa08299480324f4823Michael Graff /* Adjust node numbering. */
1a69a1a78cfaa86f3b68bbc965232b7876d4da2aDavid Lawrence dest->elements[nelem + i].node_num =
f9df80f4348ef68043903efa08299480324f4823Michael Graff source->elements[i].node_num + dest->node_count;
f9df80f4348ef68043903efa08299480324f4823Michael Graff
f9df80f4348ef68043903efa08299480324f4823Michael Graff /* Duplicate nested acl. */
f9df80f4348ef68043903efa08299480324f4823Michael Graff if (source->elements[i].type == dns_aclelementtype_nestedacl &&
e223094b2248afa2697c531f75e6f84855638becMichael Graff source->elements[i].nestedacl != NULL)
d8705ff90a299e0aa9fc2b4286bc0a71cf221872Bob Halley dns_acl_attach(source->elements[i].nestedacl,
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff &dest->elements[nelem + i].nestedacl);
d8705ff90a299e0aa9fc2b4286bc0a71cf221872Bob Halley
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,
d68838693666ba930ec4143f848c18bff2bfc244Michael Graff dest->mctx,
823e45c1273512a8048cd5e7e57f31f58c964f7fMichael Graff &dest->elements[nelem+i].keyname);
e223094b2248afa2697c531f75e6f84855638becMichael Graff if (result != ISC_R_SUCCESS)
2726950412a5c598e123554e4d758fe66a2ebc21Michael Graff return result;
5caab9f99d19ab9ebb0a0ba64c09c8de80e89e29Brian Wellington }
41faaa9b35bb5b3c72ca964e108ba398eaa63f3dBrian Wellington
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;
5eb8688b78ddf13d46cd52561301c35d24a5d52aBob Halley } else {
0f80bfec687db08a6e6ce945ef1d818da06c7ca9Brian Wellington dest->elements[nelem + i].negative =
97e7d389d54a9e3a1ba8313ed140b04afabc7081Michael Graff source->elements[i].negative;
e690d225ad09e0b4617554c753b68abc82f0583aMichael Graff }
70fd62761dfe44f2254fb63ac3ded1b02663713fMichael Graff }
f9df80f4348ef68043903efa08299480324f4823Michael Graff
f9df80f4348ef68043903efa08299480324f4823Michael Graff /*
6d4886fa7430889a96dbf9b88a2a4eb6f9d04674Brian Wellington * Merge the iptables. Make sure the destination ACL's
1a69a1a78cfaa86f3b68bbc965232b7876d4da2aDavid Lawrence * node_count value is set correctly afterward.
0f80bfec687db08a6e6ce945ef1d818da06c7ca9Brian Wellington */
0f80bfec687db08a6e6ce945ef1d818da06c7ca9Brian Wellington nodes = max_node + dest->node_count;
6d4886fa7430889a96dbf9b88a2a4eb6f9d04674Brian Wellington result = dns_iptable_merge(dest->iptable, source->iptable, pos);
24694ab18a48bcc9c50304bd8b7eb6b9c7650129Brian Wellington if (result != ISC_R_SUCCESS)
0b764d91c9021259f15b32c4beec852f2888f40cBrian Wellington return (result);
0b764d91c9021259f15b32c4beec852f2888f40cBrian Wellington if (nodes > dest->node_count)
0b764d91c9021259f15b32c4beec852f2888f40cBrian Wellington dest->node_count = nodes;
19c7cce8555ccc0c95455a0c35dedd017d420d05Mark Andrews
6d4886fa7430889a96dbf9b88a2a4eb6f9d04674Brian Wellington return (ISC_R_SUCCESS);
6d4886fa7430889a96dbf9b88a2a4eb6f9d04674Brian Wellington}
f9df80f4348ef68043903efa08299480324f4823Michael Graff
d8705ff90a299e0aa9fc2b4286bc0a71cf221872Bob Halley/*
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.
d8705ff90a299e0aa9fc2b4286bc0a71cf221872Bob Halley *
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.
996028142c5f95492fcd42e69186b95641320c7bBob Halley */
996028142c5f95492fcd42e69186b95641320c7bBob Halleyisc_boolean_t
24694ab18a48bcc9c50304bd8b7eb6b9c7650129Brian Wellingtondns_aclelement_match(const isc_netaddr_t *reqaddr,
f7fbd68b1cd96c733140fce938a61faf8b459b6fBrian Wellington const dns_name_t *reqsigner,
f7fbd68b1cd96c733140fce938a61faf8b459b6fBrian Wellington const dns_aclelement_t *e,
febaa091847ab004f40500cc475a819f2c73fcddAndreas Gustafsson const dns_aclenv_t *env,
febaa091847ab004f40500cc475a819f2c73fcddAndreas Gustafsson const dns_aclelement_t **matchelt)
efcd38346161b10d60368411cfb2c0d1c22b5fb1Brian Wellington{
efcd38346161b10d60368411cfb2c0d1c22b5fb1Brian Wellington dns_acl_t *inner = NULL;
efcd38346161b10d60368411cfb2c0d1c22b5fb1Brian Wellington int indirectmatch;
efcd38346161b10d60368411cfb2c0d1c22b5fb1Brian Wellington isc_result_t result;
efcd38346161b10d60368411cfb2c0d1c22b5fb1Brian Wellington
efcd38346161b10d60368411cfb2c0d1c22b5fb1Brian Wellington switch (e->type) {
efcd38346161b10d60368411cfb2c0d1c22b5fb1Brian Wellington case dns_aclelementtype_keyname:
d8705ff90a299e0aa9fc2b4286bc0a71cf221872Bob Halley if (reqsigner != NULL &&
d8705ff90a299e0aa9fc2b4286bc0a71cf221872Bob Halley dns_name_equal(reqsigner, &e->keyname)) {
d8705ff90a299e0aa9fc2b4286bc0a71cf221872Bob Halley if (matchelt != NULL)
d8705ff90a299e0aa9fc2b4286bc0a71cf221872Bob Halley *matchelt = e;
f9df80f4348ef68043903efa08299480324f4823Michael Graff return (ISC_TRUE);
d8705ff90a299e0aa9fc2b4286bc0a71cf221872Bob Halley } else {
d8705ff90a299e0aa9fc2b4286bc0a71cf221872Bob Halley return (ISC_FALSE);
f9df80f4348ef68043903efa08299480324f4823Michael Graff }
f9df80f4348ef68043903efa08299480324f4823Michael Graff
f9df80f4348ef68043903efa08299480324f4823Michael Graff case dns_aclelementtype_nestedacl:
f9df80f4348ef68043903efa08299480324f4823Michael Graff inner = e->nestedacl;
d8705ff90a299e0aa9fc2b4286bc0a71cf221872Bob Halley break;
f9df80f4348ef68043903efa08299480324f4823Michael Graff
f9df80f4348ef68043903efa08299480324f4823Michael Graff case dns_aclelementtype_localhost:
f9df80f4348ef68043903efa08299480324f4823Michael Graff if (env == NULL || env->localhost == NULL)
f9df80f4348ef68043903efa08299480324f4823Michael Graff return (ISC_FALSE);
f9df80f4348ef68043903efa08299480324f4823Michael Graff inner = env->localhost;
f9df80f4348ef68043903efa08299480324f4823Michael Graff break;
f9df80f4348ef68043903efa08299480324f4823Michael Graff
f9df80f4348ef68043903efa08299480324f4823Michael Graff case dns_aclelementtype_localnets:
f9df80f4348ef68043903efa08299480324f4823Michael Graff if (env == NULL || env->localnets == NULL)
f9df80f4348ef68043903efa08299480324f4823Michael Graff return (ISC_FALSE);
f2762b0d99a9f1cc43f57f713aa632f6abe37892Michael Graff inner = env->localnets;
f9df80f4348ef68043903efa08299480324f4823Michael Graff break;
d8f304288d2fb29fccd2da1672d72ea06af73f8dMichael Graff
f9df80f4348ef68043903efa08299480324f4823Michael Graff default:
f9df80f4348ef68043903efa08299480324f4823Michael Graff /* Should be impossible. */
d2762d6c3797b1ce43965404d03b410f215932e0Michael Graff INSIST(0);
d2762d6c3797b1ce43965404d03b410f215932e0Michael Graff }
af6e7e5cd2643e2aaaffefe1dd804a03394b4928Michael Graff
fccf7905e8a06067d49ec00c53d4d57a38a71e52Michael Graff result = dns_acl_match(reqaddr, reqsigner, inner, env,
f9df80f4348ef68043903efa08299480324f4823Michael Graff &indirectmatch, matchelt);
f9df80f4348ef68043903efa08299480324f4823Michael Graff INSIST(result == ISC_R_SUCCESS);
d8705ff90a299e0aa9fc2b4286bc0a71cf221872Bob Halley
d8705ff90a299e0aa9fc2b4286bc0a71cf221872Bob Halley /*
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 */
5eb8688b78ddf13d46cd52561301c35d24a5d52aBob Halley
5eb8688b78ddf13d46cd52561301c35d24a5d52aBob Halley if (indirectmatch > 0) {
5eb8688b78ddf13d46cd52561301c35d24a5d52aBob Halley if (matchelt != NULL)
5eb8688b78ddf13d46cd52561301c35d24a5d52aBob Halley *matchelt = e;
5eb8688b78ddf13d46cd52561301c35d24a5d52aBob Halley return (ISC_TRUE);
5eb8688b78ddf13d46cd52561301c35d24a5d52aBob Halley }
5eb8688b78ddf13d46cd52561301c35d24a5d52aBob Halley
5eb8688b78ddf13d46cd52561301c35d24a5d52aBob Halley /*
5eb8688b78ddf13d46cd52561301c35d24a5d52aBob Halley * A negative indirect match may have set *matchelt, but we don't
5eb8688b78ddf13d46cd52561301c35d24a5d52aBob Halley * want it set when we return.
5caab9f99d19ab9ebb0a0ba64c09c8de80e89e29Brian Wellington */
0f80bfec687db08a6e6ce945ef1d818da06c7ca9Brian Wellington
0f80bfec687db08a6e6ce945ef1d818da06c7ca9Brian Wellington if (matchelt != NULL)
0f80bfec687db08a6e6ce945ef1d818da06c7ca9Brian Wellington *matchelt = NULL;
0f80bfec687db08a6e6ce945ef1d818da06c7ca9Brian Wellington
0f80bfec687db08a6e6ce945ef1d818da06c7ca9Brian Wellington return (ISC_FALSE);
fe0e3c7707580da885bb6819e4f307986eb60cd0Brian Wellington}
fe0e3c7707580da885bb6819e4f307986eb60cd0Brian Wellington
5caab9f99d19ab9ebb0a0ba64c09c8de80e89e29Brian Wellingtonvoid
0f80bfec687db08a6e6ce945ef1d818da06c7ca9Brian Wellingtondns_acl_attach(dns_acl_t *source, dns_acl_t **target) {
fe0e3c7707580da885bb6819e4f307986eb60cd0Brian Wellington REQUIRE(DNS_ACL_VALID(source));
fe0e3c7707580da885bb6819e4f307986eb60cd0Brian Wellington
0f80bfec687db08a6e6ce945ef1d818da06c7ca9Brian Wellington isc_refcount_increment(&source->refcount, NULL);
fe0e3c7707580da885bb6819e4f307986eb60cd0Brian Wellington *target = source;
fe0e3c7707580da885bb6819e4f307986eb60cd0Brian Wellington}
fe0e3c7707580da885bb6819e4f307986eb60cd0Brian Wellington
fe0e3c7707580da885bb6819e4f307986eb60cd0Brian Wellingtonstatic void
fe0e3c7707580da885bb6819e4f307986eb60cd0Brian Wellingtondestroy(dns_acl_t *dacl) {
0f80bfec687db08a6e6ce945ef1d818da06c7ca9Brian Wellington unsigned int i;
0f80bfec687db08a6e6ce945ef1d818da06c7ca9Brian Wellington
d1cbf714097e900ed1703529584d3e1a50e8a4a8Brian Wellington INSIST(!ISC_LINK_LINKED(dacl, nextincache));
d1cbf714097e900ed1703529584d3e1a50e8a4a8Brian Wellington
5caab9f99d19ab9ebb0a0ba64c09c8de80e89e29Brian Wellington for (i = 0; i < dacl->length; i++) {
fe0e3c7707580da885bb6819e4f307986eb60cd0Brian Wellington dns_aclelement_t *de = &dacl->elements[i];
5caab9f99d19ab9ebb0a0ba64c09c8de80e89e29Brian Wellington if (de->type == dns_aclelementtype_keyname) {
6dc130c7c95107748fff5f767161c2bb742f9f87Brian Wellington dns_name_free(&de->keyname, dacl->mctx);
22057930cd2a71e1073781b650c7296739c869a6Brian Wellington } else if (de->type == dns_aclelementtype_nestedacl) {
22057930cd2a71e1073781b650c7296739c869a6Brian Wellington dns_acl_detach(&de->nestedacl);
6dc130c7c95107748fff5f767161c2bb742f9f87Brian Wellington }
5caab9f99d19ab9ebb0a0ba64c09c8de80e89e29Brian Wellington }
5caab9f99d19ab9ebb0a0ba64c09c8de80e89e29Brian Wellington if (dacl->elements != NULL)
5caab9f99d19ab9ebb0a0ba64c09c8de80e89e29Brian Wellington isc_mem_put(dacl->mctx, dacl->elements,
5caab9f99d19ab9ebb0a0ba64c09c8de80e89e29Brian Wellington dacl->alloc * sizeof(dns_aclelement_t));
5caab9f99d19ab9ebb0a0ba64c09c8de80e89e29Brian Wellington if (dacl->name != NULL)
d1cbf714097e900ed1703529584d3e1a50e8a4a8Brian Wellington isc_mem_free(dacl->mctx, dacl->name);
d1cbf714097e900ed1703529584d3e1a50e8a4a8Brian Wellington if (dacl->iptable != NULL)
d1cbf714097e900ed1703529584d3e1a50e8a4a8Brian Wellington dns_iptable_detach(&dacl->iptable);
41faaa9b35bb5b3c72ca964e108ba398eaa63f3dBrian Wellington isc_refcount_destroy(&dacl->refcount);
d1cbf714097e900ed1703529584d3e1a50e8a4a8Brian Wellington dacl->magic = 0;
5caab9f99d19ab9ebb0a0ba64c09c8de80e89e29Brian Wellington isc_mem_putanddetach(&dacl->mctx, dacl, sizeof(*dacl));
41faaa9b35bb5b3c72ca964e108ba398eaa63f3dBrian Wellington}
5caab9f99d19ab9ebb0a0ba64c09c8de80e89e29Brian Wellington
5caab9f99d19ab9ebb0a0ba64c09c8de80e89e29Brian Wellingtonvoid
5caab9f99d19ab9ebb0a0ba64c09c8de80e89e29Brian Wellingtondns_acl_detach(dns_acl_t **aclp) {
d8705ff90a299e0aa9fc2b4286bc0a71cf221872Bob Halley dns_acl_t *acl = *aclp;
d8705ff90a299e0aa9fc2b4286bc0a71cf221872Bob Halley unsigned int refs;
febaa091847ab004f40500cc475a819f2c73fcddAndreas Gustafsson
d8705ff90a299e0aa9fc2b4286bc0a71cf221872Bob Halley REQUIRE(DNS_ACL_VALID(acl));
d8705ff90a299e0aa9fc2b4286bc0a71cf221872Bob Halley
1a69a1a78cfaa86f3b68bbc965232b7876d4da2aDavid Lawrence isc_refcount_decrement(&acl->refcount, &refs);
d8705ff90a299e0aa9fc2b4286bc0a71cf221872Bob Halley if (refs == 0)
4556681e191b7c1654639895ce719d98f2822ee2Michael Graff destroy(acl);
d8705ff90a299e0aa9fc2b4286bc0a71cf221872Bob Halley *aclp = NULL;
d8705ff90a299e0aa9fc2b4286bc0a71cf221872Bob Halley}
d8705ff90a299e0aa9fc2b4286bc0a71cf221872Bob Halley
d8705ff90a299e0aa9fc2b4286bc0a71cf221872Bob Halley
5eb8688b78ddf13d46cd52561301c35d24a5d52aBob Halleystatic isc_once_t insecure_prefix_once = ISC_ONCE_INIT;
0f80bfec687db08a6e6ce945ef1d818da06c7ca9Brian Wellingtonstatic isc_mutex_t insecure_prefix_lock;
ac77fece9a62537a9e0e5852498ebeda7b2978c3Bob Halleystatic isc_boolean_t insecure_prefix_found;
f9df80f4348ef68043903efa08299480324f4823Michael Graff
f9df80f4348ef68043903efa08299480324f4823Michael Graffstatic void
f9df80f4348ef68043903efa08299480324f4823Michael Graffinitialize_action(void) {
f9df80f4348ef68043903efa08299480324f4823Michael Graff RUNTIME_CHECK(isc_mutex_init(&insecure_prefix_lock) == ISC_R_SUCCESS);
70fd62761dfe44f2254fb63ac3ded1b02663713fMichael Graff}
70fd62761dfe44f2254fb63ac3ded1b02663713fMichael Graff
70fd62761dfe44f2254fb63ac3ded1b02663713fMichael Graff/*
70fd62761dfe44f2254fb63ac3ded1b02663713fMichael Graff * Called via isc_radix_walk() to find IP table nodes that are
70fd62761dfe44f2254fb63ac3ded1b02663713fMichael Graff * insecure.
70fd62761dfe44f2254fb63ac3ded1b02663713fMichael Graff */
70fd62761dfe44f2254fb63ac3ded1b02663713fMichael Graffstatic void
70fd62761dfe44f2254fb63ac3ded1b02663713fMichael Graffis_insecure(isc_prefix_t *prefix, void **data) {
70fd62761dfe44f2254fb63ac3ded1b02663713fMichael Graff isc_boolean_t secure;
70fd62761dfe44f2254fb63ac3ded1b02663713fMichael Graff int bitlen, family;
70fd62761dfe44f2254fb63ac3ded1b02663713fMichael Graff
70fd62761dfe44f2254fb63ac3ded1b02663713fMichael Graff bitlen = prefix->bitlen;
70fd62761dfe44f2254fb63ac3ded1b02663713fMichael Graff family = prefix->family;
70fd62761dfe44f2254fb63ac3ded1b02663713fMichael Graff
70fd62761dfe44f2254fb63ac3ded1b02663713fMichael Graff /* Negated entries are always secure. */
70fd62761dfe44f2254fb63ac3ded1b02663713fMichael Graff secure = * (isc_boolean_t *)data[ISC_IS6(family)];
f9df80f4348ef68043903efa08299480324f4823Michael Graff if (!secure) {
f9df80f4348ef68043903efa08299480324f4823Michael Graff return;
97e7d389d54a9e3a1ba8313ed140b04afabc7081Michael Graff }
4556681e191b7c1654639895ce719d98f2822ee2Michael Graff
f9df80f4348ef68043903efa08299480324f4823Michael Graff /* If loopback prefix found, return */
f9df80f4348ef68043903efa08299480324f4823Michael Graff switch (family) {
f9df80f4348ef68043903efa08299480324f4823Michael Graff case AF_INET:
f9df80f4348ef68043903efa08299480324f4823Michael Graff if (bitlen == 32 &&
f9df80f4348ef68043903efa08299480324f4823Michael Graff htonl(prefix->add.sin.s_addr) == INADDR_LOOPBACK)
4556681e191b7c1654639895ce719d98f2822ee2Michael Graff return;
f9df80f4348ef68043903efa08299480324f4823Michael Graff break;
f9df80f4348ef68043903efa08299480324f4823Michael Graff case AF_INET6:
f9df80f4348ef68043903efa08299480324f4823Michael Graff if (bitlen == 128 && IN6_IS_ADDR_LOOPBACK(&prefix->add.sin6))
f9df80f4348ef68043903efa08299480324f4823Michael Graff return;
f9df80f4348ef68043903efa08299480324f4823Michael Graff break;
97e7d389d54a9e3a1ba8313ed140b04afabc7081Michael Graff default:
97e7d389d54a9e3a1ba8313ed140b04afabc7081Michael Graff break;
f9df80f4348ef68043903efa08299480324f4823Michael Graff }
f9df80f4348ef68043903efa08299480324f4823Michael Graff
f9df80f4348ef68043903efa08299480324f4823Michael Graff /* Non-negated, non-loopback */
f9df80f4348ef68043903efa08299480324f4823Michael Graff insecure_prefix_found = ISC_TRUE; /* LOCKED */
f9df80f4348ef68043903efa08299480324f4823Michael Graff return;
97e7d389d54a9e3a1ba8313ed140b04afabc7081Michael Graff}
f9df80f4348ef68043903efa08299480324f4823Michael Graff
f9df80f4348ef68043903efa08299480324f4823Michael Graff/*
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.
97e7d389d54a9e3a1ba8313ed140b04afabc7081Michael Graff */
97e7d389d54a9e3a1ba8313ed140b04afabc7081Michael Graffisc_boolean_t
ddd035637d92035a0d9e2bc32a7e2c9cc8a99d3fMichael Graffdns_acl_isinsecure(const dns_acl_t *a) {
ddd035637d92035a0d9e2bc32a7e2c9cc8a99d3fMichael Graff unsigned int i;
ddd035637d92035a0d9e2bc32a7e2c9cc8a99d3fMichael Graff isc_boolean_t insecure;
ddd035637d92035a0d9e2bc32a7e2c9cc8a99d3fMichael Graff
ddd035637d92035a0d9e2bc32a7e2c9cc8a99d3fMichael Graff RUNTIME_CHECK(isc_once_do(&insecure_prefix_once,
97e7d389d54a9e3a1ba8313ed140b04afabc7081Michael Graff initialize_action) == ISC_R_SUCCESS);
ddd035637d92035a0d9e2bc32a7e2c9cc8a99d3fMichael Graff
f9df80f4348ef68043903efa08299480324f4823Michael Graff /*
f9df80f4348ef68043903efa08299480324f4823Michael Graff * Walk radix tree to find out if there are any non-negated,
70fd62761dfe44f2254fb63ac3ded1b02663713fMichael Graff * non-loopback prefixes.
1d7987f4227c838f7fa790ad57255d3df3332ccaMichael Graff */
1d7987f4227c838f7fa790ad57255d3df3332ccaMichael Graff LOCK(&insecure_prefix_lock);
0b764d91c9021259f15b32c4beec852f2888f40cBrian Wellington insecure_prefix_found = ISC_FALSE;
af602636644fdfaabc331bd926b0aabb9432e152Brian Wellington isc_radix_process(a->iptable->radix, is_insecure);
0b764d91c9021259f15b32c4beec852f2888f40cBrian Wellington insecure = insecure_prefix_found;
0b764d91c9021259f15b32c4beec852f2888f40cBrian Wellington UNLOCK(&insecure_prefix_lock);
0b764d91c9021259f15b32c4beec852f2888f40cBrian Wellington if (insecure)
8d6fe3f38895752e3603cf2e1e9a0446b38f20cfBrian Wellington return(ISC_TRUE);
efcd38346161b10d60368411cfb2c0d1c22b5fb1Brian Wellington
efcd38346161b10d60368411cfb2c0d1c22b5fb1Brian Wellington /* Now check non-radix elements */
efcd38346161b10d60368411cfb2c0d1c22b5fb1Brian Wellington for (i = 0; i < a->length; i++) {
8d6fe3f38895752e3603cf2e1e9a0446b38f20cfBrian Wellington dns_aclelement_t *e = &a->elements[i];
8d6fe3f38895752e3603cf2e1e9a0446b38f20cfBrian Wellington
0b764d91c9021259f15b32c4beec852f2888f40cBrian Wellington /* A negated match can never be insecure. */
6d4886fa7430889a96dbf9b88a2a4eb6f9d04674Brian Wellington if (e->negative)
8d6fe3f38895752e3603cf2e1e9a0446b38f20cfBrian Wellington continue;
efcd38346161b10d60368411cfb2c0d1c22b5fb1Brian Wellington
efcd38346161b10d60368411cfb2c0d1c22b5fb1Brian Wellington switch (e->type) {
efcd38346161b10d60368411cfb2c0d1c22b5fb1Brian Wellington case dns_aclelementtype_keyname:
8d6fe3f38895752e3603cf2e1e9a0446b38f20cfBrian Wellington case dns_aclelementtype_localhost:
8d6fe3f38895752e3603cf2e1e9a0446b38f20cfBrian Wellington continue;
5c688a008a28f215cd772377774e6a1ed07d0525Brian Wellington
5c688a008a28f215cd772377774e6a1ed07d0525Brian Wellington case dns_aclelementtype_nestedacl:
af6e7e5cd2643e2aaaffefe1dd804a03394b4928Michael Graff if (dns_acl_isinsecure(e->nestedacl))
af6e7e5cd2643e2aaaffefe1dd804a03394b4928Michael Graff return (ISC_TRUE);
af6e7e5cd2643e2aaaffefe1dd804a03394b4928Michael Graff continue;
af6e7e5cd2643e2aaaffefe1dd804a03394b4928Michael Graff
af6e7e5cd2643e2aaaffefe1dd804a03394b4928Michael Graff case dns_aclelementtype_localnets:
af6e7e5cd2643e2aaaffefe1dd804a03394b4928Michael Graff return (ISC_TRUE);
069104dd6a1bba610d0c3a413459accf73f3921bBrian Wellington
af6e7e5cd2643e2aaaffefe1dd804a03394b4928Michael Graff default:
af6e7e5cd2643e2aaaffefe1dd804a03394b4928Michael Graff INSIST(0);
af6e7e5cd2643e2aaaffefe1dd804a03394b4928Michael Graff return (ISC_TRUE);
af6e7e5cd2643e2aaaffefe1dd804a03394b4928Michael Graff }
f9df80f4348ef68043903efa08299480324f4823Michael Graff }
f9df80f4348ef68043903efa08299480324f4823Michael Graff
f9df80f4348ef68043903efa08299480324f4823Michael Graff /* No insecure elements were found. */
97e7d389d54a9e3a1ba8313ed140b04afabc7081Michael Graff return (ISC_FALSE);
97e7d389d54a9e3a1ba8313ed140b04afabc7081Michael Graff}
f9df80f4348ef68043903efa08299480324f4823Michael Graff
f9df80f4348ef68043903efa08299480324f4823Michael Graff/*
0f80bfec687db08a6e6ce945ef1d818da06c7ca9Brian Wellington * Initialize ACL environment, setting up localhost and localnets ACLs
0f80bfec687db08a6e6ce945ef1d818da06c7ca9Brian Wellington */
0f80bfec687db08a6e6ce945ef1d818da06c7ca9Brian Wellingtonisc_result_t
0f80bfec687db08a6e6ce945ef1d818da06c7ca9Brian Wellingtondns_aclenv_init(isc_mem_t *mctx, dns_aclenv_t *env) {
0f80bfec687db08a6e6ce945ef1d818da06c7ca9Brian Wellington isc_result_t result;
0f80bfec687db08a6e6ce945ef1d818da06c7ca9Brian Wellington
0f80bfec687db08a6e6ce945ef1d818da06c7ca9Brian Wellington env->localhost = NULL;
0f80bfec687db08a6e6ce945ef1d818da06c7ca9Brian Wellington env->localnets = NULL;
0f80bfec687db08a6e6ce945ef1d818da06c7ca9Brian Wellington result = dns_acl_create(mctx, 0, &env->localhost);
0f80bfec687db08a6e6ce945ef1d818da06c7ca9Brian Wellington if (result != ISC_R_SUCCESS)
0f80bfec687db08a6e6ce945ef1d818da06c7ca9Brian Wellington goto cleanup_nothing;
0f80bfec687db08a6e6ce945ef1d818da06c7ca9Brian Wellington result = dns_acl_create(mctx, 0, &env->localnets);
0f80bfec687db08a6e6ce945ef1d818da06c7ca9Brian Wellington if (result != ISC_R_SUCCESS)
abaec24086f0cc3d7c0994ca9d2247b40eb6aaedBrian Wellington goto cleanup_localhost;
abaec24086f0cc3d7c0994ca9d2247b40eb6aaedBrian Wellington env->match_mapped = ISC_FALSE;
0f80bfec687db08a6e6ce945ef1d818da06c7ca9Brian Wellington return (ISC_R_SUCCESS);
0f80bfec687db08a6e6ce945ef1d818da06c7ca9Brian Wellington
0f80bfec687db08a6e6ce945ef1d818da06c7ca9Brian Wellington cleanup_localhost:
0f80bfec687db08a6e6ce945ef1d818da06c7ca9Brian Wellington dns_acl_detach(&env->localhost);
0f80bfec687db08a6e6ce945ef1d818da06c7ca9Brian Wellington cleanup_nothing:
0f80bfec687db08a6e6ce945ef1d818da06c7ca9Brian Wellington return (result);
0f80bfec687db08a6e6ce945ef1d818da06c7ca9Brian Wellington}
0f80bfec687db08a6e6ce945ef1d818da06c7ca9Brian Wellington
0f80bfec687db08a6e6ce945ef1d818da06c7ca9Brian Wellingtonvoid
abaec24086f0cc3d7c0994ca9d2247b40eb6aaedBrian Wellingtondns_aclenv_copy(dns_aclenv_t *t, dns_aclenv_t *s) {
0f80bfec687db08a6e6ce945ef1d818da06c7ca9Brian Wellington dns_acl_detach(&t->localhost);
0f80bfec687db08a6e6ce945ef1d818da06c7ca9Brian Wellington dns_acl_attach(s->localhost, &t->localhost);
0f80bfec687db08a6e6ce945ef1d818da06c7ca9Brian Wellington dns_acl_detach(&t->localnets);
f2338a0d6aa0327372eb20ab5dc29502bc8c71efBrian Wellington dns_acl_attach(s->localnets, &t->localnets);
0f80bfec687db08a6e6ce945ef1d818da06c7ca9Brian Wellington t->match_mapped = s->match_mapped;
0f80bfec687db08a6e6ce945ef1d818da06c7ca9Brian Wellington}
0f80bfec687db08a6e6ce945ef1d818da06c7ca9Brian Wellington
0f80bfec687db08a6e6ce945ef1d818da06c7ca9Brian Wellingtonvoid
0f80bfec687db08a6e6ce945ef1d818da06c7ca9Brian Wellingtondns_aclenv_destroy(dns_aclenv_t *env) {
0f80bfec687db08a6e6ce945ef1d818da06c7ca9Brian Wellington dns_acl_detach(&env->localhost);
0f80bfec687db08a6e6ce945ef1d818da06c7ca9Brian Wellington dns_acl_detach(&env->localnets);
abaec24086f0cc3d7c0994ca9d2247b40eb6aaedBrian Wellington}
0f80bfec687db08a6e6ce945ef1d818da06c7ca9Brian Wellington