Home | History | Annotate | Line # | Download | only in dns
      1 /*	$NetBSD: iptable.c,v 1.7 2025/01/26 16:25:23 christos Exp $	*/
      2 
      3 /*
      4  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
      5  *
      6  * SPDX-License-Identifier: MPL-2.0
      7  *
      8  * This Source Code Form is subject to the terms of the Mozilla Public
      9  * License, v. 2.0. If a copy of the MPL was not distributed with this
     10  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
     11  *
     12  * See the COPYRIGHT file distributed with this work for additional
     13  * information regarding copyright ownership.
     14  */
     15 
     16 #include <inttypes.h>
     17 #include <stdbool.h>
     18 
     19 #include <isc/mem.h>
     20 #include <isc/radix.h>
     21 #include <isc/util.h>
     22 
     23 #include <dns/acl.h>
     24 
     25 /*
     26  * Create a new IP table and the underlying radix structure
     27  */
     28 void
     29 dns_iptable_create(isc_mem_t *mctx, dns_iptable_t **target) {
     30 	dns_iptable_t *tab = isc_mem_get(mctx, sizeof(*tab));
     31 	*tab = (dns_iptable_t){
     32 		.references = ISC_REFCOUNT_INITIALIZER(1),
     33 		.magic = DNS_IPTABLE_MAGIC,
     34 	};
     35 	isc_mem_attach(mctx, &tab->mctx);
     36 
     37 	isc_radix_create(mctx, &tab->radix, RADIX_MAXBITS);
     38 
     39 	*target = tab;
     40 }
     41 
     42 static bool dns_iptable_neg = false;
     43 static bool dns_iptable_pos = true;
     44 
     45 /*
     46  * Add an IP prefix to an existing IP table
     47  */
     48 isc_result_t
     49 dns_iptable_addprefix(dns_iptable_t *tab, const isc_netaddr_t *addr,
     50 		      uint16_t bitlen, bool pos) {
     51 	isc_result_t result;
     52 	isc_prefix_t pfx;
     53 	isc_radix_node_t *node = NULL;
     54 	int i;
     55 
     56 	INSIST(DNS_IPTABLE_VALID(tab));
     57 	INSIST(tab->radix != NULL);
     58 
     59 	NETADDR_TO_PREFIX_T(addr, pfx, bitlen);
     60 
     61 	result = isc_radix_insert(tab->radix, &node, NULL, &pfx);
     62 	if (result != ISC_R_SUCCESS) {
     63 		isc_refcount_destroy(&pfx.refcount);
     64 		return result;
     65 	}
     66 
     67 	/* If a node already contains data, don't overwrite it */
     68 	if (pfx.family == AF_UNSPEC) {
     69 		/* "any" or "none" */
     70 		INSIST(pfx.bitlen == 0);
     71 		for (i = 0; i < RADIX_FAMILIES; i++) {
     72 			if (node->data[i] == NULL) {
     73 				node->data[i] = pos ? &dns_iptable_pos
     74 						    : &dns_iptable_neg;
     75 			}
     76 		}
     77 	} else {
     78 		/* any other prefix */
     79 		int fam = ISC_RADIX_FAMILY(&pfx);
     80 		if (node->data[fam] == NULL) {
     81 			node->data[fam] = pos ? &dns_iptable_pos
     82 					      : &dns_iptable_neg;
     83 		}
     84 	}
     85 
     86 	isc_refcount_destroy(&pfx.refcount);
     87 	return ISC_R_SUCCESS;
     88 }
     89 
     90 /*
     91  * Merge one IP table into another one.
     92  */
     93 isc_result_t
     94 dns_iptable_merge(dns_iptable_t *tab, dns_iptable_t *source, bool pos) {
     95 	isc_result_t result;
     96 	isc_radix_node_t *node, *new_node;
     97 	int i, max_node = 0;
     98 
     99 	RADIX_WALK(source->radix->head, node) {
    100 		new_node = NULL;
    101 		result = isc_radix_insert(tab->radix, &new_node, node, NULL);
    102 
    103 		if (result != ISC_R_SUCCESS) {
    104 			return result;
    105 		}
    106 
    107 		/*
    108 		 * If we're negating a nested ACL, then we should
    109 		 * reverse the sense of every node.  However, this
    110 		 * could lead to a negative node in a nested ACL
    111 		 * becoming a positive match in the parent, which
    112 		 * could be a security risk.  To prevent this, we
    113 		 * just leave the negative nodes negative.
    114 		 */
    115 		for (i = 0; i < RADIX_FAMILIES; i++) {
    116 			if (!pos) {
    117 				if (node->data[i] && *(bool *)node->data[i]) {
    118 					new_node->data[i] = &dns_iptable_neg;
    119 				}
    120 			}
    121 			if (node->node_num[i] > max_node) {
    122 				max_node = node->node_num[i];
    123 			}
    124 		}
    125 	}
    126 	RADIX_WALK_END;
    127 
    128 	tab->radix->num_added_node += max_node;
    129 	return ISC_R_SUCCESS;
    130 }
    131 
    132 static void
    133 dns__iptable_destroy(dns_iptable_t *dtab) {
    134 	REQUIRE(DNS_IPTABLE_VALID(dtab));
    135 
    136 	dtab->magic = 0;
    137 
    138 	if (dtab->radix != NULL) {
    139 		isc_radix_destroy(dtab->radix, NULL);
    140 		dtab->radix = NULL;
    141 	}
    142 
    143 	isc_mem_putanddetach(&dtab->mctx, dtab, sizeof(*dtab));
    144 }
    145 
    146 #if DNS_IPTABLE_TRACE
    147 ISC_REFCOUNT_TRACE_IMPL(dns_iptable, dns__iptable_destroy);
    148 #else
    149 ISC_REFCOUNT_IMPL(dns_iptable, dns__iptable_destroy);
    150 #endif
    151