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