1/* 2 * Copyright (C) 2007-2009 Internet Systems Consortium, Inc. ("ISC") 3 * 4 * Permission to use, copy, modify, and/or distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 9 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 10 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 11 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 12 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 13 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 14 * PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17/* $Id: iptable.c,v 1.15 2009/02/18 23:47:48 tbox Exp $ */ 18 19#include <config.h> 20 21#include <isc/mem.h> 22#include <isc/radix.h> 23 24#include <dns/acl.h> 25 26static void destroy_iptable(dns_iptable_t *dtab); 27 28/* 29 * Create a new IP table and the underlying radix structure 30 */ 31isc_result_t 32dns_iptable_create(isc_mem_t *mctx, dns_iptable_t **target) { 33 isc_result_t result; 34 dns_iptable_t *tab; 35 36 tab = isc_mem_get(mctx, sizeof(*tab)); 37 if (tab == NULL) 38 return (ISC_R_NOMEMORY); 39 tab->mctx = mctx; 40 isc_refcount_init(&tab->refcount, 1); 41 tab->radix = NULL; 42 tab->magic = DNS_IPTABLE_MAGIC; 43 44 result = isc_radix_create(mctx, &tab->radix, RADIX_MAXBITS); 45 if (result != ISC_R_SUCCESS) 46 goto cleanup; 47 48 *target = tab; 49 return (ISC_R_SUCCESS); 50 51 cleanup: 52 dns_iptable_detach(&tab); 53 return (result); 54} 55 56isc_boolean_t dns_iptable_neg = ISC_FALSE; 57isc_boolean_t dns_iptable_pos = ISC_TRUE; 58 59/* 60 * Add an IP prefix to an existing IP table 61 */ 62isc_result_t 63dns_iptable_addprefix(dns_iptable_t *tab, isc_netaddr_t *addr, 64 isc_uint16_t bitlen, isc_boolean_t pos) 65{ 66 isc_result_t result; 67 isc_prefix_t pfx; 68 isc_radix_node_t *node = NULL; 69 int family; 70 71 INSIST(DNS_IPTABLE_VALID(tab)); 72 INSIST(tab->radix); 73 74 NETADDR_TO_PREFIX_T(addr, pfx, bitlen); 75 76 result = isc_radix_insert(tab->radix, &node, NULL, &pfx); 77 if (result != ISC_R_SUCCESS) { 78 isc_refcount_destroy(&pfx.refcount); 79 return(result); 80 } 81 82 /* If a node already contains data, don't overwrite it */ 83 family = pfx.family; 84 if (family == AF_UNSPEC) { 85 /* "any" or "none" */ 86 INSIST(pfx.bitlen == 0); 87 if (pos) { 88 if (node->data[0] == NULL) 89 node->data[0] = &dns_iptable_pos; 90 if (node->data[1] == NULL) 91 node->data[1] = &dns_iptable_pos; 92 } else { 93 if (node->data[0] == NULL) 94 node->data[0] = &dns_iptable_neg; 95 if (node->data[1] == NULL) 96 node->data[1] = &dns_iptable_neg; 97 } 98 } else { 99 /* any other prefix */ 100 if (node->data[ISC_IS6(family)] == NULL) { 101 if (pos) 102 node->data[ISC_IS6(family)] = &dns_iptable_pos; 103 else 104 node->data[ISC_IS6(family)] = &dns_iptable_neg; 105 } 106 } 107 108 isc_refcount_destroy(&pfx.refcount); 109 return (ISC_R_SUCCESS); 110} 111 112/* 113 * Merge one IP table into another one. 114 */ 115isc_result_t 116dns_iptable_merge(dns_iptable_t *tab, dns_iptable_t *source, isc_boolean_t pos) 117{ 118 isc_result_t result; 119 isc_radix_node_t *node, *new_node; 120 int max_node = 0; 121 122 RADIX_WALK (source->radix->head, node) { 123 new_node = NULL; 124 result = isc_radix_insert (tab->radix, &new_node, node, NULL); 125 126 if (result != ISC_R_SUCCESS) 127 return(result); 128 129 /* 130 * If we're negating a nested ACL, then we should 131 * reverse the sense of every node. However, this 132 * could lead to a negative node in a nested ACL 133 * becoming a positive match in the parent, which 134 * could be a security risk. To prevent this, we 135 * just leave the negative nodes negative. 136 */ 137 if (!pos) { 138 if (node->data[0] && 139 *(isc_boolean_t *) node->data[0] == ISC_TRUE) 140 new_node->data[0] = &dns_iptable_neg; 141 142 if (node->data[1] && 143 *(isc_boolean_t *) node->data[1] == ISC_TRUE) 144 new_node->data[1] = &dns_iptable_neg; 145 } 146 147 if (node->node_num[0] > max_node) 148 max_node = node->node_num[0]; 149 if (node->node_num[1] > max_node) 150 max_node = node->node_num[1]; 151 } RADIX_WALK_END; 152 153 tab->radix->num_added_node += max_node; 154 return (ISC_R_SUCCESS); 155} 156 157void 158dns_iptable_attach(dns_iptable_t *source, dns_iptable_t **target) { 159 REQUIRE(DNS_IPTABLE_VALID(source)); 160 isc_refcount_increment(&source->refcount, NULL); 161 *target = source; 162} 163 164void 165dns_iptable_detach(dns_iptable_t **tabp) { 166 dns_iptable_t *tab = *tabp; 167 unsigned int refs; 168 REQUIRE(DNS_IPTABLE_VALID(tab)); 169 isc_refcount_decrement(&tab->refcount, &refs); 170 if (refs == 0) 171 destroy_iptable(tab); 172 *tabp = NULL; 173} 174 175static void 176destroy_iptable(dns_iptable_t *dtab) { 177 178 REQUIRE(DNS_IPTABLE_VALID(dtab)); 179 180 if (dtab->radix != NULL) { 181 isc_radix_destroy(dtab->radix, NULL); 182 dtab->radix = NULL; 183 } 184 185 isc_refcount_destroy(&dtab->refcount); 186 dtab->magic = 0; 187 isc_mem_put(dtab->mctx, dtab, sizeof(*dtab)); 188} 189