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