PageRenderTime 28ms CodeModel.GetById 14ms app.highlight 11ms RepoModel.GetById 1ms app.codeStats 0ms

/contrib/bind9/lib/dns/iptable.c

https://bitbucket.org/freebsd/freebsd-head/
C | 188 lines | 122 code | 30 blank | 36 comment | 36 complexity | 8bfaefb2b6940670dfbc7151c8fe1f82 MD5 | raw file
  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}