iptable.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2007-2009, 2013, 2014  Internet Systems Consortium, Inc. ("ISC")
00003  *
00004  * Permission to use, copy, modify, and/or distribute this software for any
00005  * purpose with or without fee is hereby granted, provided that the above
00006  * copyright notice and this permission notice appear in all copies.
00007  *
00008  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
00009  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00010  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
00011  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
00012  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
00013  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00014  * PERFORMANCE OF THIS SOFTWARE.
00015  */
00016 
00017 #include <config.h>
00018 
00019 #include <isc/mem.h>
00020 #include <isc/radix.h>
00021 
00022 #include <dns/acl.h>
00023 
00024 static void destroy_iptable(dns_iptable_t *dtab);
00025 
00026 /*
00027  * Create a new IP table and the underlying radix structure
00028  */
00029 isc_result_t
00030 dns_iptable_create(isc_mem_t *mctx, dns_iptable_t **target) {
00031         isc_result_t result;
00032         dns_iptable_t *tab;
00033 
00034         tab = isc_mem_get(mctx, sizeof(*tab));
00035         if (tab == NULL)
00036                 return (ISC_R_NOMEMORY);
00037         tab->mctx = NULL;
00038         isc_mem_attach(mctx, &tab->mctx);
00039         isc_refcount_init(&tab->refcount, 1);
00040         tab->radix = NULL;
00041         tab->magic = DNS_IPTABLE_MAGIC;
00042 
00043         result = isc_radix_create(mctx, &tab->radix, RADIX_MAXBITS);
00044         if (result != ISC_R_SUCCESS)
00045                 goto cleanup;
00046 
00047         *target = tab;
00048         return (ISC_R_SUCCESS);
00049 
00050  cleanup:
00051         dns_iptable_detach(&tab);
00052         return (result);
00053 }
00054 
00055 isc_boolean_t dns_iptable_neg = ISC_FALSE;
00056 isc_boolean_t dns_iptable_pos = ISC_TRUE;
00057 
00058 /*
00059  * Add an IP prefix to an existing IP table
00060  */
00061 isc_result_t
00062 dns_iptable_addprefix(dns_iptable_t *tab, isc_netaddr_t *addr,
00063                       isc_uint16_t bitlen, isc_boolean_t pos)
00064 {
00065         return(dns_iptable_addprefix2(tab, addr, bitlen, pos, ISC_FALSE));
00066 }
00067 
00068 isc_result_t
00069 dns_iptable_addprefix2(dns_iptable_t *tab, isc_netaddr_t *addr,
00070                        isc_uint16_t bitlen, isc_boolean_t pos,
00071                        isc_boolean_t is_ecs)
00072 {
00073         isc_result_t result;
00074         isc_prefix_t pfx;
00075         isc_radix_node_t *node = NULL;
00076         int i;
00077 
00078         INSIST(DNS_IPTABLE_VALID(tab));
00079         INSIST(tab->radix);
00080 
00081         NETADDR_TO_PREFIX_T(addr, pfx, bitlen, is_ecs);
00082 
00083         result = isc_radix_insert(tab->radix, &node, NULL, &pfx);
00084         if (result != ISC_R_SUCCESS) {
00085                 isc_refcount_destroy(&pfx.refcount);
00086                 return(result);
00087         }
00088 
00089         /* If a node already contains data, don't overwrite it */
00090         if (pfx.family == AF_UNSPEC) {
00091                 /* "any" or "none" */
00092                 INSIST(pfx.bitlen == 0);
00093                 for (i = 0; i < 4; i++) {
00094                         if (node->data[i] == NULL)
00095                                 node->data[i] = pos ? &dns_iptable_pos
00096                                                     : &dns_iptable_neg;
00097                 }
00098         } else {
00099                 /* any other prefix */
00100                 int offset = ISC_RADIX_OFF(&pfx);
00101                 if (node->data[offset] == NULL) {
00102                         node->data[offset] = pos ? &dns_iptable_pos
00103                                                  : &dns_iptable_neg;
00104                 }
00105         }
00106 
00107         isc_refcount_destroy(&pfx.refcount);
00108         return (ISC_R_SUCCESS);
00109 }
00110 
00111 /*
00112  * Merge one IP table into another one.
00113  */
00114 isc_result_t
00115 dns_iptable_merge(dns_iptable_t *tab, dns_iptable_t *source, isc_boolean_t pos)
00116 {
00117         isc_result_t result;
00118         isc_radix_node_t *node, *new_node;
00119         int i, max_node = 0;
00120 
00121         RADIX_WALK (source->radix->head, node) {
00122                 new_node = NULL;
00123                 result = isc_radix_insert (tab->radix, &new_node, node, NULL);
00124 
00125                 if (result != ISC_R_SUCCESS)
00126                         return(result);
00127 
00128                 /*
00129                  * If we're negating a nested ACL, then we should
00130                  * reverse the sense of every node.  However, this
00131                  * could lead to a negative node in a nested ACL
00132                  * becoming a positive match in the parent, which
00133                  * could be a security risk.  To prevent this, we
00134                  * just leave the negative nodes negative.
00135                  */
00136                 for (i = 0; i < 4; i++) {
00137                         if (!pos) {
00138                                 if (node->data[i] &&
00139                                     *(isc_boolean_t *) node->data[i])
00140                                         new_node->data[i] = &dns_iptable_neg;
00141                         }
00142                         if (node->node_num[i] > max_node)
00143                                 max_node = node->node_num[i];
00144                 }
00145         } RADIX_WALK_END;
00146 
00147         tab->radix->num_added_node += max_node;
00148         return (ISC_R_SUCCESS);
00149 }
00150 
00151 void
00152 dns_iptable_attach(dns_iptable_t *source, dns_iptable_t **target) {
00153         REQUIRE(DNS_IPTABLE_VALID(source));
00154         isc_refcount_increment(&source->refcount, NULL);
00155         *target = source;
00156 }
00157 
00158 void
00159 dns_iptable_detach(dns_iptable_t **tabp) {
00160         dns_iptable_t *tab = *tabp;
00161         unsigned int refs;
00162         REQUIRE(DNS_IPTABLE_VALID(tab));
00163         isc_refcount_decrement(&tab->refcount, &refs);
00164         if (refs == 0)
00165                 destroy_iptable(tab);
00166         *tabp = NULL;
00167 }
00168 
00169 static void
00170 destroy_iptable(dns_iptable_t *dtab) {
00171 
00172         REQUIRE(DNS_IPTABLE_VALID(dtab));
00173 
00174         if (dtab->radix != NULL) {
00175                 isc_radix_destroy(dtab->radix, NULL);
00176                 dtab->radix = NULL;
00177         }
00178 
00179         isc_refcount_destroy(&dtab->refcount);
00180         dtab->magic = 0;
00181         isc_mem_putanddetach(&dtab->mctx, dtab, sizeof(*dtab));
00182 }

Generated on Tue Apr 28 17:40:57 2015 by Doxygen 1.5.4 for BIND9 Internals 9.11.0pre-alpha