xref: /netbsd-src/external/mpl/bind/dist/lib/dns/nametree.c (revision bcda20f65a8566e103791ec395f7f499ef322704)
1*bcda20f6Schristos /*	$NetBSD: nametree.c,v 1.2 2025/01/26 16:25:23 christos Exp $	*/
29689912eSchristos 
39689912eSchristos /*
49689912eSchristos  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
59689912eSchristos  *
69689912eSchristos  * SPDX-License-Identifier: MPL-2.0
79689912eSchristos  *
89689912eSchristos  * This Source Code Form is subject to the terms of the Mozilla Public
99689912eSchristos  * License, v. 2.0. If a copy of the MPL was not distributed with this
109689912eSchristos  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
119689912eSchristos  *
129689912eSchristos  * See the COPYRIGHT file distributed with this work for additional
139689912eSchristos  * information regarding copyright ownership.
149689912eSchristos  */
159689912eSchristos 
169689912eSchristos /*! \file */
179689912eSchristos 
189689912eSchristos #include <stdbool.h>
199689912eSchristos 
209689912eSchristos #include <isc/mem.h>
219689912eSchristos #include <isc/refcount.h>
229689912eSchristos #include <isc/result.h>
239689912eSchristos #include <isc/string.h>
249689912eSchristos #include <isc/urcu.h>
259689912eSchristos #include <isc/util.h>
269689912eSchristos 
279689912eSchristos #include <dns/fixedname.h>
289689912eSchristos #include <dns/nametree.h>
299689912eSchristos #include <dns/qp.h>
309689912eSchristos 
319689912eSchristos #define NAMETREE_MAGIC	   ISC_MAGIC('N', 'T', 'r', 'e')
329689912eSchristos #define VALID_NAMETREE(kt) ISC_MAGIC_VALID(kt, NAMETREE_MAGIC)
339689912eSchristos 
349689912eSchristos struct dns_nametree {
359689912eSchristos 	unsigned int magic;
369689912eSchristos 	isc_mem_t *mctx;
379689912eSchristos 	isc_refcount_t references;
389689912eSchristos 	dns_nametree_type_t type;
399689912eSchristos 	dns_qpmulti_t *table;
409689912eSchristos 	char name[64];
419689912eSchristos };
429689912eSchristos 
439689912eSchristos struct dns_ntnode {
449689912eSchristos 	isc_mem_t *mctx;
459689912eSchristos 	isc_refcount_t references;
469689912eSchristos 	dns_name_t name;
479689912eSchristos 	bool set;
489689912eSchristos 	uint8_t *bits;
499689912eSchristos };
509689912eSchristos 
519689912eSchristos /* QP trie methods */
529689912eSchristos static void
539689912eSchristos qp_attach(void *uctx, void *pval, uint32_t ival);
549689912eSchristos static void
559689912eSchristos qp_detach(void *uctx, void *pval, uint32_t ival);
569689912eSchristos static size_t
579689912eSchristos qp_makekey(dns_qpkey_t key, void *uctx, void *pval, uint32_t ival);
589689912eSchristos static void
599689912eSchristos qp_triename(void *uctx, char *buf, size_t size);
609689912eSchristos 
619689912eSchristos static dns_qpmethods_t qpmethods = {
629689912eSchristos 	qp_attach,
639689912eSchristos 	qp_detach,
649689912eSchristos 	qp_makekey,
659689912eSchristos 	qp_triename,
669689912eSchristos };
679689912eSchristos 
689689912eSchristos static void
699689912eSchristos destroy_ntnode(dns_ntnode_t *node) {
709689912eSchristos 	if (node->bits != NULL) {
719689912eSchristos 		isc_mem_cput(node->mctx, node->bits, node->bits[0],
729689912eSchristos 			     sizeof(char));
739689912eSchristos 	}
749689912eSchristos 	dns_name_free(&node->name, node->mctx);
759689912eSchristos 	isc_mem_putanddetach(&node->mctx, node, sizeof(dns_ntnode_t));
769689912eSchristos }
779689912eSchristos 
789689912eSchristos #if DNS_NAMETREE_TRACE
799689912eSchristos ISC_REFCOUNT_TRACE_IMPL(dns_ntnode, destroy_ntnode);
809689912eSchristos #else
819689912eSchristos ISC_REFCOUNT_IMPL(dns_ntnode, destroy_ntnode);
829689912eSchristos #endif
839689912eSchristos 
849689912eSchristos void
859689912eSchristos dns_nametree_create(isc_mem_t *mctx, dns_nametree_type_t type, const char *name,
869689912eSchristos 		    dns_nametree_t **ntp) {
879689912eSchristos 	dns_nametree_t *nametree = NULL;
889689912eSchristos 
899689912eSchristos 	REQUIRE(ntp != NULL && *ntp == NULL);
909689912eSchristos 
919689912eSchristos 	nametree = isc_mem_get(mctx, sizeof(*nametree));
929689912eSchristos 	*nametree = (dns_nametree_t){
939689912eSchristos 		.magic = NAMETREE_MAGIC,
949689912eSchristos 		.type = type,
959689912eSchristos 	};
969689912eSchristos 	isc_mem_attach(mctx, &nametree->mctx);
979689912eSchristos 	isc_refcount_init(&nametree->references, 1);
989689912eSchristos 
999689912eSchristos 	if (name != NULL) {
1009689912eSchristos 		strlcpy(nametree->name, name, sizeof(nametree->name));
1019689912eSchristos 	}
1029689912eSchristos 
1039689912eSchristos 	dns_qpmulti_create(mctx, &qpmethods, nametree, &nametree->table);
1049689912eSchristos 	*ntp = nametree;
1059689912eSchristos }
1069689912eSchristos 
1079689912eSchristos static void
1089689912eSchristos destroy_nametree(dns_nametree_t *nametree) {
1099689912eSchristos 	nametree->magic = 0;
1109689912eSchristos 
1119689912eSchristos 	dns_qpmulti_destroy(&nametree->table);
1129689912eSchristos 
1139689912eSchristos 	isc_mem_putanddetach(&nametree->mctx, nametree, sizeof(*nametree));
1149689912eSchristos }
1159689912eSchristos 
1169689912eSchristos #if DNS_NAMETREE_TRACE
1179689912eSchristos ISC_REFCOUNT_TRACE_IMPL(dns_nametree, destroy_nametree);
1189689912eSchristos #else
1199689912eSchristos ISC_REFCOUNT_IMPL(dns_nametree, destroy_nametree);
1209689912eSchristos #endif
1219689912eSchristos 
1229689912eSchristos static dns_ntnode_t *
1239689912eSchristos newnode(isc_mem_t *mctx, const dns_name_t *name) {
1249689912eSchristos 	dns_ntnode_t *node = isc_mem_get(mctx, sizeof(*node));
1259689912eSchristos 	*node = (dns_ntnode_t){
1269689912eSchristos 		.name = DNS_NAME_INITEMPTY,
1279689912eSchristos 	};
1289689912eSchristos 	isc_mem_attach(mctx, &node->mctx);
1299689912eSchristos 	isc_refcount_init(&node->references, 1);
1309689912eSchristos 
1319689912eSchristos 	dns_name_dupwithoffsets(name, mctx, &node->name);
1329689912eSchristos 
1339689912eSchristos 	return node;
1349689912eSchristos }
1359689912eSchristos 
1369689912eSchristos static bool
1379689912eSchristos matchbit(unsigned char *bits, uint32_t val) {
1389689912eSchristos 	unsigned int len = val / 8 + 2;
1399689912eSchristos 	unsigned int mask = 1 << (val % 8);
1409689912eSchristos 
1419689912eSchristos 	if (len <= bits[0] && (bits[len - 1] & mask) != 0) {
1429689912eSchristos 		return true;
1439689912eSchristos 	}
1449689912eSchristos 	return false;
1459689912eSchristos }
1469689912eSchristos 
1479689912eSchristos isc_result_t
1489689912eSchristos dns_nametree_add(dns_nametree_t *nametree, const dns_name_t *name,
1499689912eSchristos 		 uint32_t value) {
1509689912eSchristos 	isc_result_t result;
1519689912eSchristos 	dns_qp_t *qp = NULL;
1529689912eSchristos 	uint32_t size, pos, mask, count = 0;
1539689912eSchristos 	dns_ntnode_t *old = NULL, *new = NULL;
1549689912eSchristos 
1559689912eSchristos 	REQUIRE(VALID_NAMETREE(nametree));
1569689912eSchristos 	REQUIRE(name != NULL);
1579689912eSchristos 
1589689912eSchristos 	dns_qpmulti_write(nametree->table, &qp);
1599689912eSchristos 
1609689912eSchristos 	switch (nametree->type) {
1619689912eSchristos 	case DNS_NAMETREE_BOOL:
1629689912eSchristos 		new = newnode(nametree->mctx, name);
1639689912eSchristos 		new->set = value;
1649689912eSchristos 		break;
1659689912eSchristos 
1669689912eSchristos 	case DNS_NAMETREE_COUNT:
1679689912eSchristos 		new = newnode(nametree->mctx, name);
1689689912eSchristos 		new->set = true;
1699689912eSchristos 		result = dns_qp_deletename(qp, name, (void **)&old, &count);
1709689912eSchristos 		if (result == ISC_R_SUCCESS) {
1719689912eSchristos 			count += 1;
1729689912eSchristos 		}
1739689912eSchristos 		break;
1749689912eSchristos 
1759689912eSchristos 	case DNS_NAMETREE_BITS:
1769689912eSchristos 		result = dns_qp_getname(qp, name, (void **)&old, NULL);
1779689912eSchristos 		if (result == ISC_R_SUCCESS && matchbit(old->bits, value)) {
1789689912eSchristos 			goto out;
1799689912eSchristos 		}
1809689912eSchristos 
1819689912eSchristos 		size = pos = value / 8 + 2;
1829689912eSchristos 		mask = 1 << (value % 8);
1839689912eSchristos 
1849689912eSchristos 		if (old != NULL && old->bits[0] > pos) {
1859689912eSchristos 			size = old->bits[0];
1869689912eSchristos 		}
1879689912eSchristos 
1889689912eSchristos 		new = newnode(nametree->mctx, name);
1899689912eSchristos 		new->bits = isc_mem_cget(nametree->mctx, size, sizeof(char));
1909689912eSchristos 		if (result == ISC_R_SUCCESS) {
1919689912eSchristos 			memmove(new->bits, old->bits, old->bits[0]);
1929689912eSchristos 			result = dns_qp_deletename(qp, name, NULL, NULL);
1939689912eSchristos 			INSIST(result == ISC_R_SUCCESS);
1949689912eSchristos 		}
1959689912eSchristos 
1969689912eSchristos 		new->bits[pos - 1] |= mask;
1979689912eSchristos 		new->bits[0] = size;
1989689912eSchristos 		break;
1999689912eSchristos 	default:
2009689912eSchristos 		UNREACHABLE();
2019689912eSchristos 	}
2029689912eSchristos 
2039689912eSchristos 	result = dns_qp_insert(qp, new, count);
2049689912eSchristos 	/*
2059689912eSchristos 	 * We detach the node here, so any dns_qp_deletename() will
2069689912eSchristos 	 * destroy the node directly.
2079689912eSchristos 	 */
2089689912eSchristos 	dns_ntnode_detach(&new);
2099689912eSchristos 
2109689912eSchristos out:
2119689912eSchristos 	dns_qp_compact(qp, DNS_QPGC_MAYBE);
2129689912eSchristos 	dns_qpmulti_commit(nametree->table, &qp);
2139689912eSchristos 	return result;
2149689912eSchristos }
2159689912eSchristos 
2169689912eSchristos isc_result_t
2179689912eSchristos dns_nametree_delete(dns_nametree_t *nametree, const dns_name_t *name) {
2189689912eSchristos 	isc_result_t result;
2199689912eSchristos 	dns_qp_t *qp = NULL;
2209689912eSchristos 	dns_ntnode_t *old = NULL;
2219689912eSchristos 	uint32_t count;
2229689912eSchristos 
2239689912eSchristos 	REQUIRE(VALID_NAMETREE(nametree));
2249689912eSchristos 	REQUIRE(name != NULL);
2259689912eSchristos 
2269689912eSchristos 	dns_qpmulti_write(nametree->table, &qp);
2279689912eSchristos 	result = dns_qp_deletename(qp, name, (void **)&old, &count);
2289689912eSchristos 	switch (nametree->type) {
2299689912eSchristos 	case DNS_NAMETREE_BOOL:
2309689912eSchristos 	case DNS_NAMETREE_BITS:
2319689912eSchristos 		break;
2329689912eSchristos 
2339689912eSchristos 	case DNS_NAMETREE_COUNT:
2349689912eSchristos 		if (result == ISC_R_SUCCESS && count-- != 0) {
2359689912eSchristos 			dns_ntnode_t *new = newnode(nametree->mctx, name);
2369689912eSchristos 			new->set = true;
2379689912eSchristos 			result = dns_qp_insert(qp, new, count);
2389689912eSchristos 			INSIST(result == ISC_R_SUCCESS);
2399689912eSchristos 			dns_ntnode_detach(&new);
2409689912eSchristos 		}
2419689912eSchristos 		break;
2429689912eSchristos 	default:
2439689912eSchristos 		UNREACHABLE();
2449689912eSchristos 	}
2459689912eSchristos 	dns_qp_compact(qp, DNS_QPGC_MAYBE);
2469689912eSchristos 	dns_qpmulti_commit(nametree->table, &qp);
2479689912eSchristos 
2489689912eSchristos 	return result;
2499689912eSchristos }
2509689912eSchristos 
2519689912eSchristos isc_result_t
2529689912eSchristos dns_nametree_find(dns_nametree_t *nametree, const dns_name_t *name,
2539689912eSchristos 		  dns_ntnode_t **ntnodep) {
2549689912eSchristos 	isc_result_t result;
2559689912eSchristos 	dns_ntnode_t *node = NULL;
2569689912eSchristos 	dns_qpread_t qpr;
2579689912eSchristos 
2589689912eSchristos 	REQUIRE(VALID_NAMETREE(nametree));
2599689912eSchristos 	REQUIRE(name != NULL);
2609689912eSchristos 	REQUIRE(ntnodep != NULL && *ntnodep == NULL);
2619689912eSchristos 
2629689912eSchristos 	dns_qpmulti_query(nametree->table, &qpr);
2639689912eSchristos 	result = dns_qp_getname(&qpr, name, (void **)&node, NULL);
2649689912eSchristos 	if (result == ISC_R_SUCCESS) {
2659689912eSchristos 		dns_ntnode_attach(node, ntnodep);
2669689912eSchristos 	}
2679689912eSchristos 	dns_qpread_destroy(nametree->table, &qpr);
2689689912eSchristos 
2699689912eSchristos 	return result;
2709689912eSchristos }
2719689912eSchristos 
2729689912eSchristos bool
2739689912eSchristos dns_nametree_covered(dns_nametree_t *nametree, const dns_name_t *name,
2749689912eSchristos 		     dns_name_t *found, uint32_t bit) {
2759689912eSchristos 	isc_result_t result;
2769689912eSchristos 	dns_qpread_t qpr;
2779689912eSchristos 	dns_ntnode_t *node = NULL;
2789689912eSchristos 	bool ret = false;
2799689912eSchristos 
2809689912eSchristos 	REQUIRE(VALID_NAMETREE(nametree));
2819689912eSchristos 
2829689912eSchristos 	dns_qpmulti_query(nametree->table, &qpr);
2839689912eSchristos 	result = dns_qp_lookup(&qpr, name, NULL, NULL, NULL, (void **)&node,
2849689912eSchristos 			       NULL);
2859689912eSchristos 	if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
2869689912eSchristos 		if (found != NULL) {
2879689912eSchristos 			dns_name_copy(&node->name, found);
2889689912eSchristos 		}
2899689912eSchristos 		switch (nametree->type) {
2909689912eSchristos 		case DNS_NAMETREE_BOOL:
2919689912eSchristos 			ret = node->set;
2929689912eSchristos 			break;
2939689912eSchristos 		case DNS_NAMETREE_COUNT:
2949689912eSchristos 			ret = true;
2959689912eSchristos 			break;
2969689912eSchristos 		case DNS_NAMETREE_BITS:
2979689912eSchristos 			ret = matchbit(node->bits, bit);
2989689912eSchristos 			break;
2999689912eSchristos 		}
3009689912eSchristos 	}
3019689912eSchristos 
3029689912eSchristos 	dns_qpread_destroy(nametree->table, &qpr);
3039689912eSchristos 	return ret;
3049689912eSchristos }
3059689912eSchristos 
3069689912eSchristos static void
3079689912eSchristos qp_attach(void *uctx ISC_ATTR_UNUSED, void *pval,
3089689912eSchristos 	  uint32_t ival ISC_ATTR_UNUSED) {
3099689912eSchristos 	dns_ntnode_t *ntnode = pval;
3109689912eSchristos 	dns_ntnode_ref(ntnode);
3119689912eSchristos }
3129689912eSchristos 
3139689912eSchristos static void
3149689912eSchristos qp_detach(void *uctx ISC_ATTR_UNUSED, void *pval,
3159689912eSchristos 	  uint32_t ival ISC_ATTR_UNUSED) {
3169689912eSchristos 	dns_ntnode_t *ntnode = pval;
3179689912eSchristos 	dns_ntnode_detach(&ntnode);
3189689912eSchristos }
3199689912eSchristos 
3209689912eSchristos static size_t
3219689912eSchristos qp_makekey(dns_qpkey_t key, void *uctx ISC_ATTR_UNUSED, void *pval,
3229689912eSchristos 	   uint32_t ival ISC_ATTR_UNUSED) {
3239689912eSchristos 	dns_ntnode_t *ntnode = pval;
3249689912eSchristos 	return dns_qpkey_fromname(key, &ntnode->name);
3259689912eSchristos }
3269689912eSchristos 
3279689912eSchristos static void
3289689912eSchristos qp_triename(void *uctx, char *buf, size_t size) {
3299689912eSchristos 	dns_nametree_t *nametree = uctx;
3309689912eSchristos 	snprintf(buf, size, "%s nametree", nametree->name);
3319689912eSchristos }
332