2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-30 05:57:52 +00:00

Add support for O(1) ACL processing, based on radix tree code originally

written by kevin brintnall. [RT #16288]
This commit is contained in:
Evan Hunt 2007-09-12 01:09:08 +00:00
parent c1ff5c2b94
commit c7e266b7e5
17 changed files with 648 additions and 409 deletions

View File

@ -1,3 +1,7 @@
2233. [func] Add support for O(1) ACL processing, based on
radix tree code originally written by kevin
brintnall. [RT #16288]
2232. [bug] dns_adb_findaddrinfo() could fail and return
ISC_R_SUCCESS. [RT #17137]

View File

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: controlconf.c,v 1.54 2007/06/18 23:47:18 tbox Exp $ */
/* $Id: controlconf.c,v 1.55 2007/09/12 01:09:07 each Exp $ */
/*! \file */
@ -1014,7 +1014,7 @@ update_listener(ns_controls_t *cp, controllistener_t **listenerp,
if (control != NULL && type == isc_sockettype_tcp) {
allow = cfg_tuple_get(control, "allow");
result = cfg_acl_fromconfig(allow, config, ns_g_lctx,
aclconfctx, listener->mctx,
aclconfctx, listener->mctx, 0,
&new_acl);
} else {
result = dns_acl_any(listener->mctx, &new_acl);
@ -1101,7 +1101,8 @@ add_listener(ns_controls_t *cp, controllistener_t **listenerp,
if (control != NULL && type == isc_sockettype_tcp) {
allow = cfg_tuple_get(control, "allow");
result = cfg_acl_fromconfig(allow, config, ns_g_lctx,
aclconfctx, mctx, &new_acl);
aclconfctx, mctx, 0,
&new_acl);
} else {
result = dns_acl_any(mctx, &new_acl);
}

View File

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: interfacemgr.c,v 1.89 2007/06/18 23:47:18 tbox Exp $ */
/* $Id: interfacemgr.c,v 1.90 2007/09/12 01:09:07 each Exp $ */
/*! \file */
@ -483,7 +483,7 @@ static isc_result_t
clearacl(isc_mem_t *mctx, dns_acl_t **aclp) {
dns_acl_t *newacl = NULL;
isc_result_t result;
result = dns_acl_create(mctx, 10, &newacl);
result = dns_acl_create(mctx, 0, &newacl);
if (result != ISC_R_SUCCESS)
return (result);
dns_acl_detach(aclp);
@ -494,36 +494,31 @@ clearacl(isc_mem_t *mctx, dns_acl_t **aclp) {
static isc_boolean_t
listenon_is_ip6_any(ns_listenelt_t *elt) {
if (elt->acl->length != 1)
return (ISC_FALSE);
if (elt->acl->elements[0].negative == ISC_FALSE &&
elt->acl->elements[0].type == dns_aclelementtype_any)
return (ISC_TRUE); /* listen-on-v6 { any; } */
return (ISC_FALSE); /* All others */
REQUIRE(elt && elt->acl);
return dns_acl_isany(elt->acl);
}
static isc_result_t
setup_locals(ns_interfacemgr_t *mgr, isc_interface_t *interface) {
isc_result_t result;
dns_aclelement_t elt;
unsigned int family;
unsigned int prefixlen;
isc_netaddr_t *netaddr;
family = interface->address.family;
netaddr = &interface->address;
elt.type = dns_aclelementtype_ipprefix;
elt.negative = ISC_FALSE;
elt.u.ip_prefix.address = interface->address;
elt.u.ip_prefix.prefixlen = (family == AF_INET) ? 32 : 128;
result = dns_acl_appendelement(mgr->aclenv.localhost, &elt);
/* First add localhost address */
prefixlen = (netaddr->family == AF_INET) ? 32 : 128;
result = dns_iptable_addprefix(mgr->aclenv.localhost->iptable,
netaddr, prefixlen, ISC_TRUE);
if (result != ISC_R_SUCCESS)
return (result);
/* Then add localnets prefix */
result = isc_netaddr_masktoprefixlen(&interface->netmask,
&prefixlen);
/* Non contigious netmasks not allowed by IPv6 arch. */
if (result != ISC_R_SUCCESS && family == AF_INET6)
if (result != ISC_R_SUCCESS && netaddr->family == AF_INET6)
return (result);
if (result != ISC_R_SUCCESS) {
@ -533,17 +528,14 @@ setup_locals(ns_interfacemgr_t *mgr, isc_interface_t *interface) {
"localnets ACL: %s",
interface->name,
isc_result_totext(result));
} else {
elt.u.ip_prefix.prefixlen = prefixlen;
if (dns_acl_elementmatch(mgr->aclenv.localnets, &elt,
NULL) == ISC_R_NOTFOUND) {
result = dns_acl_appendelement(mgr->aclenv.localnets,
&elt);
if (result != ISC_R_SUCCESS)
return (result);
}
return (ISC_R_SUCCESS);
}
result = dns_iptable_addprefix(mgr->aclenv.localnets->iptable,
netaddr, prefixlen, ISC_TRUE);
if (result != ISC_R_SUCCESS)
return (result);
return (ISC_R_SUCCESS);
}

View File

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: server.c,v 1.489 2007/07/09 02:12:42 marka Exp $ */
/* $Id: server.c,v 1.490 2007/09/12 01:09:07 each Exp $ */
/*! \file */
@ -307,7 +307,51 @@ configure_view_acl(const cfg_obj_t *vconfig, const cfg_obj_t *config,
return (ISC_R_SUCCESS);
result = cfg_acl_fromconfig(aclobj, config, ns_g_lctx,
actx, mctx, aclp);
actx, mctx, 0, aclp);
return (result);
}
/*%
* Configure a sortlist at '*aclp'. Essentially the same as
* configure_view_acl() except it calls cfg_acl_fromconfig with a
* nest_level value of 2.
*/
static isc_result_t
configure_view_sortlist(const cfg_obj_t *vconfig, const cfg_obj_t *config,
cfg_aclconfctx_t *actx, isc_mem_t *mctx,
dns_acl_t **aclp)
{
isc_result_t result;
const cfg_obj_t *maps[3];
const cfg_obj_t *aclobj = NULL;
int i = 0;
if (*aclp != NULL)
dns_acl_detach(aclp);
if (vconfig != NULL)
maps[i++] = cfg_tuple_get(vconfig, "options");
if (config != NULL) {
const cfg_obj_t *options = NULL;
(void)cfg_map_get(config, "options", &options);
if (options != NULL)
maps[i++] = options;
}
maps[i] = NULL;
(void)ns_config_get(maps, "sortlist", &aclobj);
if (aclobj == NULL)
return (ISC_R_SUCCESS);
/*
* Use a nest level of 2 for the "top level" of the sortlist;
* this means each entry in the top two levels will be stored as
* lists of separate, nested ACLs, rather than merged together
* into IP tables as is usually done with ACLs.
*/
result = cfg_acl_fromconfig(aclobj, config, ns_g_lctx,
actx, mctx, 2, aclp);
return (result);
}
@ -1598,8 +1642,11 @@ configure_view(dns_view_t *view, const cfg_obj_t *config,
"allow-query-cache", actx,
ns_g_mctx, &view->queryacl));
CHECK(configure_view_acl(vconfig, config, "sortlist",
actx, ns_g_mctx, &view->sortlist));
/*
* Configure sortlist, if set
*/
CHECK(configure_view_sortlist(vconfig, config, actx, ns_g_mctx,
&view->sortlist));
obj = NULL;
result = ns_config_get(maps, "request-ixfr", &obj);
@ -2490,25 +2537,23 @@ add_listenelt(isc_mem_t *mctx, ns_listenlist_t *list, isc_sockaddr_t *addr,
{
ns_listenelt_t *lelt = NULL;
dns_acl_t *src_acl = NULL;
dns_aclelement_t aelt;
isc_result_t result;
isc_sockaddr_t any_sa6;
isc_netaddr_t netaddr;
REQUIRE(isc_sockaddr_pf(addr) == AF_INET6);
isc_sockaddr_any6(&any_sa6);
if (!isc_sockaddr_equal(&any_sa6, addr) &&
(wcardport_ok || isc_sockaddr_getport(addr) != 0)) {
aelt.type = dns_aclelementtype_ipprefix;
aelt.negative = ISC_FALSE;
aelt.u.ip_prefix.prefixlen = 128;
isc_netaddr_fromin6(&aelt.u.ip_prefix.address,
&addr->type.sin6.sin6_addr);
result = dns_acl_create(mctx, 1, &src_acl);
isc_netaddr_fromin6(&netaddr, &addr->type.sin6.sin6_addr);
result = dns_acl_create(mctx, 0, &src_acl);
if (result != ISC_R_SUCCESS)
return (result);
result = dns_acl_appendelement(src_acl, &aelt);
result = dns_iptable_addprefix(src_acl->iptable,
&netaddr, 128, ISC_TRUE);
if (result != ISC_R_SUCCESS)
goto clean;
@ -4391,7 +4436,8 @@ ns_listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config,
return (result);
result = cfg_acl_fromconfig(cfg_tuple_get(listener, "acl"),
config, ns_g_lctx, actx, mctx, &delt->acl);
config, ns_g_lctx, actx, mctx, 0,
&delt->acl);
if (result != ISC_R_SUCCESS) {
ns_listenelt_destroy(delt);
return (result);

View File

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: sortlist.c,v 1.15 2007/06/19 23:46:59 tbox Exp $ */
/* $Id: sortlist.c,v 1.16 2007/09/12 01:09:07 each Exp $ */
/*! \file */
@ -51,7 +51,7 @@ ns_sortlist_setup(dns_acl_t *acl, isc_netaddr_t *clientaddr,
const dns_aclelement_t *matched_elt = NULL;
if (e->type == dns_aclelementtype_nestedacl) {
dns_acl_t *inner = e->u.nestedacl;
dns_acl_t *inner = e->nestedacl;
if (inner->length < 1 || inner->length > 2)
goto dont_sort;
@ -74,7 +74,7 @@ ns_sortlist_setup(dns_acl_t *acl, isc_netaddr_t *clientaddr,
if (order_elt != NULL) {
if (order_elt->type ==
dns_aclelementtype_nestedacl) {
*argp = order_elt->u.nestedacl;
*argp = order_elt->nestedacl;
return (NS_SORTLISTTYPE_2ELEMENT);
} else if (order_elt->type ==
dns_aclelementtype_localhost &&

View File

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: zoneconf.c,v 1.137 2007/06/19 23:46:59 tbox Exp $ */
/* $Id: zoneconf.c,v 1.138 2007/09/12 01:09:07 each Exp $ */
/*% */
@ -90,7 +90,7 @@ configure_zone_acl(const cfg_obj_t *zconfig, const cfg_obj_t *vconfig,
}
result = cfg_acl_fromconfig(aclobj, config, ns_g_lctx, actx,
dns_zone_getmctx(zone), &dacl);
dns_zone_getmctx(zone), 0, &dacl);
if (result != ISC_R_SUCCESS)
return (result);
(*setzacl)(zone, dacl);

View File

@ -18,7 +18,7 @@
- PERFORMANCE OF THIS SOFTWARE.
-->
<!-- File: $Id: Bv9ARM-book.xml,v 1.333 2007/09/07 07:29:22 marka Exp $ -->
<!-- File: $Id: Bv9ARM-book.xml,v 1.334 2007/09/12 01:09:08 each Exp $ -->
<book xmlns:xi="http://www.w3.org/2001/XInclude">
<title>BIND 9 Administrator Reference Manual</title>
@ -3023,9 +3023,8 @@ $ORIGIN 0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa.
Address match lists are primarily used to determine access
control for various server operations. They are also used in
the <command>listen-on</command> and <command>sortlist</command>
statements. The elements
which constitute an address match list can be any of the
following:
statements. The elements which constitute an address match
list can be any of the following:
</para>
<itemizedlist>
<listitem>
@ -3053,28 +3052,30 @@ $ORIGIN 0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa.
<para>
Elements can be negated with a leading exclamation mark (`!'),
and the match list names "any", "none", "localhost", and
"localnets"
are predefined. More information on those names can be found in
the description of the acl statement.
"localnets" are predefined. More information on those names
can be found in the description of the acl statement.
</para>
<para>
The addition of the key clause made the name of this syntactic
element something of a misnomer, since security keys can be used
to validate access without regard to a host or network address.
Nonetheless,
the term "address match list" is still used throughout the
documentation.
Nonetheless, the term "address match list" is still used
throughout the documentation.
</para>
<para>
When a given IP address or prefix is compared to an address
match list, the list is traversed in order until an element
matches.
match list, the comparison takes place in approximately O(1)
time. However, key comparisons require that the list of keys
be traversed until a matching key is found, and therefore may
be somewhat slower.
</para>
<para>
The interpretation of a match depends on whether the list is being
used
for access control, defining listen-on ports, or in a sortlist,
and whether the element was negated.
used for access control, defining listen-on ports, or in a
sortlist, and whether the element was negated.
</para>
<para>
@ -3093,23 +3094,25 @@ $ORIGIN 0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa.
<command>allow-update-forwarding</command>, and
<command>blackhole</command> all use address match
lists. Similarly, the listen-on option will cause the
server to not accept queries on any of the machine's
server to refuse queries on any of the machine's
addresses which do not match the list.
</para>
<para>
Because of the first-match aspect of the algorithm, an element
that defines a subset of another element in the list should come
before the broader element, regardless of whether either is
negated. For
example, in
<command>1.2.3/24; ! 1.2.3.13;</command> the 1.2.3.13
element is
completely useless because the algorithm will match any lookup for
1.2.3.13 to the 1.2.3/24 element.
Using <command>! 1.2.3.13; 1.2.3/24</command> fixes
that problem by having 1.2.3.13 blocked by the negation but all
other 1.2.3.* hosts fall through.
Order of insertion is signficant. If more than one element
in an ACL is found to match a given IP address or prefix,
preference will be given to the one that came
<emphasis>first</emphasis> in the ACL definition.
Because of this first-match behavior, an element that
defines a subset of another element in the list should
come before the broader element, regardless of whether
either is negated. For example, in
<command>1.2.3/24; ! 1.2.3.13;</command>
the 1.2.3.13 element is completely useless because the
algorithm will match any lookup for 1.2.3.13 to the 1.2.3/24
element. Using <command>! 1.2.3.13; 1.2.3/24</command> fixes
that problem by having 1.2.3.13 blocked by the negation, but
all other 1.2.3.* hosts fall through.
</para>
</sect3>
</sect2>
@ -3390,8 +3393,7 @@ $ORIGIN 0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa.
<para>
Note that an address match list's name must be defined
with <command>acl</command> before it can be used
elsewhere; no
forward references are allowed.
elsewhere; no forward references are allowed.
</para>
<para>

View File

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: check.c,v 1.81 2007/08/29 03:23:46 marka Exp $ */
/* $Id: check.c,v 1.82 2007/09/12 01:09:08 each Exp $ */
/*! \file */
@ -379,7 +379,8 @@ checkacl(const char *aclname, cfg_aclconfctx_t *actx, const cfg_obj_t *zconfig,
}
if (aclobj == NULL)
return (ISC_R_SUCCESS);
result = cfg_acl_fromconfig(aclobj, config, logctx, actx, mctx, &acl);
result = cfg_acl_fromconfig(aclobj, config, logctx,
actx, mctx, 0, &acl);
if (acl != NULL)
dns_acl_detach(&acl);
return (result);
@ -459,7 +460,7 @@ check_recursionacls(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions,
continue;
tresult = cfg_acl_fromconfig(aclobj, config, logctx,
actx, mctx, &acl);
actx, mctx, 0, &acl);
if (tresult != ISC_R_SUCCESS)
result = tresult;
@ -1932,7 +1933,7 @@ bind9_check_controls(const cfg_obj_t *config, isc_log_t *logctx,
control = cfg_listelt_value(element2);
allow = cfg_tuple_get(control, "allow");
tresult = cfg_acl_fromconfig(allow, config, logctx,
&actx, mctx, &acl);
&actx, mctx, 0, &acl);
if (acl != NULL)
dns_acl_detach(&acl);
if (tresult != ISC_R_SUCCESS)
@ -2114,8 +2115,9 @@ bind9_check_namedconf(const cfg_obj_t *config, isc_log_t *logctx,
}
}
tresult = cfg_map_get(config, "acl", &acls);
if (tresult == ISC_R_SUCCESS) {
cfg_map_get(config, "acl", &acls);
if (acls != NULL) {
const cfg_listelt_t *elt;
const cfg_listelt_t *elt2;
const char *aclname;
@ -2124,6 +2126,7 @@ bind9_check_namedconf(const cfg_obj_t *config, isc_log_t *logctx,
elt != NULL;
elt = cfg_list_next(elt)) {
const cfg_obj_t *acl = cfg_listelt_value(elt);
unsigned int line = cfg_obj_line(acl);
unsigned int i;
aclname = cfg_obj_asstring(cfg_tuple_get(acl, "name"));
@ -2148,7 +2151,6 @@ bind9_check_namedconf(const cfg_obj_t *config, isc_log_t *logctx,
"name"));
if (strcasecmp(aclname, name) == 0) {
const char *file = cfg_obj_file(acl);
unsigned int line = cfg_obj_line(acl);
if (file == NULL)
file = "<unknown file>";

View File

@ -13,7 +13,7 @@
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
# $Id: Makefile.in,v 1.157 2007/06/19 23:47:16 tbox Exp $
# $Id: Makefile.in,v 1.158 2007/09/12 01:09:08 each Exp $
srcdir = @srcdir@
VPATH = @srcdir@
@ -53,8 +53,8 @@ DSTOBJS = @DST_EXTRA_OBJS@ \
DNSOBJS = acache.@O@ acl.@O@ adb.@O@ byaddr.@O@ \
cache.@O@ callbacks.@O@ compress.@O@ \
db.@O@ dbiterator.@O@ dbtable.@O@ diff.@O@ dispatch.@O@ \
dlz.@O@ dnssec.@O@ ds.@O@ forward.@O@ journal.@O@ keytable.@O@ \
lib.@O@ log.@O@ lookup.@O@ \
dlz.@O@ dnssec.@O@ ds.@O@ forward.@O@ iptable.@O@ journal.@O@ \
keytable.@O@ lib.@O@ log.@O@ lookup.@O@ \
master.@O@ masterdump.@O@ message.@O@ \
name.@O@ ncache.@O@ nsec.@O@ order.@O@ peer.@O@ portlist.@O@ \
rbt.@O@ rbtdb.@O@ rbtdb64.@O@ rcode.@O@ rdata.@O@ \
@ -79,8 +79,8 @@ DSTSRCS = @DST_EXTRA_SRCS@ \
DNSSRCS = acache.c acl.c adb.c byaddr.c \
cache.c callbacks.c compress.c \
db.c dbiterator.c dbtable.c diff.c dispatch.c \
dlz.c dnssec.c ds.c forward.c journal.c keytable.c \
lib.c log.c lookup.c \
dlz.c dnssec.c ds.c forward.c iptable.c journal.c \
keytable.c lib.c log.c lookup.c \
master.c masterdump.c message.c \
name.c ncache.c nsec.c order.c peer.c portlist.c \
rbt.c rbtdb.c rbtdb64.c rcode.c rdata.c \

View File

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: acl.c,v 1.32 2007/06/19 23:47:16 tbox Exp $ */
/* $Id: acl.c,v 1.33 2007/09/12 01:09:08 each Exp $ */
/*! \file */
@ -26,7 +26,13 @@
#include <isc/util.h>
#include <dns/acl.h>
#include <dns/iptable.h>
/*
* Create a new ACL, including an IP table and an array with room
* for 'n' ACL elements. The elements are uninitialized and the
* length is 0.
*/
isc_result_t
dns_acl_create(isc_mem_t *mctx, int n, dns_acl_t **target) {
isc_result_t result;
@ -43,11 +49,19 @@ dns_acl_create(isc_mem_t *mctx, int n, dns_acl_t **target) {
return (ISC_R_NOMEMORY);
acl->mctx = mctx;
acl->name = NULL;
result = isc_refcount_init(&acl->refcount, 1);
if (result != ISC_R_SUCCESS) {
isc_mem_put(mctx, acl, sizeof(*acl));
return (result);
}
result = dns_iptable_create(mctx, &acl->iptable);
if (result != ISC_R_SUCCESS) {
isc_mem_put(mctx, acl, sizeof(*acl));
return (result);
}
acl->elements = NULL;
acl->alloc = 0;
acl->length = 0;
@ -73,111 +87,234 @@ dns_acl_create(isc_mem_t *mctx, int n, dns_acl_t **target) {
return (result);
}
isc_result_t
dns_acl_appendelement(dns_acl_t *acl, const dns_aclelement_t *elt) {
if (acl->length + 1 > acl->alloc) {
/*
* Resize the ACL.
*/
unsigned int newalloc;
void *newmem;
newalloc = acl->alloc * 2;
if (newalloc < 4)
newalloc = 4;
newmem = isc_mem_get(acl->mctx,
newalloc * sizeof(dns_aclelement_t));
if (newmem == NULL)
return (ISC_R_NOMEMORY);
memcpy(newmem, acl->elements,
acl->length * sizeof(dns_aclelement_t));
isc_mem_put(acl->mctx, acl->elements,
acl->alloc * sizeof(dns_aclelement_t));
acl->elements = newmem;
acl->alloc = newalloc;
}
/*
* Append the new element.
*/
acl->elements[acl->length++] = *elt;
return (ISC_R_SUCCESS);
}
/*
* Create a new ACL and initialize it with the value "any" or "none",
* depending on the value of the "neg" parameter.
* "any" is a positive iptable entry with bit length 0.
* "none" is the same as "!any".
*/
static isc_result_t
dns_acl_anyornone(isc_mem_t *mctx, isc_boolean_t neg, dns_acl_t **target) {
isc_result_t result;
dns_acl_t *acl = NULL;
result = dns_acl_create(mctx, 1, &acl);
result = dns_acl_create(mctx, 0, &acl);
if (result != ISC_R_SUCCESS)
return (result);
acl->elements[0].negative = neg;
acl->elements[0].type = dns_aclelementtype_any;
acl->length = 1;
dns_iptable_addprefix(acl->iptable, NULL, 0, ISC_TF(!neg));
*target = acl;
return (result);
}
/*
* Create a new ACL that matches everything.
*/
isc_result_t
dns_acl_any(isc_mem_t *mctx, dns_acl_t **target) {
return (dns_acl_anyornone(mctx, ISC_FALSE, target));
}
/*
* Create a new ACL that matches nothing.
*/
isc_result_t
dns_acl_none(isc_mem_t *mctx, dns_acl_t **target) {
return (dns_acl_anyornone(mctx, ISC_TRUE, target));
}
/*
* If pos is ISC_TRUE, test whether acl is set to "{ any; }"
* If pos is ISC_FALSE, test whether acl is set to "{ none; }"
*/
static isc_boolean_t
dns_acl_isanyornone(dns_acl_t *acl, isc_boolean_t pos)
{
/* Should never happen but let's be safe */
if (acl == NULL ||
acl->iptable == NULL ||
acl->iptable->radix == NULL ||
acl->iptable->radix->head == NULL ||
acl->iptable->radix->head->prefix == NULL)
return (ISC_FALSE);
if (acl->length != 0 && acl->node_count != 1)
return (ISC_FALSE);
if (acl->iptable->radix->head->prefix->bitlen == 0 &&
*(isc_boolean_t *) (acl->iptable->radix->head->data) == pos)
return (ISC_TRUE);
return (ISC_FALSE); /* All others */
}
/*
* Test whether acl is set to "{ any; }"
*/
isc_boolean_t
dns_acl_isany(dns_acl_t *acl)
{
return (dns_acl_isanyornone(acl, ISC_TRUE));
}
/*
* Test whether acl is set to "{ none; }"
*/
isc_boolean_t
dns_acl_isnone(dns_acl_t *acl)
{
return (dns_acl_isanyornone(acl, ISC_FALSE));
}
/*
* Determine whether a given address or signer matches a given ACL.
* For a match with a positive ACL element or iptable radix entry,
* return with a positive value in match; for a match with a negated ACL
* element or radix entry, return with a negative value in match.
*/
isc_result_t
dns_acl_match(const isc_netaddr_t *reqaddr,
const dns_name_t *reqsigner,
const dns_acl_t *acl,
const dns_aclenv_t *env,
int *match,
dns_aclelement_t const**matchelt)
const dns_aclelement_t **matchelt)
{
isc_uint16_t bitlen;
isc_prefix_t pfx;
isc_radix_node_t *node;
const isc_netaddr_t *addr;
isc_netaddr_t v4addr;
isc_result_t result;
int match_num = -1;
unsigned int i;
REQUIRE(reqaddr != NULL);
REQUIRE(matchelt == NULL || *matchelt == NULL);
if (env == NULL || env->match_mapped == ISC_FALSE ||
reqaddr->family != AF_INET6 ||
!IN6_IS_ADDR_V4MAPPED(&reqaddr->type.in6))
addr = reqaddr;
else {
isc_netaddr_fromv4mapped(&v4addr, reqaddr);
addr = &v4addr;
}
/* Always match with host addresses. */
bitlen = reqaddr->family == AF_INET6 ? 128 : 32;
NETADDR_TO_PREFIX_T(addr, pfx, bitlen);
/* Assume no match. */
*match = 0;
/* Search radix. */
result = isc_radix_search(acl->iptable->radix, &node, &pfx);
/* Found a match. */
if (result == ISC_R_SUCCESS && node != NULL) {
match_num = node->node_num;
if (*(isc_boolean_t *) node->data == ISC_TRUE)
*match = match_num;
else
*match = -match_num;
}
/* Now search non-radix elements for a match with a lower node_num. */
for (i = 0; i < acl->length; i++) {
dns_aclelement_t *e = &acl->elements[i];
if (dns_aclelement_match(reqaddr, reqsigner,
e, env, matchelt)) {
*match = e->negative ? -((int)i+1) : ((int)i+1);
if (match_num == -1 || e->node_num < match_num) {
if (e->negative)
*match = -e->node_num;
else
*match = e->node_num;
}
return (ISC_R_SUCCESS);
}
}
/* No match. */
*match = 0;
return (ISC_R_SUCCESS);
}
/*
* Merge the contents of one ACL into another. Call dns_iptable_merge()
* for the IP tables, then concatenate the element arrays.
*
* If pos is set to false, then the nested ACL is to be negated. This
* means reverse the sense of each *positive* element or IP table node,
* but leave negatives alone, so as to prevent a double-negative causing
* an unexpected postive match in the parent ACL.
*/
isc_result_t
dns_acl_elementmatch(const dns_acl_t *acl,
const dns_aclelement_t *elt,
const dns_aclelement_t **matchelt)
dns_acl_merge(dns_acl_t *dest, dns_acl_t *source, isc_boolean_t pos)
{
unsigned int i;
unsigned int newalloc, nelem, i;
int max_node = 0, nodes;
REQUIRE(elt != NULL);
REQUIRE(matchelt == NULL || *matchelt == NULL);
for (i = 0; i < acl->length; i++) {
dns_aclelement_t *e = &acl->elements[i];
/* Resize the element array if needed. */
if (dest->length + source->length > dest->alloc) {
void *newmem;
if (dns_aclelement_equal(e, elt) == ISC_TRUE) {
if (matchelt != NULL)
*matchelt = e;
return (ISC_R_SUCCESS);
}
}
newalloc = dest->alloc + source->alloc;
if (newalloc < 4)
newalloc = 4;
return (ISC_R_NOTFOUND);
newmem = isc_mem_get(dest->mctx,
newalloc * sizeof(dns_aclelement_t));
if (newmem == NULL)
return (ISC_R_NOMEMORY);
/* Copy in the original elements */
memcpy(newmem, dest->elements,
dest->length * sizeof(dns_aclelement_t));
/* Release the memory for the old elements array */
isc_mem_put(dest->mctx, dest->elements,
dest->alloc * sizeof(dns_aclelement_t));
dest->elements = newmem;
dest->alloc = newalloc;
}
/*
* Now copy in the new elements, increasing their node_num
* values so as to keep the new ACL consistent. If we're
* negating, then negate positive elements, but keep negative
* elements the same for security reasons.
*/
nelem = dest->length;
memcpy(&dest->elements[nelem], source->elements,
(source->length * sizeof(dns_aclelement_t)));
for (i = 0; i < source->length; i++) {
dest->elements[nelem + i].node_num =
source->elements[i].node_num + dest->node_count;
if (source->elements[i].node_num > max_node)
max_node = source->elements[i].node_num;
if (!pos && source->elements[i].negative == ISC_FALSE)
dest->elements[nelem + i].negative = ISC_TRUE;
}
/*
* Merge the iptables. Make sure the destination ACL's
* node_count value is set correctly afterward.
*/
nodes = max_node + dest->node_count;
dns_iptable_merge(dest->iptable, source->iptable, pos);
if (nodes > dest->node_count)
dest->node_count = nodes;
return (ISC_R_SUCCESS);
}
/*
* Like dns_acl_match, but matches against the single ACL element 'e'
* rather than a complete ACL, and returns ISC_TRUE iff it matched.
*
* To determine whether the match was prositive or negative, the
* caller should examine e->negative. Since the element 'e' may be
* a reference to a named ACL or a nested ACL, a matching element
* returned through 'matchelt' is not necessarily 'e' itself.
*/
isc_boolean_t
dns_aclelement_match(const isc_netaddr_t *reqaddr,
const dns_name_t *reqsigner,
@ -186,90 +323,66 @@ dns_aclelement_match(const isc_netaddr_t *reqaddr,
const dns_aclelement_t **matchelt)
{
dns_acl_t *inner = NULL;
const isc_netaddr_t *addr;
isc_netaddr_t v4addr;
int indirectmatch;
isc_result_t result;
switch (e->type) {
case dns_aclelementtype_ipprefix:
if (env == NULL ||
env->match_mapped == ISC_FALSE ||
reqaddr->family != AF_INET6 ||
!IN6_IS_ADDR_V4MAPPED(&reqaddr->type.in6))
addr = reqaddr;
else {
isc_netaddr_fromv4mapped(&v4addr, reqaddr);
addr = &v4addr;
}
if (isc_netaddr_eqprefix(addr,
&e->u.ip_prefix.address,
e->u.ip_prefix.prefixlen))
goto matched;
break;
case dns_aclelementtype_keyname:
switch (e->type) {
case dns_aclelementtype_keyname:
if (reqsigner != NULL &&
dns_name_equal(reqsigner, &e->u.keyname))
goto matched;
break;
case dns_aclelementtype_nestedacl:
inner = e->u.nestedacl;
nested:
result = dns_acl_match(reqaddr, reqsigner,
inner,
env,
&indirectmatch, matchelt);
INSIST(result == ISC_R_SUCCESS);
dns_name_equal(reqsigner, &e->keyname)) {
if (matchelt != NULL)
*matchelt = e;
return (ISC_TRUE);
} else {
return (ISC_FALSE);
}
/*
* Treat negative matches in indirect ACLs as
* "no match".
* That way, a negated indirect ACL will never become
* a surprise positive match through double negation.
* XXXDCL this should be documented.
*/
if (indirectmatch > 0)
goto matchelt_set;
/*
* A negative indirect match may have set *matchelt,
* but we don't want it set when we return.
*/
if (matchelt != NULL)
*matchelt = NULL;
break;
case dns_aclelementtype_any:
matched:
if (matchelt != NULL)
*matchelt = e;
matchelt_set:
return (ISC_TRUE);
case dns_aclelementtype_localhost:
if (env != NULL && env->localhost != NULL) {
inner = env->localhost;
goto nested;
} else {
break;
}
case dns_aclelementtype_localnets:
if (env != NULL && env->localnets != NULL) {
inner = env->localnets;
goto nested;
} else {
break;
}
default:
INSIST(0);
break;
}
case dns_aclelementtype_nestedacl:
inner = e->nestedacl;
break;
case dns_aclelementtype_localhost:
if (env == NULL || env->localhost == NULL)
return (ISC_FALSE);
inner = env->localhost;
break;
case dns_aclelementtype_localnets:
if (env == NULL || env->localnets == NULL)
return (ISC_FALSE);
inner = env->localnets;
break;
default:
/* Should be impossible */
INSIST(0);
}
result = dns_acl_match(reqaddr, reqsigner, inner, env,
&indirectmatch, matchelt);
INSIST(result == ISC_R_SUCCESS);
/*
* Treat negative matches in indirect ACLs as "no match".
* That way, a negated indirect ACL will never become a
* surprise positive match through double negation.
* XXXDCL this should be documented.
*/
if (indirectmatch > 0) {
if (matchelt != NULL)
*matchelt = e;
return (ISC_TRUE);
}
/*
* A negative indirect match may have set *matchelt, but we don't
* want it set when we return.
*/
if (matchelt != NULL)
*matchelt = NULL;
return (ISC_FALSE);
}
@ -285,15 +398,8 @@ destroy(dns_acl_t *dacl) {
unsigned int i;
for (i = 0; i < dacl->length; i++) {
dns_aclelement_t *de = &dacl->elements[i];
switch (de->type) {
case dns_aclelementtype_keyname:
dns_name_free(&de->u.keyname, dacl->mctx);
break;
case dns_aclelementtype_nestedacl:
dns_acl_detach(&de->u.nestedacl);
break;
default:
break;
if (de->type == dns_aclelementtype_keyname) {
dns_name_free(&de->keyname, dacl->mctx);
}
}
if (dacl->elements != NULL)
@ -301,6 +407,8 @@ destroy(dns_acl_t *dacl) {
dacl->alloc * sizeof(dns_aclelement_t));
if (dacl->name != NULL)
isc_mem_free(dacl->mctx, dacl->name);
if (dacl->iptable != NULL)
dns_iptable_detach(&dacl->iptable);
isc_refcount_destroy(&dacl->refcount);
dacl->magic = 0;
isc_mem_put(dacl->mctx, dacl, sizeof(*dacl));
@ -317,69 +425,62 @@ dns_acl_detach(dns_acl_t **aclp) {
*aclp = NULL;
}
isc_boolean_t
dns_aclelement_equal(const dns_aclelement_t *ea, const dns_aclelement_t *eb) {
if (ea->type != eb->type)
return (ISC_FALSE);
switch (ea->type) {
case dns_aclelementtype_ipprefix:
if (ea->u.ip_prefix.prefixlen !=
eb->u.ip_prefix.prefixlen)
return (ISC_FALSE);
return (isc_netaddr_eqprefix(&ea->u.ip_prefix.address,
&eb->u.ip_prefix.address,
ea->u.ip_prefix.prefixlen));
case dns_aclelementtype_keyname:
return (dns_name_equal(&ea->u.keyname, &eb->u.keyname));
case dns_aclelementtype_nestedacl:
return (dns_acl_equal(ea->u.nestedacl, eb->u.nestedacl));
case dns_aclelementtype_localhost:
case dns_aclelementtype_localnets:
case dns_aclelementtype_any:
return (ISC_TRUE);
default:
INSIST(0);
return (ISC_FALSE);
}
}
static isc_boolean_t insecure_prefix_found;
isc_boolean_t
dns_acl_equal(const dns_acl_t *a, const dns_acl_t *b) {
unsigned int i;
if (a == b)
return (ISC_TRUE);
if (a->length != b->length)
return (ISC_FALSE);
for (i = 0; i < a->length; i++) {
if (! dns_aclelement_equal(&a->elements[i],
&b->elements[i]))
return (ISC_FALSE);
}
return (ISC_TRUE);
}
/*
* Called via isc_radix_walk() to find IP table nodes that are
* insecure.
*/
static void
is_insecure(isc_prefix_t *prefix, isc_boolean_t *data) {
/* Negated entries are always secure */
if(* (isc_boolean_t *)data == ISC_FALSE) {
return;
}
static isc_boolean_t
is_loopback(const dns_aclipprefix_t *p) {
switch (p->address.family) {
case AF_INET:
if (p->prefixlen == 32 &&
htonl(p->address.type.in.s_addr) == INADDR_LOOPBACK)
return (ISC_TRUE);
/* If loopback prefix found, return */
switch (prefix->family) {
case AF_INET:
if (prefix->bitlen == 32 &&
htonl(prefix->add.sin.s_addr) == INADDR_LOOPBACK)
return;
break;
case AF_INET6:
if (p->prefixlen == 128 &&
IN6_IS_ADDR_LOOPBACK(&p->address.type.in6))
return (ISC_TRUE);
case AF_INET6:
if (prefix->bitlen == 128 &&
IN6_IS_ADDR_LOOPBACK(&prefix->add.sin6))
return;
break;
default:
default:
break;
}
return (ISC_FALSE);
/* Non-negated, non-loopback */
insecure_prefix_found = ISC_TRUE;
return;
}
/*
* Return ISC_TRUE iff the acl 'a' is considered insecure, that is,
* if it contains IP addresses other than those of the local host.
* This is intended for applications such as printing warning
* messages for suspect ACLs; it is not intended for making access
* control decisions. We make no guarantee that an ACL for which
* this function returns ISC_FALSE is safe.
*/
isc_boolean_t
dns_acl_isinsecure(const dns_acl_t *a) {
unsigned int i;
/*
* Walk radix tree to find out if there are any non-negated,
* non-loopback prefixes.
*/
insecure_prefix_found = ISC_FALSE;
isc_radix_process(a->iptable->radix, is_insecure);
if(insecure_prefix_found)
return(ISC_TRUE);
/* Now check non-radix elements */
for (i = 0; i < a->length; i++) {
dns_aclelement_t *e = &a->elements[i];
@ -388,34 +489,31 @@ dns_acl_isinsecure(const dns_acl_t *a) {
continue;
switch (e->type) {
case dns_aclelementtype_ipprefix:
/* The loopback address is considered secure. */
if (! is_loopback(&e->u.ip_prefix))
return (ISC_TRUE);
continue;
case dns_aclelementtype_keyname:
case dns_aclelementtype_localhost:
case dns_aclelementtype_keyname:
case dns_aclelementtype_localhost:
continue;
case dns_aclelementtype_nestedacl:
if (dns_acl_isinsecure(e->u.nestedacl))
return (ISC_TRUE);
continue;
case dns_aclelementtype_localnets:
case dns_aclelementtype_any:
case dns_aclelementtype_nestedacl:
if (dns_acl_isinsecure(e->nestedacl))
return (ISC_TRUE);
continue;
case dns_aclelementtype_localnets:
return (ISC_TRUE);
default:
default:
INSIST(0);
return (ISC_TRUE);
}
}
/* No insecure elements were found. */
return (ISC_FALSE);
}
/*
* Initialize ACL environment, setting up localhost and localnets ACLs
*/
isc_result_t
dns_aclenv_init(isc_mem_t *mctx, dns_aclenv_t *env) {
isc_result_t result;

View File

@ -13,7 +13,7 @@
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
# $Id: Makefile.in,v 1.52 2007/06/19 23:47:16 tbox Exp $
# $Id: Makefile.in,v 1.53 2007/09/12 01:09:08 each Exp $
srcdir = @srcdir@
VPATH = @srcdir@
@ -24,7 +24,7 @@ top_srcdir = @top_srcdir@
HEADERS = acl.h adb.h byaddr.h cache.h callbacks.h \
cert.h compress.h \
db.h dbiterator.h dbtable.h diff.h dispatch.h \
dnssec.h ds.h events.h fixedname.h journal.h keyflags.h \
dnssec.h ds.h events.h fixedname.h iptable.h journal.h keyflags.h \
keytable.h keyvalues.h lib.h log.h master.h masterdump.h \
message.h name.h ncache.h \
nsec.h peer.h portlist.h rbt.h rcode.h \

View File

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: acl.h,v 1.29 2007/06/19 23:47:16 tbox Exp $ */
/* $Id: acl.h,v 1.30 2007/09/12 01:09:08 each Exp $ */
#ifndef DNS_ACL_H
#define DNS_ACL_H 1
@ -40,6 +40,7 @@
#include <dns/name.h>
#include <dns/types.h>
#include <dns/iptable.h>
/***
*** Types
@ -64,17 +65,17 @@ struct dns_aclipprefix {
struct dns_aclelement {
dns_aclelemettype_t type;
isc_boolean_t negative;
union {
dns_aclipprefix_t ip_prefix;
dns_name_t keyname;
dns_acl_t *nestedacl;
} u;
dns_name_t keyname;
dns_acl_t *nestedacl;
int node_num;
};
struct dns_acl {
unsigned int magic;
isc_mem_t *mctx;
isc_refcount_t refcount;
dns_iptable_t *iptable;
#define node_count iptable->radix->num_added_node
dns_aclelement_t *elements;
unsigned int alloc; /*%< Elements allocated */
unsigned int length; /*%< Elements initialized */
@ -100,14 +101,9 @@ ISC_LANG_BEGINDECLS
isc_result_t
dns_acl_create(isc_mem_t *mctx, int n, dns_acl_t **target);
/*%<
* Create a new ACL with room for 'n' elements.
* The elements are uninitialized and the length is 0.
*/
isc_result_t
dns_acl_appendelement(dns_acl_t *acl, const dns_aclelement_t *elt);
/*%<
* Append an element to an existing ACL.
* Create a new ACL, including an IP table and an array with room
* for 'n' ACL elements. The elements are uninitialized and the
* length is 0.
*/
isc_result_t
@ -122,18 +118,36 @@ dns_acl_none(isc_mem_t *mctx, dns_acl_t **target);
* Create a new ACL that matches nothing.
*/
isc_boolean_t
dns_acl_isany(dns_acl_t *acl);
/*%<
* Test whether ACL is set to "{ any; }"
*/
isc_boolean_t
dns_acl_isnone(dns_acl_t *acl);
/*%<
* Test whether ACL is set to "{ none; }"
*/
isc_result_t
dns_acl_merge(dns_acl_t *dest, dns_acl_t *source, isc_boolean_t pos);
/*%<
* Merge the contents of one ACL into another. Call dns_iptable_merge()
* for the IP tables, then concatenate the element arrays.
*
* If pos is set to false, then the nested ACL is to be negated. This
* means reverse the sense of each *positive* element or IP table node,
* but leave negatives alone, so as to prevent a double-negative causing
* an unexpected postive match in the parent ACL.
*/
void
dns_acl_attach(dns_acl_t *source, dns_acl_t **target);
void
dns_acl_detach(dns_acl_t **aclp);
isc_boolean_t
dns_aclelement_equal(const dns_aclelement_t *ea, const dns_aclelement_t *eb);
isc_boolean_t
dns_acl_equal(const dns_acl_t *a, const dns_acl_t *b);
isc_boolean_t
dns_acl_isinsecure(const dns_acl_t *a);
/*%<
@ -147,6 +161,9 @@ dns_acl_isinsecure(const dns_acl_t *a);
isc_result_t
dns_aclenv_init(isc_mem_t *mctx, dns_aclenv_t *env);
/*%<
* Initialize ACL environment, setting up localhost and localnets ACLs
*/
void
dns_aclenv_copy(dns_aclenv_t *t, dns_aclenv_t *s);
@ -168,19 +185,17 @@ dns_acl_match(const isc_netaddr_t *reqaddr,
* Match the address 'reqaddr', and optionally the key name 'reqsigner',
* against 'acl'. 'reqsigner' may be NULL.
*
* If there is a positive match, '*match' will be set to a positive value
* indicating the distance from the beginning of the list.
*
* If there is a negative match, '*match' will be set to a negative value
* whose absolute value indicates the distance from the beginning of
* the list.
*
* If there is a match (either positive or negative) and 'matchelt' is
* non-NULL, *matchelt will be attached to the primitive
* (non-indirect) address match list element that matched.
* If there is a match, '*match' will be set to an integer whose absolute
* value corresponds to the order in which the matching value was inserted
* into the ACL. For a positive match, this value will be positive; for a
* negative match, it will be negative.
*
* If there is no match, *match will be set to zero.
*
* If there is a match in the element list (either positive or negative)
* and 'matchelt' is non-NULL, *matchelt will be pointed to the matching
* element.
*
* Returns:
*\li #ISC_R_SUCCESS Always succeeds.
*/
@ -193,30 +208,14 @@ dns_aclelement_match(const isc_netaddr_t *reqaddr,
const dns_aclelement_t **matchelt);
/*%<
* Like dns_acl_match, but matches against the single ACL element 'e'
* rather than a complete list and returns ISC_TRUE iff it matched.
* rather than a complete ACL, and returns ISC_TRUE iff it matched.
*
* To determine whether the match was prositive or negative, the
* caller should examine e->negative. Since the element 'e' may be
* a reference to a named ACL or a nested ACL, the matching element
* a reference to a named ACL or a nested ACL, a matching element
* returned through 'matchelt' is not necessarily 'e' itself.
*/
isc_result_t
dns_acl_elementmatch(const dns_acl_t *acl,
const dns_aclelement_t *elt,
const dns_aclelement_t **matchelt);
/*%<
* Search for an ACL element in 'acl' which is exactly the same as 'elt'.
* If there is one, and 'matchelt' is non NULL, then '*matchelt' will point
* to the entry.
*
* This function is intended to be used for avoiding duplicated ACL entries
* before adding an entry.
*
* Returns:
*\li #ISC_R_SUCCESS Match succeeds.
*\li #ISC_R_NOTFOUND Match fails.
*/
ISC_LANG_ENDDECLS
#endif /* DNS_ACL_H */

View File

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: types.h,v 1.125 2007/06/19 23:47:17 tbox Exp $ */
/* $Id: types.h,v 1.126 2007/09/12 01:09:08 each Exp $ */
#ifndef DNS_TYPES_H
#define DNS_TYPES_H 1
@ -68,6 +68,7 @@ typedef struct dns_fetch dns_fetch_t;
typedef struct dns_fixedname dns_fixedname_t;
typedef struct dns_forwarders dns_forwarders_t;
typedef struct dns_fwdtable dns_fwdtable_t;
typedef struct dns_iptable dns_iptable_t;
typedef isc_uint16_t dns_keyflags_t;
typedef struct dns_keynode dns_keynode_t;
typedef struct dns_keytable dns_keytable_t;

View File

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: zone.c,v 1.467 2007/08/30 05:08:42 marka Exp $ */
/* $Id: zone.c,v 1.468 2007/09/12 01:09:08 each Exp $ */
/*! \file */
@ -1144,11 +1144,7 @@ zone_isdynamic(dns_zone_t *zone) {
zone->type == dns_zone_stub ||
(!zone->update_disabled && zone->ssutable != NULL) ||
(!zone->update_disabled && zone->update_acl != NULL &&
! (zone->update_acl->length == 1 &&
zone->update_acl->elements[0].negative == ISC_TRUE
&&
zone->update_acl->elements[0].type ==
dns_aclelementtype_any))));
!dns_acl_isnone(zone->update_acl))));
}

View File

@ -13,7 +13,7 @@
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
# $Id: Makefile.in,v 1.91 2007/06/19 23:47:17 tbox Exp $
# $Id: Makefile.in,v 1.92 2007/09/12 01:09:08 each Exp $
srcdir = @srcdir@
VPATH = @srcdir@
@ -58,7 +58,7 @@ OBJS = @ISC_EXTRA_OBJS@ \
lex.@O@ lfsr.@O@ lib.@O@ log.@O@ \
md5.@O@ mem.@O@ mutexblock.@O@ \
netaddr.@O@ netscope.@O@ ondestroy.@O@ \
parseint.@O@ quota.@O@ random.@O@ \
parseint.@O@ quota.@O@ radix.@O@ random.@O@ \
ratelimiter.@O@ refcount.@O@ region.@O@ result.@O@ rwlock.@O@ \
serial.@O@ sha1.@O@ sha2.@O@ sockaddr.@O@ \
string.@O@ strtoul.@O@ symtab.@O@ task.@O@ taskpool.@O@ \
@ -73,7 +73,7 @@ SRCS = @ISC_EXTRA_SRCS@ \
lex.c lfsr.c lib.c log.c \
md5.c mem.c mutexblock.c \
netaddr.c netscope.c ondestroy.c \
parseint.c quota.c random.c \
parseint.c quota.c radix.c random.c \
ratelimiter.c refcount.c region.c result.c rwlock.c \
serial.c sha1.c sha2.c sockaddr.c string.c strtoul.c \
symtab.c task.c taskpool.c timer.c version.c

View File

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: aclconf.c,v 1.9 2007/06/19 23:47:22 tbox Exp $ */
/* $Id: aclconf.c,v 1.10 2007/09/12 01:09:08 each Exp $ */
#include <config.h>
@ -27,6 +27,7 @@
#include <isccfg/aclconf.h>
#include <dns/acl.h>
#include <dns/iptable.h>
#include <dns/fixedname.h>
#include <dns/log.h>
@ -40,6 +41,7 @@ cfg_aclconfctx_init(cfg_aclconfctx_t *ctx) {
void
cfg_aclconfctx_destroy(cfg_aclconfctx_t *ctx) {
dns_acl_t *dacl, *next;
for (dacl = ISC_LIST_HEAD(ctx->named_acl_cache);
dacl != NULL;
dacl = next)
@ -67,7 +69,9 @@ get_acl_def(const cfg_obj_t *cctx, const char *name, const cfg_obj_t **ret) {
const cfg_obj_t *acl = cfg_listelt_value(elt);
const char *aclname = cfg_obj_asstring(cfg_tuple_get(acl, "name"));
if (strcasecmp(aclname, name) == 0) {
*ret = cfg_tuple_get(acl, "value");
if (ret != NULL) {
*ret = cfg_tuple_get(acl, "value");
}
return (ISC_R_SUCCESS);
}
}
@ -77,7 +81,8 @@ get_acl_def(const cfg_obj_t *cctx, const char *name, const cfg_obj_t **ret) {
static isc_result_t
convert_named_acl(const cfg_obj_t *nameobj, const cfg_obj_t *cctx,
isc_log_t *lctx, cfg_aclconfctx_t *ctx,
isc_mem_t *mctx, dns_acl_t **target)
isc_mem_t *mctx, int nest_level,
dns_acl_t **target)
{
isc_result_t result;
const cfg_obj_t *cacl = NULL;
@ -115,7 +120,8 @@ convert_named_acl(const cfg_obj_t *nameobj, const cfg_obj_t *cctx,
DE_CONST(aclname, loop.name);
loop.magic = LOOP_MAGIC;
ISC_LIST_APPEND(ctx->named_acl_cache, &loop, nextincache);
result = cfg_acl_fromconfig(cacl, cctx, lctx, ctx, mctx, &dacl);
result = cfg_acl_fromconfig(cacl, cctx, lctx, ctx, mctx,
nest_level, &dacl);
ISC_LIST_UNLINK(ctx->named_acl_cache, &loop, nextincache);
loop.magic = 0;
loop.name = NULL;
@ -160,25 +166,47 @@ cfg_acl_fromconfig(const cfg_obj_t *caml,
isc_log_t *lctx,
cfg_aclconfctx_t *ctx,
isc_mem_t *mctx,
int nest_level,
dns_acl_t **target)
{
isc_result_t result;
unsigned int count;
dns_acl_t *dacl = NULL;
dns_acl_t *dacl = NULL, *inneracl = NULL;
dns_aclelement_t *de;
const cfg_listelt_t *elt;
dns_iptable_t *iptab;
REQUIRE(target != NULL && *target == NULL);
REQUIRE(target != NULL);
REQUIRE(*target == NULL || ISC_MAGIC_VALID(target, DNS_ACL_MAGIC));
count = 0;
for (elt = cfg_list_first(caml);
elt != NULL;
elt = cfg_list_next(elt))
count++;
result = dns_acl_create(mctx, count, &dacl);
if (result != ISC_R_SUCCESS)
return (result);
if (*target != NULL) {
/*
* If target already points to an ACL, then we're being
* called recursively to configure a nested ACL. The
* nested ACL's contents should just be absorbed into its
* parent ACL.
*/
dacl = *target;
} else {
/*
* Need to allocate a new ACL structure. Count the items
* in the ACL definition and allocate space for that many
* elements (even though some or all of them may end up in
* the iptable instead of the element array).
*/
unsigned int element_count = 0;
for (elt = cfg_list_first(caml);
elt != NULL;
elt = cfg_list_next(elt)) {
const cfg_obj_t *ce = cfg_listelt_value(elt);
if (cfg_obj_istuple(ce))
ce = cfg_tuple_get(ce, "value");
if (cfg_obj_isnetprefix(ce))
element_count++;
}
result = dns_acl_create(mctx, element_count, &dacl);
if (result != ISC_R_SUCCESS)
return (result);
}
de = dacl->elements;
for (elt = cfg_list_first(caml);
@ -186,56 +214,114 @@ cfg_acl_fromconfig(const cfg_obj_t *caml,
elt = cfg_list_next(elt))
{
const cfg_obj_t *ce = cfg_listelt_value(elt);
isc_boolean_t neg;
if (cfg_obj_istuple(ce)) {
/* This must be a negated element. */
ce = cfg_tuple_get(ce, "value");
de->negative = ISC_TRUE;
} else {
de->negative = ISC_FALSE;
}
neg = ISC_TRUE;
} else
neg = ISC_FALSE;
/*
* If nest_level is nonzero, then every element is
* to be stored as a separate, nested ACL rather than
* merged into the main iptable.
*/
iptab = dacl->iptable;
if (nest_level) {
result = dns_acl_create(mctx, 0, &de->nestedacl);
if (result != ISC_R_SUCCESS)
goto cleanup;
iptab = de->nestedacl->iptable;
}
if (cfg_obj_isnetprefix(ce)) {
/* Network prefix */
de->type = dns_aclelementtype_ipprefix;
isc_netaddr_t addr;
unsigned int bitlen;
cfg_obj_asnetprefix(ce,
&de->u.ip_prefix.address,
&de->u.ip_prefix.prefixlen);
} else if (cfg_obj_istype(ce, &cfg_type_keyref)) {
/* Key name */
de->type = dns_aclelementtype_keyname;
dns_name_init(&de->u.keyname, NULL);
result = convert_keyname(ce, lctx, mctx,
&de->u.keyname);
cfg_obj_asnetprefix(ce, &addr, &bitlen);
result = dns_iptable_addprefix(iptab, &addr, bitlen,
ISC_TF(!neg));
if (result != ISC_R_SUCCESS)
goto cleanup;
continue;
} else if (cfg_obj_islist(ce)) {
/* Nested ACL */
de->type = dns_aclelementtype_nestedacl;
result = cfg_acl_fromconfig(ce, cctx, lctx, ctx,
mctx, &de->u.nestedacl);
/*
* If we're nesting ACLs, put the nested
* ACL onto the elements list; otherwise
* merge it into *this* ACL.
*/
if (nest_level == 0) {
result = cfg_acl_fromconfig(ce,
cctx, lctx, ctx, mctx, 0,
&dacl);
} else {
de->type = dns_aclelementtype_nestedacl;
de->negative = neg;
result = cfg_acl_fromconfig(ce,
cctx, lctx, ctx, mctx,
nest_level - 1,
&de->nestedacl);
}
if (result != ISC_R_SUCCESS)
goto cleanup;
goto cleanup;
continue;
} else if (cfg_obj_isstring(ce)) {
/* ACL name */
const char *name = cfg_obj_asstring(ce);
if (strcasecmp(name, "localhost") == 0) {
if (strcasecmp(name, "any") == 0) {
/* iptable entry with zero bit length */
dns_iptable_addprefix(iptab, NULL, 0,
ISC_TRUE);
continue;
} else if (strcasecmp(name, "none") == 0) {
/* negated "any" */
dns_iptable_addprefix(iptab, NULL, 0,
ISC_FALSE);
continue;
} else if (strcasecmp(name, "localhost") == 0) {
de->type = dns_aclelementtype_localhost;
de->negative = neg;
} else if (strcasecmp(name, "localnets") == 0) {
de->type = dns_aclelementtype_localnets;
} else if (strcasecmp(name, "any") == 0) {
de->type = dns_aclelementtype_any;
} else if (strcasecmp(name, "none") == 0) {
de->type = dns_aclelementtype_any;
de->negative = ISC_TF(! de->negative);
de->negative = neg;
} else {
de->type = dns_aclelementtype_nestedacl;
result = convert_named_acl(ce, cctx, lctx,
ctx, mctx,
&de->u.nestedacl);
result = get_acl_def(cctx, name, NULL);
if (result == ISC_R_SUCCESS) {
/* found it in acl definitions */
inneracl = NULL;
result = convert_named_acl(ce, cctx,
lctx, ctx, mctx,
nest_level
? (nest_level - 1)
: 0,
&inneracl);
}
if (result != ISC_R_SUCCESS)
goto cleanup;
if (nest_level) {
de->type = dns_aclelementtype_nestedacl,
de->negative = neg;
de->nestedacl = inneracl;
} else {
dns_acl_merge(dacl, inneracl,
ISC_TF(!neg));
dns_acl_detach(&inneracl);
}
continue;
}
} else if (cfg_obj_istype(ce, &cfg_type_keyref)) {
/* Key name */
de->type = dns_aclelementtype_keyname;
de->negative = neg;
dns_name_init(&de->keyname, NULL);
result = convert_keyname(ce, lctx, mctx,
&de->keyname);
if (result != ISC_R_SUCCESS)
goto cleanup;
} else {
cfg_obj_log(ce, lctx, ISC_LOG_WARNING,
"address match list contains "
@ -243,6 +329,16 @@ cfg_acl_fromconfig(const cfg_obj_t *caml,
result = ISC_R_FAILURE;
goto cleanup;
}
/*
* XXX each: This should only be reached for localhost,
* localnets and keyname elements -- probably should
* be refactored for clearer flow
*/
if (nest_level && de->type != dns_aclelementtype_nestedacl)
dns_acl_detach(&de->nestedacl);
de->node_num = dacl->node_count++;
de++;
dacl->length++;
}

View File

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: aclconf.h,v 1.8 2007/06/19 23:47:22 tbox Exp $ */
/* $Id: aclconf.h,v 1.9 2007/09/12 01:09:08 each Exp $ */
#ifndef ISCCFG_ACLCONF_H
#define ISCCFG_ACLCONF_H 1
@ -28,6 +28,7 @@
typedef struct cfg_aclconfctx {
ISC_LIST(dns_acl_t) named_acl_cache;
ISC_LIST(dns_iptable_t) named_iptable_cache;
} cfg_aclconfctx_t;
/***
@ -54,6 +55,7 @@ cfg_acl_fromconfig(const cfg_obj_t *caml,
isc_log_t *lctx,
cfg_aclconfctx_t *ctx,
isc_mem_t *mctx,
int nest_level,
dns_acl_t **target);
/*
* Construct a new dns_acl_t from configuration data in 'caml' and