0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews * Copyright (C) 1999-2002, 2004-2009, 2011, 2013, 2014, 2016 Internet Systems Consortium, Inc. ("ISC")
0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews * This Source Code Form is subject to the terms of the Mozilla Public
0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews * License, v. 2.0. If a copy of the MPL was not distributed with this
0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews * file, You can obtain one at http://mozilla.org/MPL/2.0/.
c7e266b7e5675e12d1ca3cc929f24b3e86d41f8eEvan Hunt * Create a new ACL, including an IP table and an array with room
c7e266b7e5675e12d1ca3cc929f24b3e86d41f8eEvan Hunt * for 'n' ACL elements. The elements are uninitialized and the
c7e266b7e5675e12d1ca3cc929f24b3e86d41f8eEvan Hunt * length is 0.
1a69a1a78cfaa86f3b68bbc965232b7876d4da2aDavid Lawrencedns_acl_create(isc_mem_t *mctx, int n, dns_acl_t **target) {
1a69a1a78cfaa86f3b68bbc965232b7876d4da2aDavid Lawrence * Work around silly limitation of isc_mem_get().
604419a812b491cd35fb6fad129c3c39da7200a1Mark Andrews result = dns_iptable_create(mctx, &acl->iptable);
1a69a1a78cfaa86f3b68bbc965232b7876d4da2aDavid Lawrence * Must set magic early because we use dns_acl_detach() to clean up.
7693d4de8fca501dfe6989a7f30d8d3c86fe096aAndreas Gustafsson acl->elements = isc_mem_get(mctx, n * sizeof(dns_aclelement_t));
7693d4de8fca501dfe6989a7f30d8d3c86fe096aAndreas Gustafsson memset(acl->elements, 0, n * sizeof(dns_aclelement_t));
c7e266b7e5675e12d1ca3cc929f24b3e86d41f8eEvan Hunt * Create a new ACL and initialize it with the value "any" or "none",
c7e266b7e5675e12d1ca3cc929f24b3e86d41f8eEvan Hunt * depending on the value of the "neg" parameter.
c7e266b7e5675e12d1ca3cc929f24b3e86d41f8eEvan Hunt * "any" is a positive iptable entry with bit length 0.
c7e266b7e5675e12d1ca3cc929f24b3e86d41f8eEvan Hunt * "none" is the same as "!any".
1a69a1a78cfaa86f3b68bbc965232b7876d4da2aDavid Lawrencedns_acl_anyornone(isc_mem_t *mctx, isc_boolean_t neg, dns_acl_t **target) {
1aba9fe67899522364a9dbc3ee5a14da081f0314Evan Hunt result = dns_iptable_addprefix(acl->iptable, NULL, 0, ISC_TF(!neg));
c7e266b7e5675e12d1ca3cc929f24b3e86d41f8eEvan Hunt * Create a new ACL that matches everything.
7693d4de8fca501dfe6989a7f30d8d3c86fe096aAndreas Gustafssondns_acl_any(isc_mem_t *mctx, dns_acl_t **target) {
7693d4de8fca501dfe6989a7f30d8d3c86fe096aAndreas Gustafsson return (dns_acl_anyornone(mctx, ISC_FALSE, target));
c7e266b7e5675e12d1ca3cc929f24b3e86d41f8eEvan Hunt * Create a new ACL that matches nothing.
7693d4de8fca501dfe6989a7f30d8d3c86fe096aAndreas Gustafssondns_acl_none(isc_mem_t *mctx, dns_acl_t **target) {
7693d4de8fca501dfe6989a7f30d8d3c86fe096aAndreas Gustafsson return (dns_acl_anyornone(mctx, ISC_TRUE, target));
c7e266b7e5675e12d1ca3cc929f24b3e86d41f8eEvan Hunt * If pos is ISC_TRUE, test whether acl is set to "{ any; }"
c7e266b7e5675e12d1ca3cc929f24b3e86d41f8eEvan Hunt * If pos is ISC_FALSE, test whether acl is set to "{ none; }"
c7e266b7e5675e12d1ca3cc929f24b3e86d41f8eEvan Huntdns_acl_isanyornone(dns_acl_t *acl, isc_boolean_t pos)
604419a812b491cd35fb6fad129c3c39da7200a1Mark Andrews /* Should never happen but let's be safe */
c7e266b7e5675e12d1ca3cc929f24b3e86d41f8eEvan Hunt if (acl->iptable->radix->head->prefix->bitlen == 0 &&
28ad0be64ee756013c0f6a474fc447ee613ee0d1Evan Hunt *(isc_boolean_t *) (acl->iptable->radix->head->data[0]) == pos)
c7e266b7e5675e12d1ca3cc929f24b3e86d41f8eEvan Hunt * Test whether acl is set to "{ any; }"
c7e266b7e5675e12d1ca3cc929f24b3e86d41f8eEvan Hunt * Test whether acl is set to "{ none; }"
c7e266b7e5675e12d1ca3cc929f24b3e86d41f8eEvan Hunt * Determine whether a given address or signer matches a given ACL.
2f012d936b5ccdf6520c96a4de23721dc58a2221Automatic Updater * For a match with a positive ACL element or iptable radix entry,
c7e266b7e5675e12d1ca3cc929f24b3e86d41f8eEvan Hunt * return with a positive value in match; for a match with a negated ACL
c7e266b7e5675e12d1ca3cc929f24b3e86d41f8eEvan Hunt * element or radix entry, return with a negative value in match.
d46855caedd5cb101795707f6f467fa363ef1448Evan Hunt return (dns_acl_match2(reqaddr, reqsigner, NULL, 0, NULL, acl, env,
8bb77cd31b7518fb5d2a6a9d75e16e4abd59df61Andreas Gustafsson unsigned int i;
6017f424ee3c02d7f22132c77576ea38542fa949Andreas Gustafsson REQUIRE(matchelt == NULL || *matchelt == NULL);
c7e266b7e5675e12d1ca3cc929f24b3e86d41f8eEvan Hunt /* Always match with host addresses. */
d46855caedd5cb101795707f6f467fa363ef1448Evan Hunt NETADDR_TO_PREFIX_T(addr, pfx, bitlen, ISC_FALSE);
c7e266b7e5675e12d1ca3cc929f24b3e86d41f8eEvan Hunt /* Assume no match. */
c7e266b7e5675e12d1ca3cc929f24b3e86d41f8eEvan Hunt /* Search radix. */
c7e266b7e5675e12d1ca3cc929f24b3e86d41f8eEvan Hunt result = isc_radix_search(acl->iptable->radix, &node, &pfx);
c7e266b7e5675e12d1ca3cc929f24b3e86d41f8eEvan Hunt /* Found a match. */
d46855caedd5cb101795707f6f467fa363ef1448Evan Hunt * If ecs is not NULL, we search the radix tree again to
d46855caedd5cb101795707f6f467fa363ef1448Evan Hunt * see if we find a better match on an ECS node
d46855caedd5cb101795707f6f467fa363ef1448Evan Hunt result = isc_radix_search(acl->iptable->radix, &node, &pfx);
604419a812b491cd35fb6fad129c3c39da7200a1Mark Andrews /* Now search non-radix elements for a match with a lower node_num. */
114c14f8adfc249cf2e5cdcb9007af46fed257e3Mark Andrews /* Already found a better match? */
d46855caedd5cb101795707f6f467fa363ef1448Evan Hunt if (dns_aclelement_match2(reqaddr, reqsigner, ecs, ecslen,
604419a812b491cd35fb6fad129c3c39da7200a1Mark Andrews if (match_num == -1 || e->node_num < match_num) {
c7e266b7e5675e12d1ca3cc929f24b3e86d41f8eEvan Hunt * Merge the contents of one ACL into another. Call dns_iptable_merge()
c7e266b7e5675e12d1ca3cc929f24b3e86d41f8eEvan Hunt * for the IP tables, then concatenate the element arrays.
c7e266b7e5675e12d1ca3cc929f24b3e86d41f8eEvan Hunt * If pos is set to false, then the nested ACL is to be negated. This
c7e266b7e5675e12d1ca3cc929f24b3e86d41f8eEvan Hunt * means reverse the sense of each *positive* element or IP table node,
c7e266b7e5675e12d1ca3cc929f24b3e86d41f8eEvan Hunt * but leave negatives alone, so as to prevent a double-negative causing
584848087f7463c1f659ce4712dc047d8e7f2b07Francis Dupont * an unexpected positive match in the parent ACL.
c7e266b7e5675e12d1ca3cc929f24b3e86d41f8eEvan Huntdns_acl_merge(dns_acl_t *dest, dns_acl_t *source, isc_boolean_t pos)
604419a812b491cd35fb6fad129c3c39da7200a1Mark Andrews /* Resize the element array if needed. */
604419a812b491cd35fb6fad129c3c39da7200a1Mark Andrews if (dest->length + source->length > dest->alloc) {
3e90f6c373d2e6c9c9909b112468975c4c86544eMark Andrews memset(newmem, 0, newalloc * sizeof(dns_aclelement_t));
604419a812b491cd35fb6fad129c3c39da7200a1Mark Andrews /* Copy in the original elements */
604419a812b491cd35fb6fad129c3c39da7200a1Mark Andrews /* Release the memory for the old elements array */
604419a812b491cd35fb6fad129c3c39da7200a1Mark Andrews * Now copy in the new elements, increasing their node_num
604419a812b491cd35fb6fad129c3c39da7200a1Mark Andrews * values so as to keep the new ACL consistent. If we're
604419a812b491cd35fb6fad129c3c39da7200a1Mark Andrews * negating, then negate positive elements, but keep negative
604419a812b491cd35fb6fad129c3c39da7200a1Mark Andrews * elements the same for security reasons.
604419a812b491cd35fb6fad129c3c39da7200a1Mark Andrews /* Copy type. */
604419a812b491cd35fb6fad129c3c39da7200a1Mark Andrews dest->elements[nelem + i].type = source->elements[i].type;
604419a812b491cd35fb6fad129c3c39da7200a1Mark Andrews /* Adjust node numbering. */
604419a812b491cd35fb6fad129c3c39da7200a1Mark Andrews source->elements[i].node_num + dest->node_count;
604419a812b491cd35fb6fad129c3c39da7200a1Mark Andrews /* Duplicate nested acl. */
262c39b2366bf79062f7f86b218947523dd1cbacEvan Hunt if (source->elements[i].type == dns_aclelementtype_nestedacl &&
604419a812b491cd35fb6fad129c3c39da7200a1Mark Andrews /* Duplicate key name. */
604419a812b491cd35fb6fad129c3c39da7200a1Mark Andrews if (source->elements[i].type == dns_aclelementtype_keyname) {
604419a812b491cd35fb6fad129c3c39da7200a1Mark Andrews dns_name_init(&dest->elements[nelem+i].keyname, NULL);
604419a812b491cd35fb6fad129c3c39da7200a1Mark Andrews result = dns_name_dup(&source->elements[i].keyname,
c0c4512020c0a4a9e5b087cb8cad1cd68fb3f52eEvan Hunt /* Duplicate GeoIP data */
c0c4512020c0a4a9e5b087cb8cad1cd68fb3f52eEvan Hunt if (source->elements[i].type == dns_aclelementtype_geoip) {
604419a812b491cd35fb6fad129c3c39da7200a1Mark Andrews /* reverse sense of positives if this is a negative acl */
604419a812b491cd35fb6fad129c3c39da7200a1Mark Andrews * Merge the iptables. Make sure the destination ACL's
604419a812b491cd35fb6fad129c3c39da7200a1Mark Andrews * node_count value is set correctly afterward.
604419a812b491cd35fb6fad129c3c39da7200a1Mark Andrews result = dns_iptable_merge(dest->iptable, source->iptable, pos);
c7e266b7e5675e12d1ca3cc929f24b3e86d41f8eEvan Hunt * Like dns_acl_match, but matches against the single ACL element 'e'
c7e266b7e5675e12d1ca3cc929f24b3e86d41f8eEvan Hunt * rather than a complete ACL, and returns ISC_TRUE iff it matched.
584848087f7463c1f659ce4712dc047d8e7f2b07Francis Dupont * To determine whether the match was positive or negative, the
c7e266b7e5675e12d1ca3cc929f24b3e86d41f8eEvan Hunt * caller should examine e->negative. Since the element 'e' may be
c7e266b7e5675e12d1ca3cc929f24b3e86d41f8eEvan Hunt * a reference to a named ACL or a nested ACL, a matching element
c7e266b7e5675e12d1ca3cc929f24b3e86d41f8eEvan Hunt * returned through 'matchelt' is not necessarily 'e' itself.
45e1bd63587102c3bb361eaca42ee7b714fb3542Mark Andrewsdns_aclelement_match(const isc_netaddr_t *reqaddr,
d46855caedd5cb101795707f6f467fa363ef1448Evan Hunt return (dns_aclelement_match2(reqaddr, reqsigner, NULL, 0, NULL,
d46855caedd5cb101795707f6f467fa363ef1448Evan Huntdns_aclelement_match2(const isc_netaddr_t *reqaddr,
604419a812b491cd35fb6fad129c3c39da7200a1Mark Andrews switch (e->type) {
d46855caedd5cb101795707f6f467fa363ef1448Evan Hunt addr = (env->geoip_use_ecs && ecs != NULL) ? ecs : reqaddr;
604419a812b491cd35fb6fad129c3c39da7200a1Mark Andrews /* Should be impossible. */
d46855caedd5cb101795707f6f467fa363ef1448Evan Hunt result = dns_acl_match2(reqaddr, reqsigner, ecs, ecslen, scope,
604419a812b491cd35fb6fad129c3c39da7200a1Mark Andrews * Treat negative matches in indirect ACLs as "no match".
604419a812b491cd35fb6fad129c3c39da7200a1Mark Andrews * That way, a negated indirect ACL will never become a
604419a812b491cd35fb6fad129c3c39da7200a1Mark Andrews * surprise positive match through double negation.
604419a812b491cd35fb6fad129c3c39da7200a1Mark Andrews * XXXDCL this should be documented.
604419a812b491cd35fb6fad129c3c39da7200a1Mark Andrews * A negative indirect match may have set *matchelt, but we don't
604419a812b491cd35fb6fad129c3c39da7200a1Mark Andrews * want it set when we return.
1a69a1a78cfaa86f3b68bbc965232b7876d4da2aDavid Lawrencedns_acl_attach(dns_acl_t *source, dns_acl_t **target) {
aa23a35d81a9618a40c4a9b44be48009553e4777Andreas Gustafsson isc_refcount_increment(&source->refcount, NULL);
6017f424ee3c02d7f22132c77576ea38542fa949Andreas Gustafsson unsigned int i;
6017f424ee3c02d7f22132c77576ea38542fa949Andreas Gustafsson dns_aclelement_t *de = &dacl->elements[i];
12e0477d4e132c9122312246ed60aaa646f819b2Mark Andrews } else if (de->type == dns_aclelementtype_nestedacl) {
df925e6c66d45d960fbac0383169763967d2111cEvan Hunt isc_mem_putanddetach(&dacl->mctx, dacl, sizeof(*dacl));
aa23a35d81a9618a40c4a9b44be48009553e4777Andreas Gustafsson isc_refcount_decrement(&acl->refcount, &refs);
69f3cb5abcb38f105c653c7b3df7cec33b87b292Mark Andrewsstatic isc_once_t insecure_prefix_once = ISC_ONCE_INIT;
604419a812b491cd35fb6fad129c3c39da7200a1Mark Andrews RUNTIME_CHECK(isc_mutex_init(&insecure_prefix_lock) == ISC_R_SUCCESS);
7a00d69909ace5dc11bcff9c1e07c311f92a7f8eWitold Krecicki * Called via isc_radix_process() to find IP table nodes that are
6db55b4ff9b099bc8d6621f6e13ec1f087d35e04Mark Andrews * If all nonexistent or negative then this node is secure.
6db55b4ff9b099bc8d6621f6e13ec1f087d35e04Mark Andrews if ((data[0] == NULL || !* (isc_boolean_t *) data[0]) &&
6db55b4ff9b099bc8d6621f6e13ec1f087d35e04Mark Andrews (data[1] == NULL || !* (isc_boolean_t *) data[1]) &&
6db55b4ff9b099bc8d6621f6e13ec1f087d35e04Mark Andrews (data[2] == NULL || !* (isc_boolean_t *) data[2]) &&
6db55b4ff9b099bc8d6621f6e13ec1f087d35e04Mark Andrews (data[3] == NULL || !* (isc_boolean_t *) data[3]))
f1e3dd087b7ce34382df8354efddaae79caa11b7Mark Andrews * If a loopback address found and the other family and
f1e3dd087b7ce34382df8354efddaae79caa11b7Mark Andrews * ecs entry doesn't exist or is negative, return.
6db55b4ff9b099bc8d6621f6e13ec1f087d35e04Mark Andrews htonl(prefix->add.sin.s_addr) == INADDR_LOOPBACK &&
6db55b4ff9b099bc8d6621f6e13ec1f087d35e04Mark Andrews (data[1] == NULL || !* (isc_boolean_t *) data[1]) &&
f1e3dd087b7ce34382df8354efddaae79caa11b7Mark Andrews (data[2] == NULL || !* (isc_boolean_t *) data[2]) &&
6db55b4ff9b099bc8d6621f6e13ec1f087d35e04Mark Andrews (data[3] == NULL || !* (isc_boolean_t *) data[3]))
6db55b4ff9b099bc8d6621f6e13ec1f087d35e04Mark Andrews (data[0] == NULL || !* (isc_boolean_t *) data[0]) &&
f1e3dd087b7ce34382df8354efddaae79caa11b7Mark Andrews (data[2] == NULL || !* (isc_boolean_t *) data[2]) &&
f1e3dd087b7ce34382df8354efddaae79caa11b7Mark Andrews (data[3] == NULL || !* (isc_boolean_t *) data[3]))
604419a812b491cd35fb6fad129c3c39da7200a1Mark Andrews /* Non-negated, non-loopback */
c7e266b7e5675e12d1ca3cc929f24b3e86d41f8eEvan Hunt * Return ISC_TRUE iff the acl 'a' is considered insecure, that is,
c7e266b7e5675e12d1ca3cc929f24b3e86d41f8eEvan Hunt * if it contains IP addresses other than those of the local host.
2f012d936b5ccdf6520c96a4de23721dc58a2221Automatic Updater * This is intended for applications such as printing warning
c7e266b7e5675e12d1ca3cc929f24b3e86d41f8eEvan Hunt * messages for suspect ACLs; it is not intended for making access
c7e266b7e5675e12d1ca3cc929f24b3e86d41f8eEvan Hunt * control decisions. We make no guarantee that an ACL for which
c7e266b7e5675e12d1ca3cc929f24b3e86d41f8eEvan Hunt * this function returns ISC_FALSE is safe.
9c566a852f31c3a5d0b9d6eaf11463114339c01dAndreas Gustafsson unsigned int i;
69f3cb5abcb38f105c653c7b3df7cec33b87b292Mark Andrews RUNTIME_CHECK(isc_once_do(&insecure_prefix_once,
604419a812b491cd35fb6fad129c3c39da7200a1Mark Andrews * Walk radix tree to find out if there are any non-negated,
604419a812b491cd35fb6fad129c3c39da7200a1Mark Andrews * non-loopback prefixes.
604419a812b491cd35fb6fad129c3c39da7200a1Mark Andrews isc_radix_process(a->iptable->radix, is_insecure);
604419a812b491cd35fb6fad129c3c39da7200a1Mark Andrews /* Now check non-radix elements */
9c566a852f31c3a5d0b9d6eaf11463114339c01dAndreas Gustafsson for (i = 0; i < a->length; i++) {
9c566a852f31c3a5d0b9d6eaf11463114339c01dAndreas Gustafsson /* A negated match can never be insecure. */
9c566a852f31c3a5d0b9d6eaf11463114339c01dAndreas Gustafsson /* No insecure elements were found. */
c7e266b7e5675e12d1ca3cc929f24b3e86d41f8eEvan Hunt * Initialize ACL environment, setting up localhost and localnets ACLs
1a69a1a78cfaa86f3b68bbc965232b7876d4da2aDavid Lawrencedns_aclenv_init(isc_mem_t *mctx, dns_aclenv_t *env) {
a1747570262ed336c213aaf6bd31bc91993a46deAndreas Gustafsson result = dns_acl_create(mctx, 0, &env->localhost);
a1747570262ed336c213aaf6bd31bc91993a46deAndreas Gustafsson result = dns_acl_create(mctx, 0, &env->localnets);
1a69a1a78cfaa86f3b68bbc965232b7876d4da2aDavid Lawrencedns_aclenv_copy(dns_aclenv_t *t, dns_aclenv_t *s) {
a1747570262ed336c213aaf6bd31bc91993a46deAndreas Gustafsson dns_acl_attach(s->localhost, &t->localhost);