2001-11-20 01:18:15 +00:00
|
|
|
/*
|
2017-09-08 13:39:09 -07:00
|
|
|
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
2001-11-20 01:18:15 +00:00
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: MPL-2.0
|
2021-06-03 08:37:05 +02:00
|
|
|
*
|
2001-11-20 01:18:15 +00:00
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
2018-02-23 09:53:12 +01:00
|
|
|
*
|
2001-11-20 01:18:15 +00:00
|
|
|
* See the COPYRIGHT file distributed with this work for additional
|
|
|
|
* information regarding copyright ownership.
|
|
|
|
*/
|
|
|
|
|
2005-04-27 04:57:32 +00:00
|
|
|
/*! \file
|
|
|
|
* \brief
|
2005-08-18 00:57:31 +00:00
|
|
|
* The built-in "version", "hostname", "id", "authors" and "empty" databases.
|
2001-11-20 01:18:15 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
2023-02-08 22:22:40 -08:00
|
|
|
#include <isc/lex.h>
|
2005-08-18 00:57:31 +00:00
|
|
|
#include <isc/mem.h>
|
2001-11-20 01:18:15 +00:00
|
|
|
#include <isc/result.h>
|
|
|
|
#include <isc/util.h>
|
|
|
|
|
2023-02-08 22:22:40 -08:00
|
|
|
#include <dns/callbacks.h>
|
|
|
|
#include <dns/dbiterator.h>
|
|
|
|
#include <dns/rdatalist.h>
|
|
|
|
#include <dns/rdatasetiter.h>
|
|
|
|
#include <dns/types.h>
|
2001-11-20 01:18:15 +00:00
|
|
|
|
|
|
|
#include <named/builtin.h>
|
|
|
|
#include <named/globals.h>
|
|
|
|
#include <named/os.h>
|
|
|
|
#include <named/server.h>
|
|
|
|
|
2023-02-09 23:21:57 -08:00
|
|
|
#define BDBNODE_MAGIC ISC_MAGIC('B', 'D', 'B', 'N')
|
|
|
|
#define VALID_BDBNODE(bdbl) ISC_MAGIC_VALID(bdbl, BDBNODE_MAGIC)
|
|
|
|
|
|
|
|
/*%
|
|
|
|
* Note that "impmagic" is not the first four bytes of the struct, so
|
|
|
|
* ISC_MAGIC_VALID cannot be used here.
|
|
|
|
*/
|
|
|
|
#define BDB_MAGIC ISC_MAGIC('B', 'D', 'B', '-')
|
|
|
|
#define VALID_BDB(bdb) ((bdb) != NULL && (bdb)->common.impmagic == BDB_MAGIC)
|
|
|
|
|
|
|
|
#define BDB_DNS64 0x00000001U
|
|
|
|
|
|
|
|
typedef struct bdbimplementation {
|
|
|
|
unsigned int flags;
|
|
|
|
dns_dbimplementation_t *dbimp;
|
|
|
|
} bdbimplementation_t;
|
|
|
|
|
|
|
|
typedef struct bdbnode bdbnode_t;
|
|
|
|
typedef struct bdb {
|
|
|
|
dns_db_t common;
|
|
|
|
bdbimplementation_t *implementation;
|
|
|
|
isc_result_t (*lookup)(bdbnode_t *node);
|
|
|
|
char *server;
|
|
|
|
char *contact;
|
|
|
|
} bdb_t;
|
|
|
|
|
|
|
|
struct bdbnode {
|
Decouple database and node lifetimes by adding node-specific vtables
All databases in the codebase follow the same structure: a database is
an associative container from DNS names to nodes, and each node is an
associative container from RR types to RR data.
Each database implementation (qpzone, qpcache, sdlz, builtin, dyndb) has
its own corresponding node type (qpznode, qpcnode, etc). However, some
code needs to work with nodes generically regardless of their specific
type - for example, to acquire locks, manage references, or
register/unregister slabs from the heap.
Currently, these generic node operations are implemented as methods in
the database vtable, which creates problematic coupling between database
and node lifetimes. If a node outlives its parent database, the node
destructor will destroy all RR data, and each RR data destructor will
try to unregister from heaps by calling a virtual function from the
database vtable. Since the database was already freed, this causes a
crash.
This commit breaks the coupling by standardizing the layout of all
database nodes, adding a dedicated vtable for node operations, and
moving node-specific methods from the database vtable to the node
vtable.
2025-06-05 11:51:29 +02:00
|
|
|
DBNODE_FIELDS;
|
|
|
|
|
2023-02-09 23:21:57 -08:00
|
|
|
isc_refcount_t references;
|
|
|
|
bdb_t *bdb;
|
|
|
|
ISC_LIST(dns_rdatalist_t) lists;
|
|
|
|
ISC_LIST(isc_buffer_t) buffers;
|
|
|
|
ISC_LINK(bdbnode_t) link;
|
|
|
|
dns_rdatacallbacks_t callbacks;
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef struct bdb_rdatasetiter {
|
|
|
|
dns_rdatasetiter_t common;
|
|
|
|
dns_rdatalist_t *current;
|
|
|
|
} bdb_rdatasetiter_t;
|
2001-11-20 01:18:15 +00:00
|
|
|
|
|
|
|
static isc_result_t
|
2023-02-09 23:21:57 -08:00
|
|
|
findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
|
|
|
|
dns_rdatatype_t type, dns_rdatatype_t covers, isc_stdtime_t now,
|
2023-01-05 09:12:35 +01:00
|
|
|
dns_rdataset_t *rdataset,
|
|
|
|
dns_rdataset_t *sigrdataset DNS__DB_FLARG);
|
2023-02-09 23:21:57 -08:00
|
|
|
|
Decouple database and node lifetimes by adding node-specific vtables
All databases in the codebase follow the same structure: a database is
an associative container from DNS names to nodes, and each node is an
associative container from RR types to RR data.
Each database implementation (qpzone, qpcache, sdlz, builtin, dyndb) has
its own corresponding node type (qpznode, qpcnode, etc). However, some
code needs to work with nodes generically regardless of their specific
type - for example, to acquire locks, manage references, or
register/unregister slabs from the heap.
Currently, these generic node operations are implemented as methods in
the database vtable, which creates problematic coupling between database
and node lifetimes. If a node outlives its parent database, the node
destructor will destroy all RR data, and each RR data destructor will
try to unregister from heaps by calling a virtual function from the
database vtable. Since the database was already freed, this causes a
crash.
This commit breaks the coupling by standardizing the layout of all
database nodes, adding a dedicated vtable for node operations, and
moving node-specific methods from the database vtable to the node
vtable.
2025-06-05 11:51:29 +02:00
|
|
|
/*
|
|
|
|
* Node methods forward declarations
|
|
|
|
*/
|
2023-02-09 23:21:57 -08:00
|
|
|
static void
|
Decouple database and node lifetimes by adding node-specific vtables
All databases in the codebase follow the same structure: a database is
an associative container from DNS names to nodes, and each node is an
associative container from RR types to RR data.
Each database implementation (qpzone, qpcache, sdlz, builtin, dyndb) has
its own corresponding node type (qpznode, qpcnode, etc). However, some
code needs to work with nodes generically regardless of their specific
type - for example, to acquire locks, manage references, or
register/unregister slabs from the heap.
Currently, these generic node operations are implemented as methods in
the database vtable, which creates problematic coupling between database
and node lifetimes. If a node outlives its parent database, the node
destructor will destroy all RR data, and each RR data destructor will
try to unregister from heaps by calling a virtual function from the
database vtable. Since the database was already freed, this causes a
crash.
This commit breaks the coupling by standardizing the layout of all
database nodes, adding a dedicated vtable for node operations, and
moving node-specific methods from the database vtable to the node
vtable.
2025-06-05 11:51:29 +02:00
|
|
|
bdbnode_attachnode(dns_dbnode_t *source, dns_dbnode_t **targetp DNS__DB_FLARG);
|
2023-02-09 23:21:57 -08:00
|
|
|
static void
|
Decouple database and node lifetimes by adding node-specific vtables
All databases in the codebase follow the same structure: a database is
an associative container from DNS names to nodes, and each node is an
associative container from RR types to RR data.
Each database implementation (qpzone, qpcache, sdlz, builtin, dyndb) has
its own corresponding node type (qpznode, qpcnode, etc). However, some
code needs to work with nodes generically regardless of their specific
type - for example, to acquire locks, manage references, or
register/unregister slabs from the heap.
Currently, these generic node operations are implemented as methods in
the database vtable, which creates problematic coupling between database
and node lifetimes. If a node outlives its parent database, the node
destructor will destroy all RR data, and each RR data destructor will
try to unregister from heaps by calling a virtual function from the
database vtable. Since the database was already freed, this causes a
crash.
This commit breaks the coupling by standardizing the layout of all
database nodes, adding a dedicated vtable for node operations, and
moving node-specific methods from the database vtable to the node
vtable.
2025-06-05 11:51:29 +02:00
|
|
|
bdbnode_detachnode(dns_dbnode_t **nodep DNS__DB_FLARG);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Node methods structure
|
|
|
|
*/
|
|
|
|
static dns_dbnode_methods_t bdbnode_methods = (dns_dbnode_methods_t){
|
|
|
|
.attachnode = bdbnode_attachnode,
|
|
|
|
.detachnode = bdbnode_detachnode,
|
|
|
|
};
|
2023-02-09 23:21:57 -08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Helper functions to convert text to wire forma.
|
|
|
|
*/
|
2005-08-18 00:57:31 +00:00
|
|
|
static isc_result_t
|
2023-02-09 23:21:57 -08:00
|
|
|
putrdata(bdbnode_t *node, dns_rdatatype_t typeval, dns_ttl_t ttl,
|
|
|
|
const unsigned char *rdatap, unsigned int rdlen) {
|
|
|
|
dns_rdatalist_t *rdatalist = NULL;
|
|
|
|
dns_rdata_t *rdata = NULL;
|
|
|
|
isc_buffer_t *rdatabuf = NULL;
|
|
|
|
isc_mem_t *mctx = NULL;
|
|
|
|
isc_region_t region;
|
|
|
|
|
|
|
|
mctx = node->bdb->common.mctx;
|
|
|
|
|
|
|
|
rdatalist = ISC_LIST_HEAD(node->lists);
|
|
|
|
while (rdatalist != NULL) {
|
|
|
|
if (rdatalist->type == typeval) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
rdatalist = ISC_LIST_NEXT(rdatalist, link);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rdatalist == NULL) {
|
|
|
|
rdatalist = isc_mem_get(mctx, sizeof(dns_rdatalist_t));
|
|
|
|
dns_rdatalist_init(rdatalist);
|
|
|
|
rdatalist->rdclass = node->bdb->common.rdclass;
|
|
|
|
rdatalist->type = typeval;
|
|
|
|
rdatalist->ttl = ttl;
|
|
|
|
ISC_LIST_APPEND(node->lists, rdatalist, link);
|
|
|
|
} else if (rdatalist->ttl != ttl) {
|
|
|
|
return DNS_R_BADTTL;
|
|
|
|
}
|
|
|
|
|
|
|
|
rdata = isc_mem_get(mctx, sizeof(dns_rdata_t));
|
|
|
|
|
|
|
|
isc_buffer_allocate(mctx, &rdatabuf, rdlen);
|
2023-03-30 22:34:12 +02:00
|
|
|
region.base = UNCONST(rdatap);
|
2023-02-09 23:21:57 -08:00
|
|
|
region.length = rdlen;
|
|
|
|
isc_buffer_copyregion(rdatabuf, ®ion);
|
|
|
|
isc_buffer_usedregion(rdatabuf, ®ion);
|
|
|
|
dns_rdata_init(rdata);
|
|
|
|
dns_rdata_fromregion(rdata, rdatalist->rdclass, rdatalist->type,
|
|
|
|
®ion);
|
|
|
|
ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
|
|
|
|
ISC_LIST_APPEND(node->buffers, rdatabuf, link);
|
|
|
|
|
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2011-01-07 04:31:39 +00:00
|
|
|
static isc_result_t
|
2023-02-09 23:21:57 -08:00
|
|
|
putrr(bdbnode_t *node, const char *type, dns_ttl_t ttl, const char *data) {
|
|
|
|
isc_result_t result;
|
|
|
|
dns_rdatatype_t typeval;
|
|
|
|
isc_lex_t *lex = NULL;
|
|
|
|
isc_mem_t *mctx = NULL;
|
|
|
|
const dns_name_t *origin = NULL;
|
|
|
|
isc_buffer_t *rb = NULL;
|
|
|
|
isc_buffer_t b;
|
|
|
|
|
|
|
|
REQUIRE(VALID_BDBNODE(node));
|
|
|
|
REQUIRE(type != NULL);
|
|
|
|
REQUIRE(data != NULL);
|
|
|
|
|
|
|
|
mctx = node->bdb->common.mctx;
|
|
|
|
origin = &node->bdb->common.origin;
|
|
|
|
|
|
|
|
isc_constregion_t r = { .base = type, .length = strlen(type) };
|
|
|
|
result = dns_rdatatype_fromtext(&typeval, (isc_textregion_t *)&r);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
isc_lex_create(mctx, 64, &lex);
|
|
|
|
|
|
|
|
size_t datalen = strlen(data);
|
|
|
|
isc_buffer_constinit(&b, data, datalen);
|
|
|
|
isc_buffer_add(&b, datalen);
|
|
|
|
|
|
|
|
result = isc_lex_openbuffer(lex, &b);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
isc_buffer_allocate(mctx, &rb, DNS_RDATA_MAXLENGTH);
|
|
|
|
result = dns_rdata_fromtext(NULL, node->bdb->common.rdclass, typeval,
|
|
|
|
lex, origin, 0, mctx, rb, &node->callbacks);
|
|
|
|
isc_lex_destroy(&lex);
|
|
|
|
|
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
result = putrdata(node, typeval, ttl, isc_buffer_base(rb),
|
|
|
|
isc_buffer_usedlength(rb));
|
|
|
|
}
|
|
|
|
|
|
|
|
isc_buffer_free(&rb);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Reasonable default SOA values */
|
|
|
|
#define DEFAULT_REFRESH 28800U /* 8 hours */
|
|
|
|
#define DEFAULT_RETRY 7200U /* 2 hours */
|
|
|
|
#define DEFAULT_EXPIRE 604800U /* 7 days */
|
|
|
|
#define DEFAULT_MINIMUM 86400U /* 1 day */
|
|
|
|
#define DEFAULT_TTL (60 * 60 * 24)
|
|
|
|
|
2018-07-05 15:29:30 +10:00
|
|
|
static isc_result_t
|
2023-02-09 23:21:57 -08:00
|
|
|
putsoa(bdbnode_t *node, const char *mname, const char *rname, uint32_t serial) {
|
|
|
|
char str[2 * DNS_NAME_MAXTEXT + 5 * (sizeof("2147483647")) + 7];
|
|
|
|
int n;
|
2001-11-20 01:18:15 +00:00
|
|
|
|
2023-02-09 23:21:57 -08:00
|
|
|
REQUIRE(mname != NULL);
|
|
|
|
REQUIRE(rname != NULL);
|
2001-11-20 01:18:15 +00:00
|
|
|
|
2023-02-09 23:21:57 -08:00
|
|
|
n = snprintf(str, sizeof(str), "%s %s %u %u %u %u %u", mname, rname,
|
|
|
|
serial, DEFAULT_REFRESH, DEFAULT_RETRY, DEFAULT_EXPIRE,
|
|
|
|
DEFAULT_MINIMUM);
|
|
|
|
if (n >= (int)sizeof(str) || n < 0) {
|
|
|
|
return ISC_R_NOSPACE;
|
|
|
|
}
|
|
|
|
return putrr(node, "SOA", DEFAULT_TTL, str);
|
|
|
|
}
|
2001-11-20 01:18:15 +00:00
|
|
|
|
2023-02-09 23:21:57 -08:00
|
|
|
static isc_result_t
|
|
|
|
puttxt(bdbnode_t *node, const char *text) {
|
|
|
|
unsigned char buf[256];
|
|
|
|
unsigned int len = strlen(text);
|
2001-11-20 01:18:15 +00:00
|
|
|
|
2023-02-09 23:21:57 -08:00
|
|
|
if (len > 255) {
|
|
|
|
len = 255; /* Silently truncate */
|
|
|
|
}
|
|
|
|
buf[0] = len;
|
|
|
|
memmove(&buf[1], text, len);
|
|
|
|
return putrdata(node, dns_rdatatype_txt, 0, buf, len + 1);
|
|
|
|
}
|
2001-11-20 01:18:15 +00:00
|
|
|
|
2012-04-11 12:17:57 +10:00
|
|
|
/*
|
2023-02-09 23:21:57 -08:00
|
|
|
* Builtin database implementation functions.
|
2012-04-11 12:17:57 +10:00
|
|
|
*/
|
2023-02-09 23:21:57 -08:00
|
|
|
|
|
|
|
/* Precomputed HEX * 16 or 1 table. */
|
2012-04-11 12:17:57 +10:00
|
|
|
static const unsigned char hex16[256] = {
|
|
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*00*/
|
|
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*10*/
|
|
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*20*/
|
|
|
|
0, 16, 32, 48, 64, 80, 96, 112, 128, 144, 1, 1, 1, 1, 1, 1, /*30*/
|
|
|
|
1, 160, 176, 192, 208, 224, 240, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*40*/
|
|
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*50*/
|
|
|
|
1, 160, 176, 192, 208, 224, 240, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*60*/
|
|
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*70*/
|
|
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*80*/
|
|
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*90*/
|
|
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*A0*/
|
|
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*B0*/
|
|
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*C0*/
|
|
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*D0*/
|
|
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*E0*/
|
|
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 /*F0*/
|
|
|
|
};
|
|
|
|
|
2018-07-05 15:29:30 +10:00
|
|
|
static const unsigned char decimal[] = "0123456789";
|
|
|
|
static const unsigned char ipv4only[] = "\010ipv4only\004arpa";
|
2012-04-11 12:17:57 +10:00
|
|
|
|
|
|
|
static size_t
|
|
|
|
dns64_rdata(unsigned char *v, size_t start, unsigned char *rdata) {
|
|
|
|
size_t i, j = 0;
|
|
|
|
|
2012-08-24 07:32:50 +10:00
|
|
|
for (i = 0; i < 4U; i++) {
|
2012-04-11 12:17:57 +10:00
|
|
|
unsigned char c = v[start++];
|
2012-08-24 07:32:50 +10:00
|
|
|
if (start == 7U) {
|
2012-04-11 12:17:57 +10:00
|
|
|
start++;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2012-04-11 12:17:57 +10:00
|
|
|
if (c > 99) {
|
|
|
|
rdata[j++] = 3;
|
|
|
|
rdata[j++] = decimal[c / 100];
|
|
|
|
c = c % 100;
|
|
|
|
rdata[j++] = decimal[c / 10];
|
|
|
|
c = c % 10;
|
|
|
|
rdata[j++] = decimal[c];
|
|
|
|
} else if (c > 9) {
|
|
|
|
rdata[j++] = 2;
|
|
|
|
rdata[j++] = decimal[c / 10];
|
|
|
|
c = c % 10;
|
|
|
|
rdata[j++] = decimal[c];
|
|
|
|
} else {
|
|
|
|
rdata[j++] = 1;
|
|
|
|
rdata[j++] = decimal[c];
|
|
|
|
}
|
|
|
|
}
|
2014-01-08 16:27:10 -08:00
|
|
|
memmove(&rdata[j], "\07in-addr\04arpa", 14);
|
2012-04-11 12:17:57 +10:00
|
|
|
return j + 14;
|
|
|
|
}
|
2011-01-07 04:31:39 +00:00
|
|
|
|
|
|
|
static isc_result_t
|
2023-02-09 23:21:57 -08:00
|
|
|
dns64_cname(const dns_name_t *zone, const dns_name_t *name, bdbnode_t *node) {
|
2012-04-11 12:17:57 +10:00
|
|
|
size_t zlen, nlen, j, len;
|
|
|
|
unsigned char v[16], n;
|
2011-01-07 04:31:39 +00:00
|
|
|
unsigned int i;
|
2012-04-11 12:17:57 +10:00
|
|
|
unsigned char rdata[sizeof("123.123.123.123.in-addr.arpa.")];
|
|
|
|
unsigned char *ndata;
|
2011-01-07 04:31:39 +00:00
|
|
|
|
|
|
|
/*
|
2012-04-11 12:17:57 +10:00
|
|
|
* The combined length of the zone and name is 74.
|
2011-01-07 04:31:39 +00:00
|
|
|
*
|
2012-04-11 12:17:57 +10:00
|
|
|
* The minimum zone length is 10 ((3)ip6(4)arpa(0)).
|
2011-01-07 04:31:39 +00:00
|
|
|
*
|
2012-04-11 12:17:57 +10:00
|
|
|
* The length of name should always be even as we are expecting
|
2011-01-07 04:31:39 +00:00
|
|
|
* a series of nibbles.
|
|
|
|
*/
|
2012-04-11 12:17:57 +10:00
|
|
|
zlen = zone->length;
|
|
|
|
nlen = name->length;
|
|
|
|
if ((zlen + nlen) > 74U || zlen < 10U || (nlen % 2) != 0U) {
|
2011-01-07 04:31:39 +00:00
|
|
|
return ISC_R_NOTFOUND;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2011-01-07 04:31:39 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Check that name is a series of nibbles.
|
|
|
|
* Compute the byte values that correspond to the nibbles as we go.
|
|
|
|
*
|
|
|
|
* Shift the final result 4 bits, by setting 'i' to 1, if we if we
|
|
|
|
* have a odd number of nibbles so that "must be zero" tests below
|
|
|
|
* are byte aligned and we correctly return ISC_R_NOTFOUND or
|
|
|
|
* ISC_R_SUCCESS. We will not generate a CNAME in this case.
|
|
|
|
*/
|
2012-04-11 12:17:57 +10:00
|
|
|
ndata = name->ndata;
|
|
|
|
i = (nlen % 4) == 2U ? 1 : 0;
|
2011-01-07 04:31:39 +00:00
|
|
|
j = nlen;
|
|
|
|
memset(v, 0, sizeof(v));
|
2012-08-24 07:32:50 +10:00
|
|
|
while (j != 0U) {
|
2011-01-07 04:31:39 +00:00
|
|
|
INSIST((i / 2) < sizeof(v));
|
2012-04-11 12:17:57 +10:00
|
|
|
if (ndata[0] != 1) {
|
2011-01-07 04:31:39 +00:00
|
|
|
return ISC_R_NOTFOUND;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2012-04-11 12:17:57 +10:00
|
|
|
n = hex16[ndata[1] & 0xff];
|
|
|
|
if (n == 1) {
|
2011-01-07 04:31:39 +00:00
|
|
|
return ISC_R_NOTFOUND;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2012-04-11 12:17:57 +10:00
|
|
|
v[i / 2] = n | (v[i / 2] >> 4);
|
|
|
|
j -= 2;
|
|
|
|
ndata += 2;
|
2011-01-07 04:31:39 +00:00
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2011-01-07 23:47:07 +00:00
|
|
|
* If we get here then we know name only consisted of nibbles.
|
2011-01-07 04:31:39 +00:00
|
|
|
* Now we need to determine if the name exists or not and whether
|
|
|
|
* it corresponds to a empty node in the zone or there should be
|
|
|
|
* a CNAME.
|
|
|
|
*/
|
2012-04-11 12:17:57 +10:00
|
|
|
#define ZLEN(x) (10 + (x) / 2)
|
2011-01-07 04:31:39 +00:00
|
|
|
switch (zlen) {
|
2012-04-11 12:17:57 +10:00
|
|
|
case ZLEN(32): /* prefix len 32 */
|
2011-01-07 04:31:39 +00:00
|
|
|
/*
|
2012-04-11 12:17:57 +10:00
|
|
|
* The nibbles that map to this byte must be zero for 'name'
|
|
|
|
* to exist in the zone.
|
|
|
|
*/
|
|
|
|
if (nlen > 16U && v[(nlen - 1) / 4 - 4] != 0) {
|
|
|
|
return ISC_R_NOTFOUND;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2012-04-11 12:17:57 +10:00
|
|
|
/*
|
|
|
|
* If the total length is not 74 then this is a empty node
|
2011-01-07 04:31:39 +00:00
|
|
|
* so return success.
|
|
|
|
*/
|
2012-04-11 12:17:57 +10:00
|
|
|
if (nlen + zlen != 74U) {
|
2011-01-07 04:31:39 +00:00
|
|
|
return ISC_R_SUCCESS;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2012-04-11 12:17:57 +10:00
|
|
|
len = dns64_rdata(v, 8, rdata);
|
2011-01-07 04:31:39 +00:00
|
|
|
break;
|
2012-04-11 12:17:57 +10:00
|
|
|
case ZLEN(40): /* prefix len 40 */
|
2011-01-07 04:31:39 +00:00
|
|
|
/*
|
|
|
|
* The nibbles that map to this byte must be zero for 'name'
|
|
|
|
* to exist in the zone.
|
|
|
|
*/
|
2012-04-11 12:17:57 +10:00
|
|
|
if (nlen > 12U && v[(nlen - 1) / 4 - 3] != 0) {
|
2011-01-07 04:31:39 +00:00
|
|
|
return ISC_R_NOTFOUND;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2011-01-07 04:31:39 +00:00
|
|
|
/*
|
2012-04-11 12:17:57 +10:00
|
|
|
* If the total length is not 74 then this is a empty node
|
2011-01-07 04:31:39 +00:00
|
|
|
* so return success.
|
|
|
|
*/
|
2012-04-11 12:17:57 +10:00
|
|
|
if (nlen + zlen != 74U) {
|
2011-01-07 04:31:39 +00:00
|
|
|
return ISC_R_SUCCESS;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2012-04-11 12:17:57 +10:00
|
|
|
len = dns64_rdata(v, 6, rdata);
|
2011-01-07 04:31:39 +00:00
|
|
|
break;
|
2012-04-11 12:17:57 +10:00
|
|
|
case ZLEN(48): /* prefix len 48 */
|
2011-01-07 04:31:39 +00:00
|
|
|
/*
|
|
|
|
* The nibbles that map to this byte must be zero for 'name'
|
|
|
|
* to exist in the zone.
|
|
|
|
*/
|
2012-04-11 12:17:57 +10:00
|
|
|
if (nlen > 8U && v[(nlen - 1) / 4 - 2] != 0) {
|
2011-01-07 04:31:39 +00:00
|
|
|
return ISC_R_NOTFOUND;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2011-01-07 04:31:39 +00:00
|
|
|
/*
|
2012-04-11 12:17:57 +10:00
|
|
|
* If the total length is not 74 then this is a empty node
|
2011-01-07 04:31:39 +00:00
|
|
|
* so return success.
|
|
|
|
*/
|
2012-04-11 12:17:57 +10:00
|
|
|
if (nlen + zlen != 74U) {
|
2011-01-07 04:31:39 +00:00
|
|
|
return ISC_R_SUCCESS;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2012-04-11 12:17:57 +10:00
|
|
|
len = dns64_rdata(v, 5, rdata);
|
2011-01-07 04:31:39 +00:00
|
|
|
break;
|
2012-04-11 12:17:57 +10:00
|
|
|
case ZLEN(56): /* prefix len 56 */
|
2011-01-07 04:31:39 +00:00
|
|
|
/*
|
|
|
|
* The nibbles that map to this byte must be zero for 'name'
|
|
|
|
* to exist in the zone.
|
|
|
|
*/
|
2012-04-11 12:17:57 +10:00
|
|
|
if (nlen > 4U && v[(nlen - 1) / 4 - 1] != 0) {
|
2011-01-07 04:31:39 +00:00
|
|
|
return ISC_R_NOTFOUND;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2011-01-07 04:31:39 +00:00
|
|
|
/*
|
2012-04-11 12:17:57 +10:00
|
|
|
* If the total length is not 74 then this is a empty node
|
2011-01-07 04:31:39 +00:00
|
|
|
* so return success.
|
|
|
|
*/
|
2012-04-11 12:17:57 +10:00
|
|
|
if (nlen + zlen != 74U) {
|
2011-01-07 04:31:39 +00:00
|
|
|
return ISC_R_SUCCESS;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2012-04-11 12:17:57 +10:00
|
|
|
len = dns64_rdata(v, 4, rdata);
|
2011-01-07 04:31:39 +00:00
|
|
|
break;
|
2012-04-11 12:17:57 +10:00
|
|
|
case ZLEN(64): /* prefix len 64 */
|
2011-01-07 04:31:39 +00:00
|
|
|
/*
|
|
|
|
* The nibbles that map to this byte must be zero for 'name'
|
|
|
|
* to exist in the zone.
|
|
|
|
*/
|
2012-04-11 12:17:57 +10:00
|
|
|
if (v[(nlen - 1) / 4] != 0) {
|
2011-01-07 04:31:39 +00:00
|
|
|
return ISC_R_NOTFOUND;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2011-01-07 04:31:39 +00:00
|
|
|
/*
|
2012-04-11 12:17:57 +10:00
|
|
|
* If the total length is not 74 then this is a empty node
|
2011-01-07 04:31:39 +00:00
|
|
|
* so return success.
|
|
|
|
*/
|
2012-04-11 12:17:57 +10:00
|
|
|
if (nlen + zlen != 74U) {
|
2011-01-07 04:31:39 +00:00
|
|
|
return ISC_R_SUCCESS;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2012-04-11 12:17:57 +10:00
|
|
|
len = dns64_rdata(v, 3, rdata);
|
2011-01-07 04:31:39 +00:00
|
|
|
break;
|
2012-04-11 12:17:57 +10:00
|
|
|
case ZLEN(96): /* prefix len 96 */
|
2011-01-07 04:31:39 +00:00
|
|
|
/*
|
2012-04-11 12:17:57 +10:00
|
|
|
* If the total length is not 74 then this is a empty node
|
2011-01-07 04:31:39 +00:00
|
|
|
* so return success.
|
|
|
|
*/
|
2012-04-11 12:17:57 +10:00
|
|
|
if (nlen + zlen != 74U) {
|
2011-01-07 04:31:39 +00:00
|
|
|
return ISC_R_SUCCESS;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2012-04-11 12:17:57 +10:00
|
|
|
len = dns64_rdata(v, 0, rdata);
|
2011-01-07 04:31:39 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/*
|
|
|
|
* This should never be reached unless someone adds a
|
|
|
|
* zone declaration with this internal type to named.conf.
|
|
|
|
*/
|
|
|
|
return ISC_R_NOTFOUND;
|
|
|
|
}
|
2020-09-01 12:03:59 +10:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Reverse of 192.0.0.170 or 192.0.0.171 maps to ipv4only.arpa.
|
|
|
|
*/
|
|
|
|
if ((v[0] == 170 || v[0] == 171) && v[1] == 0 && v[2] == 0 &&
|
2022-11-02 19:33:14 +01:00
|
|
|
v[3] == 192)
|
|
|
|
{
|
2023-02-09 23:21:57 -08:00
|
|
|
return putrdata(node, dns_rdatatype_ptr, 3600, ipv4only,
|
|
|
|
sizeof(ipv4only));
|
2020-09-01 12:03:59 +10:00
|
|
|
}
|
|
|
|
|
2023-02-09 23:21:57 -08:00
|
|
|
return putrdata(node, dns_rdatatype_cname, 600, rdata,
|
|
|
|
(unsigned int)len);
|
2011-01-07 04:31:39 +00:00
|
|
|
}
|
|
|
|
|
2001-11-20 01:18:15 +00:00
|
|
|
static isc_result_t
|
2023-02-09 23:21:57 -08:00
|
|
|
builtin_lookup(bdb_t *bdb, const dns_name_t *name, bdbnode_t *node) {
|
2025-02-21 12:09:28 +01:00
|
|
|
if (name->length == 0) {
|
2023-02-09 23:21:57 -08:00
|
|
|
return bdb->lookup(node);
|
|
|
|
} else if ((node->bdb->implementation->flags & BDB_DNS64) != 0) {
|
|
|
|
return dns64_cname(&bdb->common.origin, name, node);
|
2001-11-20 01:18:15 +00:00
|
|
|
} else {
|
|
|
|
return ISC_R_NOTFOUND;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2001-11-20 01:18:15 +00:00
|
|
|
}
|
|
|
|
|
2012-04-11 12:17:57 +10:00
|
|
|
static isc_result_t
|
2023-02-09 23:21:57 -08:00
|
|
|
builtin_authority(bdb_t *bdb, bdbnode_t *node) {
|
|
|
|
isc_result_t result;
|
|
|
|
const char *contact = "hostmaster";
|
|
|
|
const char *server = "@";
|
2012-04-11 12:17:57 +10:00
|
|
|
|
2023-02-09 23:21:57 -08:00
|
|
|
if (bdb->server != NULL) {
|
|
|
|
server = bdb->server;
|
|
|
|
}
|
|
|
|
if (bdb->contact != NULL) {
|
|
|
|
contact = bdb->contact;
|
|
|
|
}
|
2012-04-11 12:17:57 +10:00
|
|
|
|
2023-02-09 23:21:57 -08:00
|
|
|
result = putsoa(node, server, contact, 0);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
return ISC_R_FAILURE;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2012-04-11 12:17:57 +10:00
|
|
|
|
2023-02-09 23:21:57 -08:00
|
|
|
result = putrr(node, "NS", 0, server);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
return ISC_R_FAILURE;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2023-02-09 23:21:57 -08:00
|
|
|
|
|
|
|
return ISC_R_SUCCESS;
|
2001-11-20 01:18:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
2023-02-09 23:21:57 -08:00
|
|
|
version_lookup(bdbnode_t *node) {
|
2017-09-08 13:39:09 -07:00
|
|
|
if (named_g_server->version_set) {
|
|
|
|
if (named_g_server->version == NULL) {
|
2001-11-20 01:18:15 +00:00
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
} else {
|
2023-02-09 23:21:57 -08:00
|
|
|
return puttxt(node, named_g_server->version);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2001-11-20 01:18:15 +00:00
|
|
|
} else {
|
2023-02-09 23:21:57 -08:00
|
|
|
return puttxt(node, PACKAGE_VERSION);
|
2001-11-20 01:18:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
2023-02-09 23:21:57 -08:00
|
|
|
hostname_lookup(bdbnode_t *node) {
|
2017-09-08 13:39:09 -07:00
|
|
|
if (named_g_server->hostname_set) {
|
|
|
|
if (named_g_server->hostname == NULL) {
|
2001-11-20 01:18:15 +00:00
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
} else {
|
2023-02-09 23:21:57 -08:00
|
|
|
return puttxt(node, named_g_server->hostname);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2001-11-20 01:18:15 +00:00
|
|
|
} else {
|
2002-01-25 03:12:07 +00:00
|
|
|
char buf[256];
|
2023-02-09 12:48:07 -08:00
|
|
|
if (gethostname(buf, sizeof(buf)) != 0) {
|
|
|
|
return ISC_R_FAILURE;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2023-02-09 23:21:57 -08:00
|
|
|
return puttxt(node, buf);
|
2001-11-20 01:18:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
2023-02-09 23:21:57 -08:00
|
|
|
authors_lookup(bdbnode_t *node) {
|
2001-11-20 01:18:15 +00:00
|
|
|
isc_result_t result;
|
2023-02-09 23:21:57 -08:00
|
|
|
const char **p = NULL;
|
2001-11-20 01:18:15 +00:00
|
|
|
static const char *authors[] = {
|
2024-05-10 23:37:52 +03:00
|
|
|
"Mark Andrews", "Curtis Blackburn",
|
|
|
|
"James Brister", "Ben Cottrell",
|
|
|
|
"John H. DuBois III", "Francis Dupont",
|
|
|
|
"Michael Graff", "Andreas Gustafsson",
|
|
|
|
"Bob Halley", "Evan Hunt",
|
|
|
|
"JINMEI Tatuya", "Witold Krecicki",
|
|
|
|
"David Lawrence", "Scott Mann",
|
|
|
|
"Danny Mayer", "Aydin Mercan",
|
|
|
|
"Damien Neil", "Matt Nelson",
|
|
|
|
"Jeremy C. Reed", "Michael Sawyer",
|
|
|
|
"Brian Wellington", NULL
|
2001-11-20 01:18:15 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If a version string is specified, disable the authors.bind zone.
|
|
|
|
*/
|
2017-09-08 13:39:09 -07:00
|
|
|
if (named_g_server->version_set) {
|
2001-11-20 01:18:15 +00:00
|
|
|
return ISC_R_SUCCESS;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2001-11-20 01:18:15 +00:00
|
|
|
|
|
|
|
for (p = authors; *p != NULL; p++) {
|
2023-02-09 23:21:57 -08:00
|
|
|
result = puttxt(node, *p);
|
2001-11-20 01:18:15 +00:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2023-02-09 23:21:57 -08:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ISC_R_SUCCESS;
|
2023-02-08 22:22:40 -08:00
|
|
|
}
|
|
|
|
|
2023-02-09 23:21:57 -08:00
|
|
|
static isc_result_t
|
|
|
|
id_lookup(bdbnode_t *node) {
|
|
|
|
if (named_g_server->sctx->usehostname) {
|
|
|
|
char buf[256];
|
|
|
|
if (gethostname(buf, sizeof(buf)) != 0) {
|
|
|
|
return ISC_R_FAILURE;
|
2023-02-08 22:22:40 -08:00
|
|
|
}
|
2023-02-09 23:21:57 -08:00
|
|
|
return puttxt(node, buf);
|
|
|
|
} else if (named_g_server->sctx->server_id != NULL) {
|
|
|
|
return puttxt(node, named_g_server->sctx->server_id);
|
|
|
|
} else {
|
|
|
|
return ISC_R_SUCCESS;
|
2023-02-08 22:22:40 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-09 23:21:57 -08:00
|
|
|
static isc_result_t
|
|
|
|
empty_lookup(bdbnode_t *node) {
|
|
|
|
UNUSED(node);
|
2023-02-08 22:22:40 -08:00
|
|
|
|
2023-02-09 23:21:57 -08:00
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
}
|
2023-02-08 22:22:40 -08:00
|
|
|
|
2023-02-09 23:21:57 -08:00
|
|
|
static isc_result_t
|
|
|
|
ipv4only_lookup(bdbnode_t *node) {
|
|
|
|
isc_result_t result;
|
|
|
|
unsigned char data[2][4] = { { 192, 0, 0, 170 }, { 192, 0, 0, 171 } };
|
|
|
|
|
|
|
|
for (int i = 0; i < 2; i++) {
|
|
|
|
result = putrdata(node, dns_rdatatype_a, 3600, data[i], 4);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
return result;
|
2023-02-08 22:22:40 -08:00
|
|
|
}
|
|
|
|
}
|
2023-02-09 23:21:57 -08:00
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
}
|
2023-02-08 22:22:40 -08:00
|
|
|
|
2023-02-09 23:21:57 -08:00
|
|
|
static isc_result_t
|
|
|
|
ipv4reverse_lookup(bdbnode_t *node) {
|
|
|
|
isc_result_t result;
|
2023-02-08 22:22:40 -08:00
|
|
|
|
2023-02-09 23:21:57 -08:00
|
|
|
result = putrdata(node, dns_rdatatype_ptr, 3600, ipv4only,
|
|
|
|
sizeof(ipv4only));
|
|
|
|
return result;
|
|
|
|
}
|
2023-02-08 22:22:40 -08:00
|
|
|
|
2023-02-09 23:21:57 -08:00
|
|
|
/*
|
|
|
|
* Rdataset implementation methods. An rdataset in the builtin databases is
|
|
|
|
* implemented as an rdatalist which holds a reference to the dbnode,
|
|
|
|
* to prevent the node being freed while the rdataset is still in use, so
|
|
|
|
* we need local implementations of clone and disassociate but the rest of
|
|
|
|
* the implementation can be the same as dns_rdatalist..
|
|
|
|
*/
|
|
|
|
static void
|
2023-01-05 09:12:35 +01:00
|
|
|
disassociate(dns_rdataset_t *rdataset DNS__DB_FLARG) {
|
Give the rdataset->privateN fields more helpful names
BIND's rdataset structure is a view of some DNS records. It is
polymorphic, so the details of how the records are stored can vary.
For instance, the records can be held in an rdatalist, or in an
rdataslab in the rbtdb.
The dns_rdataset structure previously had a number of fields called
`private1` up to `private7`, which were used by the various rdataset
implementations. It was not at all clear what these fields were for,
without reading the code and working it out from context.
This change makes the rdataset inheritance hierarchy more clear. The
polymorphic part of a `struct dns_rdataset` is now a union of structs,
each of which is named for the class of implementation using it. The
fields of these structs replace the old `privateN` fields. (Note: the
term "inheritance hierarchy" refers to the fact that the builtin and
SDLZ implementations are based on and inherit from the rdatalist
implementation, which in turn inherits from the generic rdataset.
Most of this change is mechanical, but there are a few extras.
In keynode.c there were a number of REQUIRE()ments that were not
necessary: they had already been checked by the rdataset method
dispatch code. On the other hand, In ncache.c there was a public
function which needed to REQUIRE() that an rdataset was valid.
I have removed lots of "reset iterator state" comments, because it
should now be clear from `target->iter = NULL` where before
`target->private5 = NULL` could have been doing anything.
Initialization is a bit neater in a few places, using C structure
literals where appropriate.
The pointer arithmetic for translating between an rdataslab header and
its raw contents is now fractionally safer.
2023-04-28 01:12:39 +01:00
|
|
|
dns_dbnode_t *node = rdataset->rdlist.node;
|
2023-02-08 22:22:40 -08:00
|
|
|
|
Decouple database and node lifetimes by adding node-specific vtables
All databases in the codebase follow the same structure: a database is
an associative container from DNS names to nodes, and each node is an
associative container from RR types to RR data.
Each database implementation (qpzone, qpcache, sdlz, builtin, dyndb) has
its own corresponding node type (qpznode, qpcnode, etc). However, some
code needs to work with nodes generically regardless of their specific
type - for example, to acquire locks, manage references, or
register/unregister slabs from the heap.
Currently, these generic node operations are implemented as methods in
the database vtable, which creates problematic coupling between database
and node lifetimes. If a node outlives its parent database, the node
destructor will destroy all RR data, and each RR data destructor will
try to unregister from heaps by calling a virtual function from the
database vtable. Since the database was already freed, this causes a
crash.
This commit breaks the coupling by standardizing the layout of all
database nodes, adding a dedicated vtable for node operations, and
moving node-specific methods from the database vtable to the node
vtable.
2025-06-05 11:51:29 +02:00
|
|
|
bdbnode_detachnode(&node DNS__DB_FLARG_PASS);
|
2023-01-05 09:12:35 +01:00
|
|
|
dns_rdatalist_disassociate(rdataset DNS__DB_FLARG_PASS);
|
2023-02-08 22:22:40 -08:00
|
|
|
}
|
|
|
|
|
2023-02-09 23:21:57 -08:00
|
|
|
static void
|
2023-01-05 09:12:35 +01:00
|
|
|
rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target DNS__DB_FLARG) {
|
Give the rdataset->privateN fields more helpful names
BIND's rdataset structure is a view of some DNS records. It is
polymorphic, so the details of how the records are stored can vary.
For instance, the records can be held in an rdatalist, or in an
rdataslab in the rbtdb.
The dns_rdataset structure previously had a number of fields called
`private1` up to `private7`, which were used by the various rdataset
implementations. It was not at all clear what these fields were for,
without reading the code and working it out from context.
This change makes the rdataset inheritance hierarchy more clear. The
polymorphic part of a `struct dns_rdataset` is now a union of structs,
each of which is named for the class of implementation using it. The
fields of these structs replace the old `privateN` fields. (Note: the
term "inheritance hierarchy" refers to the fact that the builtin and
SDLZ implementations are based on and inherit from the rdatalist
implementation, which in turn inherits from the generic rdataset.
Most of this change is mechanical, but there are a few extras.
In keynode.c there were a number of REQUIRE()ments that were not
necessary: they had already been checked by the rdataset method
dispatch code. On the other hand, In ncache.c there was a public
function which needed to REQUIRE() that an rdataset was valid.
I have removed lots of "reset iterator state" comments, because it
should now be clear from `target->iter = NULL` where before
`target->private5 = NULL` could have been doing anything.
Initialization is a bit neater in a few places, using C structure
literals where appropriate.
The pointer arithmetic for translating between an rdataslab header and
its raw contents is now fractionally safer.
2023-04-28 01:12:39 +01:00
|
|
|
dns_dbnode_t *node = source->rdlist.node;
|
2023-02-08 22:22:40 -08:00
|
|
|
|
2023-01-05 09:12:35 +01:00
|
|
|
dns_rdatalist_clone(source, target DNS__DB_FLARG_PASS);
|
Decouple database and node lifetimes by adding node-specific vtables
All databases in the codebase follow the same structure: a database is
an associative container from DNS names to nodes, and each node is an
associative container from RR types to RR data.
Each database implementation (qpzone, qpcache, sdlz, builtin, dyndb) has
its own corresponding node type (qpznode, qpcnode, etc). However, some
code needs to work with nodes generically regardless of their specific
type - for example, to acquire locks, manage references, or
register/unregister slabs from the heap.
Currently, these generic node operations are implemented as methods in
the database vtable, which creates problematic coupling between database
and node lifetimes. If a node outlives its parent database, the node
destructor will destroy all RR data, and each RR data destructor will
try to unregister from heaps by calling a virtual function from the
database vtable. Since the database was already freed, this causes a
crash.
This commit breaks the coupling by standardizing the layout of all
database nodes, adding a dedicated vtable for node operations, and
moving node-specific methods from the database vtable to the node
vtable.
2025-06-05 11:51:29 +02:00
|
|
|
bdbnode_attachnode(node, &target->rdlist.node DNS__DB_FLARG_PASS);
|
2023-02-09 23:21:57 -08:00
|
|
|
}
|
2023-02-08 22:22:40 -08:00
|
|
|
|
2023-02-09 23:21:57 -08:00
|
|
|
static dns_rdatasetmethods_t bdb_rdataset_methods = {
|
|
|
|
.disassociate = disassociate,
|
|
|
|
.first = dns_rdatalist_first,
|
|
|
|
.next = dns_rdatalist_next,
|
|
|
|
.current = dns_rdatalist_current,
|
|
|
|
.clone = rdataset_clone,
|
|
|
|
.count = dns_rdatalist_count,
|
|
|
|
.addnoqname = dns_rdatalist_addnoqname,
|
|
|
|
.getnoqname = dns_rdatalist_getnoqname,
|
|
|
|
};
|
2023-02-08 22:22:40 -08:00
|
|
|
|
2023-02-09 23:21:57 -08:00
|
|
|
static void
|
Decouple database and node lifetimes by adding node-specific vtables
All databases in the codebase follow the same structure: a database is
an associative container from DNS names to nodes, and each node is an
associative container from RR types to RR data.
Each database implementation (qpzone, qpcache, sdlz, builtin, dyndb) has
its own corresponding node type (qpznode, qpcnode, etc). However, some
code needs to work with nodes generically regardless of their specific
type - for example, to acquire locks, manage references, or
register/unregister slabs from the heap.
Currently, these generic node operations are implemented as methods in
the database vtable, which creates problematic coupling between database
and node lifetimes. If a node outlives its parent database, the node
destructor will destroy all RR data, and each RR data destructor will
try to unregister from heaps by calling a virtual function from the
database vtable. Since the database was already freed, this causes a
crash.
This commit breaks the coupling by standardizing the layout of all
database nodes, adding a dedicated vtable for node operations, and
moving node-specific methods from the database vtable to the node
vtable.
2025-06-05 11:51:29 +02:00
|
|
|
new_rdataset(dns_rdatalist_t *rdatalist, dns_db_t *db ISC_ATTR_UNUSED,
|
|
|
|
dns_dbnode_t *node, dns_rdataset_t *rdataset) {
|
2023-02-09 23:21:57 -08:00
|
|
|
dns_rdatalist_tordataset(rdatalist, rdataset);
|
2023-02-08 22:22:40 -08:00
|
|
|
|
2023-02-09 23:21:57 -08:00
|
|
|
rdataset->methods = &bdb_rdataset_methods;
|
Decouple database and node lifetimes by adding node-specific vtables
All databases in the codebase follow the same structure: a database is
an associative container from DNS names to nodes, and each node is an
associative container from RR types to RR data.
Each database implementation (qpzone, qpcache, sdlz, builtin, dyndb) has
its own corresponding node type (qpznode, qpcnode, etc). However, some
code needs to work with nodes generically regardless of their specific
type - for example, to acquire locks, manage references, or
register/unregister slabs from the heap.
Currently, these generic node operations are implemented as methods in
the database vtable, which creates problematic coupling between database
and node lifetimes. If a node outlives its parent database, the node
destructor will destroy all RR data, and each RR data destructor will
try to unregister from heaps by calling a virtual function from the
database vtable. Since the database was already freed, this causes a
crash.
This commit breaks the coupling by standardizing the layout of all
database nodes, adding a dedicated vtable for node operations, and
moving node-specific methods from the database vtable to the node
vtable.
2025-06-05 11:51:29 +02:00
|
|
|
dns_db_attachnode(node, &rdataset->rdlist.node);
|
2023-02-09 23:21:57 -08:00
|
|
|
}
|
2023-02-08 22:22:40 -08:00
|
|
|
|
2023-02-09 23:21:57 -08:00
|
|
|
/*
|
|
|
|
* Rdataset iterator methods
|
|
|
|
*/
|
2023-02-08 22:22:40 -08:00
|
|
|
|
2023-02-09 23:21:57 -08:00
|
|
|
static void
|
2023-01-05 09:12:35 +01:00
|
|
|
rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp DNS__DB_FLARG) {
|
2023-02-09 23:21:57 -08:00
|
|
|
bdb_rdatasetiter_t *bdbiterator = (bdb_rdatasetiter_t *)(*iteratorp);
|
Decouple database and node lifetimes by adding node-specific vtables
All databases in the codebase follow the same structure: a database is
an associative container from DNS names to nodes, and each node is an
associative container from RR types to RR data.
Each database implementation (qpzone, qpcache, sdlz, builtin, dyndb) has
its own corresponding node type (qpznode, qpcnode, etc). However, some
code needs to work with nodes generically regardless of their specific
type - for example, to acquire locks, manage references, or
register/unregister slabs from the heap.
Currently, these generic node operations are implemented as methods in
the database vtable, which creates problematic coupling between database
and node lifetimes. If a node outlives its parent database, the node
destructor will destroy all RR data, and each RR data destructor will
try to unregister from heaps by calling a virtual function from the
database vtable. Since the database was already freed, this causes a
crash.
This commit breaks the coupling by standardizing the layout of all
database nodes, adding a dedicated vtable for node operations, and
moving node-specific methods from the database vtable to the node
vtable.
2025-06-05 11:51:29 +02:00
|
|
|
bdbnode_detachnode(&bdbiterator->common.node DNS__DB_FLARG_PASS);
|
2023-02-09 23:21:57 -08:00
|
|
|
isc_mem_put(bdbiterator->common.db->mctx, bdbiterator,
|
|
|
|
sizeof(bdb_rdatasetiter_t));
|
|
|
|
*iteratorp = NULL;
|
|
|
|
}
|
2023-02-08 22:22:40 -08:00
|
|
|
|
2023-02-09 23:21:57 -08:00
|
|
|
static isc_result_t
|
2023-01-05 09:12:35 +01:00
|
|
|
rdatasetiter_first(dns_rdatasetiter_t *iterator DNS__DB_FLARG) {
|
2023-02-09 23:21:57 -08:00
|
|
|
bdb_rdatasetiter_t *bdbiterator = (bdb_rdatasetiter_t *)iterator;
|
|
|
|
bdbnode_t *bdbnode = (bdbnode_t *)iterator->node;
|
2023-02-08 22:22:40 -08:00
|
|
|
|
2023-02-09 23:21:57 -08:00
|
|
|
if (ISC_LIST_EMPTY(bdbnode->lists)) {
|
|
|
|
return ISC_R_NOMORE;
|
2023-02-08 22:22:40 -08:00
|
|
|
}
|
2023-02-09 23:21:57 -08:00
|
|
|
bdbiterator->current = ISC_LIST_HEAD(bdbnode->lists);
|
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
}
|
2023-02-08 22:22:40 -08:00
|
|
|
|
2023-02-09 23:21:57 -08:00
|
|
|
static isc_result_t
|
2023-01-05 09:12:35 +01:00
|
|
|
rdatasetiter_next(dns_rdatasetiter_t *iterator DNS__DB_FLARG) {
|
2023-02-09 23:21:57 -08:00
|
|
|
bdb_rdatasetiter_t *bdbiterator = (bdb_rdatasetiter_t *)iterator;
|
2023-02-08 22:22:40 -08:00
|
|
|
|
2023-02-09 23:21:57 -08:00
|
|
|
bdbiterator->current = ISC_LIST_NEXT(bdbiterator->current, link);
|
|
|
|
if (bdbiterator->current == NULL) {
|
|
|
|
return ISC_R_NOMORE;
|
|
|
|
} else {
|
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
}
|
2023-02-08 22:22:40 -08:00
|
|
|
}
|
|
|
|
|
2023-02-09 23:21:57 -08:00
|
|
|
static void
|
2023-01-05 09:12:35 +01:00
|
|
|
rdatasetiter_current(dns_rdatasetiter_t *iterator,
|
|
|
|
dns_rdataset_t *rdataset DNS__DB_FLARG) {
|
2023-02-09 23:21:57 -08:00
|
|
|
bdb_rdatasetiter_t *bdbiterator = (bdb_rdatasetiter_t *)iterator;
|
2023-02-08 22:22:40 -08:00
|
|
|
|
2023-02-09 23:21:57 -08:00
|
|
|
new_rdataset(bdbiterator->current, iterator->db, iterator->node,
|
|
|
|
rdataset);
|
2023-02-08 22:22:40 -08:00
|
|
|
}
|
|
|
|
|
2023-02-09 23:21:57 -08:00
|
|
|
static dns_rdatasetitermethods_t rdatasetiter_methods = {
|
|
|
|
rdatasetiter_destroy, rdatasetiter_first, rdatasetiter_next,
|
|
|
|
rdatasetiter_current
|
|
|
|
};
|
|
|
|
|
2023-02-08 22:22:40 -08:00
|
|
|
/*
|
2023-02-09 23:21:57 -08:00
|
|
|
* Database implementation methods
|
2023-02-08 22:22:40 -08:00
|
|
|
*/
|
|
|
|
static void
|
|
|
|
destroy(dns_db_t *db) {
|
2023-02-09 23:21:57 -08:00
|
|
|
bdb_t *bdb = (bdb_t *)db;
|
|
|
|
isc_refcount_destroy(&bdb->common.references);
|
2023-02-08 22:22:40 -08:00
|
|
|
|
2023-02-09 23:21:57 -08:00
|
|
|
if (bdb->server != NULL) {
|
2025-07-15 12:56:04 +02:00
|
|
|
isc_mem_free(isc_g_mctx, bdb->server);
|
2023-02-09 23:21:57 -08:00
|
|
|
}
|
|
|
|
if (bdb->contact != NULL) {
|
2025-07-15 12:56:04 +02:00
|
|
|
isc_mem_free(isc_g_mctx, bdb->contact);
|
2023-02-08 22:22:40 -08:00
|
|
|
}
|
|
|
|
|
2023-02-09 23:21:57 -08:00
|
|
|
bdb->common.magic = 0;
|
|
|
|
bdb->common.impmagic = 0;
|
2023-02-08 22:22:40 -08:00
|
|
|
|
2023-02-09 23:21:57 -08:00
|
|
|
dns_name_free(&bdb->common.origin, bdb->common.mctx);
|
2023-02-08 22:22:40 -08:00
|
|
|
|
2023-02-09 23:21:57 -08:00
|
|
|
isc_mem_putanddetach(&bdb->common.mctx, bdb, sizeof(bdb_t));
|
2023-02-08 22:22:40 -08:00
|
|
|
}
|
|
|
|
|
2023-02-09 23:21:57 -08:00
|
|
|
/*
|
|
|
|
* A dummy 'version' value is used so that dns_db_createversion()
|
|
|
|
* can return a non-NULL version to the caller, but there can only be
|
|
|
|
* one version of these databases, so the version value is never used.
|
|
|
|
*/
|
|
|
|
static int dummy;
|
|
|
|
|
2023-02-08 22:22:40 -08:00
|
|
|
static void
|
|
|
|
currentversion(dns_db_t *db, dns_dbversion_t **versionp) {
|
2023-02-09 23:21:57 -08:00
|
|
|
bdb_t *bdb = (bdb_t *)db;
|
2023-02-08 22:22:40 -08:00
|
|
|
|
2023-02-09 23:21:57 -08:00
|
|
|
REQUIRE(VALID_BDB(bdb));
|
2023-02-08 22:22:40 -08:00
|
|
|
|
|
|
|
*versionp = (void *)&dummy;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
attachversion(dns_db_t *db, dns_dbversion_t *source,
|
|
|
|
dns_dbversion_t **targetp) {
|
2023-02-09 23:21:57 -08:00
|
|
|
bdb_t *bdb = (bdb_t *)db;
|
|
|
|
|
|
|
|
REQUIRE(VALID_BDB(bdb));
|
2023-02-08 22:22:40 -08:00
|
|
|
REQUIRE(source != NULL && source == (void *)&dummy);
|
|
|
|
REQUIRE(targetp != NULL && *targetp == NULL);
|
|
|
|
|
|
|
|
*targetp = source;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-01-05 09:12:35 +01:00
|
|
|
closeversion(dns_db_t *db, dns_dbversion_t **versionp,
|
|
|
|
bool commit DNS__DB_FLARG) {
|
2023-02-09 23:21:57 -08:00
|
|
|
bdb_t *bdb = (bdb_t *)db;
|
|
|
|
|
|
|
|
REQUIRE(VALID_BDB(bdb));
|
2023-02-08 22:22:40 -08:00
|
|
|
REQUIRE(versionp != NULL && *versionp == (void *)&dummy);
|
|
|
|
REQUIRE(!commit);
|
|
|
|
|
|
|
|
*versionp = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
2023-02-09 23:21:57 -08:00
|
|
|
createnode(bdb_t *bdb, bdbnode_t **nodep) {
|
|
|
|
bdbnode_t *node = NULL;
|
|
|
|
|
|
|
|
REQUIRE(VALID_BDB(bdb));
|
2023-02-08 22:22:40 -08:00
|
|
|
|
2023-02-09 23:21:57 -08:00
|
|
|
node = isc_mem_get(bdb->common.mctx, sizeof(bdbnode_t));
|
|
|
|
*node = (bdbnode_t){
|
|
|
|
.lists = ISC_LIST_INITIALIZER,
|
|
|
|
.buffers = ISC_LIST_INITIALIZER,
|
|
|
|
.link = ISC_LINK_INITIALIZER,
|
|
|
|
};
|
2023-02-08 22:22:40 -08:00
|
|
|
|
2023-02-09 23:21:57 -08:00
|
|
|
dns_db_attach((dns_db_t *)bdb, (dns_db_t **)&node->bdb);
|
2023-02-08 22:22:40 -08:00
|
|
|
dns_rdatacallbacks_init(&node->callbacks);
|
|
|
|
|
|
|
|
isc_refcount_init(&node->references, 1);
|
2023-02-09 23:21:57 -08:00
|
|
|
node->magic = BDBNODE_MAGIC;
|
Decouple database and node lifetimes by adding node-specific vtables
All databases in the codebase follow the same structure: a database is
an associative container from DNS names to nodes, and each node is an
associative container from RR types to RR data.
Each database implementation (qpzone, qpcache, sdlz, builtin, dyndb) has
its own corresponding node type (qpznode, qpcnode, etc). However, some
code needs to work with nodes generically regardless of their specific
type - for example, to acquire locks, manage references, or
register/unregister slabs from the heap.
Currently, these generic node operations are implemented as methods in
the database vtable, which creates problematic coupling between database
and node lifetimes. If a node outlives its parent database, the node
destructor will destroy all RR data, and each RR data destructor will
try to unregister from heaps by calling a virtual function from the
database vtable. Since the database was already freed, this causes a
crash.
This commit breaks the coupling by standardizing the layout of all
database nodes, adding a dedicated vtable for node operations, and
moving node-specific methods from the database vtable to the node
vtable.
2025-06-05 11:51:29 +02:00
|
|
|
node->methods = &bdbnode_methods;
|
2023-02-08 22:22:40 -08:00
|
|
|
|
|
|
|
*nodep = node;
|
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-02-09 23:21:57 -08:00
|
|
|
destroynode(bdbnode_t *node) {
|
|
|
|
bdb_t *bdb = NULL;
|
2023-02-08 22:22:40 -08:00
|
|
|
isc_mem_t *mctx = NULL;
|
|
|
|
|
2023-02-09 23:21:57 -08:00
|
|
|
bdb = node->bdb;
|
|
|
|
mctx = bdb->common.mctx;
|
2023-02-08 22:22:40 -08:00
|
|
|
|
2025-05-23 13:02:22 -07:00
|
|
|
ISC_LIST_FOREACH(node->lists, list, link) {
|
|
|
|
ISC_LIST_FOREACH(list->rdata, rdata, link) {
|
2023-02-08 22:22:40 -08:00
|
|
|
ISC_LIST_UNLINK(list->rdata, rdata, link);
|
|
|
|
isc_mem_put(mctx, rdata, sizeof(dns_rdata_t));
|
|
|
|
}
|
|
|
|
ISC_LIST_UNLINK(node->lists, list, link);
|
|
|
|
isc_mem_put(mctx, list, sizeof(dns_rdatalist_t));
|
|
|
|
}
|
|
|
|
|
2025-05-23 13:02:22 -07:00
|
|
|
ISC_LIST_FOREACH(node->buffers, b, link) {
|
2023-02-08 22:22:40 -08:00
|
|
|
ISC_LIST_UNLINK(node->buffers, b, link);
|
|
|
|
isc_buffer_free(&b);
|
|
|
|
}
|
|
|
|
|
|
|
|
node->magic = 0;
|
2023-02-09 23:21:57 -08:00
|
|
|
isc_mem_put(mctx, node, sizeof(bdbnode_t));
|
|
|
|
dns_db_detach((dns_db_t **)(void *)&bdb);
|
2023-02-08 22:22:40 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
2023-01-05 09:12:35 +01:00
|
|
|
getoriginnode(dns_db_t *db, dns_dbnode_t **nodep DNS__DB_FLARG) {
|
2023-02-09 23:21:57 -08:00
|
|
|
bdb_t *bdb = (bdb_t *)db;
|
|
|
|
bdbnode_t *node = NULL;
|
2023-02-08 22:22:40 -08:00
|
|
|
isc_result_t result;
|
|
|
|
dns_name_t relname;
|
|
|
|
dns_name_t *name = NULL;
|
|
|
|
|
2023-02-09 23:21:57 -08:00
|
|
|
REQUIRE(VALID_BDB(bdb));
|
2023-02-08 22:22:40 -08:00
|
|
|
REQUIRE(nodep != NULL && *nodep == NULL);
|
|
|
|
|
2025-02-21 12:09:39 +01:00
|
|
|
dns_name_init(&relname);
|
2023-02-08 22:22:40 -08:00
|
|
|
name = &relname;
|
|
|
|
|
2023-02-09 23:21:57 -08:00
|
|
|
result = createnode(bdb, &node);
|
2023-02-08 22:22:40 -08:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2023-02-09 23:21:57 -08:00
|
|
|
result = builtin_lookup(bdb, name, node);
|
|
|
|
if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) {
|
2023-02-08 22:22:40 -08:00
|
|
|
destroynode(node);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2023-02-09 23:21:57 -08:00
|
|
|
result = builtin_authority(bdb, node);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
destroynode(node);
|
|
|
|
return result;
|
2023-02-08 22:22:40 -08:00
|
|
|
}
|
|
|
|
|
2024-11-05 16:13:10 +01:00
|
|
|
*nodep = (dns_dbnode_t *)node;
|
2023-02-08 22:22:40 -08:00
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
2023-02-09 23:21:57 -08:00
|
|
|
findnode(dns_db_t *db, const dns_name_t *name, bool create,
|
2023-01-05 09:12:35 +01:00
|
|
|
dns_dbnode_t **nodep DNS__DB_FLARG) {
|
2023-02-09 23:21:57 -08:00
|
|
|
bdb_t *bdb = (bdb_t *)db;
|
|
|
|
bdbnode_t *node = NULL;
|
2023-02-08 22:22:40 -08:00
|
|
|
isc_result_t result;
|
|
|
|
bool isorigin;
|
|
|
|
dns_name_t relname;
|
|
|
|
unsigned int labels;
|
|
|
|
|
2023-02-09 23:21:57 -08:00
|
|
|
REQUIRE(VALID_BDB(bdb));
|
2023-02-08 22:22:40 -08:00
|
|
|
REQUIRE(nodep != NULL && *nodep == NULL);
|
|
|
|
|
|
|
|
UNUSED(create);
|
|
|
|
|
2023-02-09 23:21:57 -08:00
|
|
|
isorigin = dns_name_equal(name, &bdb->common.origin);
|
2023-02-08 22:22:40 -08:00
|
|
|
|
|
|
|
labels = dns_name_countlabels(name) - dns_name_countlabels(&db->origin);
|
2025-02-21 12:09:39 +01:00
|
|
|
dns_name_init(&relname);
|
2023-02-08 22:22:40 -08:00
|
|
|
dns_name_getlabelsequence(name, 0, labels, &relname);
|
|
|
|
name = &relname;
|
|
|
|
|
2023-02-09 23:21:57 -08:00
|
|
|
result = createnode(bdb, &node);
|
2023-02-08 22:22:40 -08:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2023-02-09 23:21:57 -08:00
|
|
|
result = builtin_lookup(bdb, name, node);
|
|
|
|
if (result != ISC_R_SUCCESS && (!isorigin || result != ISC_R_NOTFOUND))
|
2023-02-08 22:22:40 -08:00
|
|
|
{
|
|
|
|
destroynode(node);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2023-02-09 23:21:57 -08:00
|
|
|
if (isorigin) {
|
|
|
|
result = builtin_authority(bdb, node);
|
2023-02-08 22:22:40 -08:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
destroynode(node);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-11-05 16:13:10 +01:00
|
|
|
*nodep = (dns_dbnode_t *)node;
|
2023-02-08 22:22:40 -08:00
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
2023-02-09 23:21:57 -08:00
|
|
|
find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version,
|
|
|
|
dns_rdatatype_t type, unsigned int options, isc_stdtime_t now,
|
|
|
|
dns_dbnode_t **nodep, dns_name_t *foundname, dns_rdataset_t *rdataset,
|
2023-01-05 09:12:35 +01:00
|
|
|
dns_rdataset_t *sigrdataset DNS__DB_FLARG) {
|
2023-02-09 23:21:57 -08:00
|
|
|
bdb_t *bdb = (bdb_t *)db;
|
|
|
|
isc_result_t result;
|
2023-02-08 22:22:40 -08:00
|
|
|
dns_dbnode_t *node = NULL;
|
|
|
|
dns_fixedname_t fname;
|
|
|
|
dns_rdataset_t xrdataset;
|
|
|
|
dns_name_t *xname = NULL;
|
2023-02-09 23:21:57 -08:00
|
|
|
unsigned int nlabels, olabels, i;
|
|
|
|
bool dns64;
|
2023-02-08 22:22:40 -08:00
|
|
|
|
2023-02-09 23:21:57 -08:00
|
|
|
REQUIRE(VALID_BDB(bdb));
|
2023-02-08 22:22:40 -08:00
|
|
|
REQUIRE(nodep == NULL || *nodep == NULL);
|
2024-11-05 18:50:15 +01:00
|
|
|
REQUIRE(version == NULL || version == (dns_dbversion_t *)&dummy);
|
2023-02-08 22:22:40 -08:00
|
|
|
|
|
|
|
if (!dns_name_issubdomain(name, &db->origin)) {
|
|
|
|
return DNS_R_NXDOMAIN;
|
|
|
|
}
|
|
|
|
|
|
|
|
olabels = dns_name_countlabels(&db->origin);
|
|
|
|
nlabels = dns_name_countlabels(name);
|
|
|
|
|
|
|
|
xname = dns_fixedname_initname(&fname);
|
|
|
|
|
|
|
|
if (rdataset == NULL) {
|
|
|
|
dns_rdataset_init(&xrdataset);
|
|
|
|
rdataset = &xrdataset;
|
|
|
|
}
|
|
|
|
|
|
|
|
result = DNS_R_NXDOMAIN;
|
2023-02-09 23:21:57 -08:00
|
|
|
dns64 = ((bdb->implementation->flags & BDB_DNS64) != 0);
|
|
|
|
for (i = (dns64 ? nlabels : olabels); i <= nlabels; i++) {
|
2023-02-08 22:22:40 -08:00
|
|
|
/*
|
|
|
|
* Look up the next label.
|
|
|
|
*/
|
|
|
|
dns_name_getlabelsequence(name, nlabels - i, i, xname);
|
2023-01-05 09:12:35 +01:00
|
|
|
result = findnode(db, xname, false, &node DNS__DB_FLARG_PASS);
|
2023-02-08 22:22:40 -08:00
|
|
|
if (result == ISC_R_NOTFOUND) {
|
|
|
|
/*
|
|
|
|
* No data at zone apex?
|
|
|
|
*/
|
|
|
|
if (i == olabels) {
|
|
|
|
return DNS_R_BADDB;
|
|
|
|
}
|
|
|
|
result = DNS_R_NXDOMAIN;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2023-02-09 23:21:57 -08:00
|
|
|
* DNS64 zones don't have DNAME or NS records.
|
2023-02-08 22:22:40 -08:00
|
|
|
*/
|
2023-02-09 23:21:57 -08:00
|
|
|
if (dns64) {
|
2023-02-08 22:22:40 -08:00
|
|
|
goto skip;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Look for a DNAME at the current label, unless this is
|
|
|
|
* the qname.
|
|
|
|
*/
|
|
|
|
if (i < nlabels) {
|
2023-01-05 09:12:35 +01:00
|
|
|
result = findrdataset(
|
|
|
|
db, node, version, dns_rdatatype_dname, 0, now,
|
|
|
|
rdataset, sigrdataset DNS__DB_FLARG_PASS);
|
2023-02-08 22:22:40 -08:00
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
result = DNS_R_DNAME;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Look for an NS at the current label, unless this is the
|
|
|
|
* origin or glue is ok.
|
|
|
|
*/
|
|
|
|
if (i != olabels && (options & DNS_DBFIND_GLUEOK) == 0) {
|
2023-01-05 09:12:35 +01:00
|
|
|
result = findrdataset(
|
|
|
|
db, node, version, dns_rdatatype_ns, 0, now,
|
|
|
|
rdataset, sigrdataset DNS__DB_FLARG_PASS);
|
2023-02-08 22:22:40 -08:00
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
if (i == nlabels && type == dns_rdatatype_any) {
|
|
|
|
result = DNS_R_ZONECUT;
|
|
|
|
dns_rdataset_disassociate(rdataset);
|
|
|
|
if (sigrdataset != NULL &&
|
|
|
|
dns_rdataset_isassociated(
|
|
|
|
sigrdataset))
|
|
|
|
{
|
|
|
|
dns_rdataset_disassociate(
|
|
|
|
sigrdataset);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
result = DNS_R_DELEGATION;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the current name is not the qname, add another label
|
|
|
|
* and try again.
|
|
|
|
*/
|
|
|
|
if (i < nlabels) {
|
2024-11-05 16:13:10 +01:00
|
|
|
destroynode((bdbnode_t *)node);
|
2023-02-08 22:22:40 -08:00
|
|
|
node = NULL;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
skip:
|
|
|
|
/*
|
|
|
|
* If we're looking for ANY, we're done.
|
|
|
|
*/
|
|
|
|
if (type == dns_rdatatype_any) {
|
|
|
|
result = ISC_R_SUCCESS;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Look for the qtype.
|
|
|
|
*/
|
|
|
|
result = findrdataset(db, node, version, type, 0, now, rdataset,
|
2023-01-05 09:12:35 +01:00
|
|
|
sigrdataset DNS__DB_FLARG_PASS);
|
2023-02-08 22:22:40 -08:00
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2023-02-09 23:21:57 -08:00
|
|
|
* Look for a CNAME.
|
2023-02-08 22:22:40 -08:00
|
|
|
*/
|
|
|
|
if (type != dns_rdatatype_cname) {
|
2023-01-05 09:12:35 +01:00
|
|
|
result = findrdataset(
|
|
|
|
db, node, version, dns_rdatatype_cname, 0, now,
|
|
|
|
rdataset, sigrdataset DNS__DB_FLARG_PASS);
|
2023-02-08 22:22:40 -08:00
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
result = DNS_R_CNAME;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
result = DNS_R_NXRRSET;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rdataset == &xrdataset && dns_rdataset_isassociated(rdataset)) {
|
|
|
|
dns_rdataset_disassociate(rdataset);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (foundname != NULL) {
|
|
|
|
dns_name_copy(xname, foundname);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nodep != NULL) {
|
|
|
|
*nodep = node;
|
|
|
|
} else if (node != NULL) {
|
Decouple database and node lifetimes by adding node-specific vtables
All databases in the codebase follow the same structure: a database is
an associative container from DNS names to nodes, and each node is an
associative container from RR types to RR data.
Each database implementation (qpzone, qpcache, sdlz, builtin, dyndb) has
its own corresponding node type (qpznode, qpcnode, etc). However, some
code needs to work with nodes generically regardless of their specific
type - for example, to acquire locks, manage references, or
register/unregister slabs from the heap.
Currently, these generic node operations are implemented as methods in
the database vtable, which creates problematic coupling between database
and node lifetimes. If a node outlives its parent database, the node
destructor will destroy all RR data, and each RR data destructor will
try to unregister from heaps by calling a virtual function from the
database vtable. Since the database was already freed, this causes a
crash.
This commit breaks the coupling by standardizing the layout of all
database nodes, adding a dedicated vtable for node operations, and
moving node-specific methods from the database vtable to the node
vtable.
2025-06-05 11:51:29 +02:00
|
|
|
bdbnode_detachnode(&node DNS__DB_FLARG_PASS);
|
2023-02-08 22:22:40 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
Decouple database and node lifetimes by adding node-specific vtables
All databases in the codebase follow the same structure: a database is
an associative container from DNS names to nodes, and each node is an
associative container from RR types to RR data.
Each database implementation (qpzone, qpcache, sdlz, builtin, dyndb) has
its own corresponding node type (qpznode, qpcnode, etc). However, some
code needs to work with nodes generically regardless of their specific
type - for example, to acquire locks, manage references, or
register/unregister slabs from the heap.
Currently, these generic node operations are implemented as methods in
the database vtable, which creates problematic coupling between database
and node lifetimes. If a node outlives its parent database, the node
destructor will destroy all RR data, and each RR data destructor will
try to unregister from heaps by calling a virtual function from the
database vtable. Since the database was already freed, this causes a
crash.
This commit breaks the coupling by standardizing the layout of all
database nodes, adding a dedicated vtable for node operations, and
moving node-specific methods from the database vtable to the node
vtable.
2025-06-05 11:51:29 +02:00
|
|
|
bdbnode_attachnode(dns_dbnode_t *source, dns_dbnode_t **targetp DNS__DB_FLARG) {
|
2023-02-09 23:21:57 -08:00
|
|
|
bdbnode_t *node = (bdbnode_t *)source;
|
2023-02-08 22:22:40 -08:00
|
|
|
|
|
|
|
isc_refcount_increment(&node->references);
|
|
|
|
|
|
|
|
*targetp = source;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
Decouple database and node lifetimes by adding node-specific vtables
All databases in the codebase follow the same structure: a database is
an associative container from DNS names to nodes, and each node is an
associative container from RR types to RR data.
Each database implementation (qpzone, qpcache, sdlz, builtin, dyndb) has
its own corresponding node type (qpznode, qpcnode, etc). However, some
code needs to work with nodes generically regardless of their specific
type - for example, to acquire locks, manage references, or
register/unregister slabs from the heap.
Currently, these generic node operations are implemented as methods in
the database vtable, which creates problematic coupling between database
and node lifetimes. If a node outlives its parent database, the node
destructor will destroy all RR data, and each RR data destructor will
try to unregister from heaps by calling a virtual function from the
database vtable. Since the database was already freed, this causes a
crash.
This commit breaks the coupling by standardizing the layout of all
database nodes, adding a dedicated vtable for node operations, and
moving node-specific methods from the database vtable to the node
vtable.
2025-06-05 11:51:29 +02:00
|
|
|
bdbnode_detachnode(dns_dbnode_t **nodep DNS__DB_FLARG) {
|
2023-02-09 23:21:57 -08:00
|
|
|
bdbnode_t *node = NULL;
|
2023-02-08 22:22:40 -08:00
|
|
|
|
2023-02-09 23:21:57 -08:00
|
|
|
REQUIRE(nodep != NULL && *nodep != NULL);
|
2023-02-08 22:22:40 -08:00
|
|
|
|
2023-02-09 23:21:57 -08:00
|
|
|
node = (bdbnode_t *)(*nodep);
|
|
|
|
*nodep = NULL;
|
2023-02-08 22:22:40 -08:00
|
|
|
|
|
|
|
if (isc_refcount_decrement(&node->references) == 1) {
|
|
|
|
destroynode(node);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
|
|
|
findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
|
|
|
|
dns_rdatatype_t type, dns_rdatatype_t covers, isc_stdtime_t now,
|
2023-01-05 09:12:35 +01:00
|
|
|
dns_rdataset_t *rdataset,
|
|
|
|
dns_rdataset_t *sigrdataset DNS__DB_FLARG) {
|
2023-02-09 23:21:57 -08:00
|
|
|
bdbnode_t *bdbnode = (bdbnode_t *)node;
|
2023-02-08 22:22:40 -08:00
|
|
|
|
2023-02-09 23:21:57 -08:00
|
|
|
REQUIRE(VALID_BDBNODE(bdbnode));
|
|
|
|
|
2023-02-08 22:22:40 -08:00
|
|
|
UNUSED(version);
|
|
|
|
UNUSED(covers);
|
|
|
|
UNUSED(now);
|
|
|
|
UNUSED(sigrdataset);
|
|
|
|
|
|
|
|
if (type == dns_rdatatype_rrsig) {
|
|
|
|
return ISC_R_NOTIMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
2025-03-22 15:26:16 -07:00
|
|
|
ISC_LIST_FOREACH(bdbnode->lists, list, link) {
|
2023-02-08 22:22:40 -08:00
|
|
|
if (list->type == type) {
|
2025-03-22 15:26:16 -07:00
|
|
|
new_rdataset(list, db, node, rdataset);
|
|
|
|
return ISC_R_SUCCESS;
|
2023-02-08 22:22:40 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-03-22 15:26:16 -07:00
|
|
|
return ISC_R_NOTFOUND;
|
2023-02-08 22:22:40 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
|
|
|
allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
|
|
|
|
unsigned int options, isc_stdtime_t now,
|
2023-01-05 09:12:35 +01:00
|
|
|
dns_rdatasetiter_t **iteratorp DNS__DB_FLARG) {
|
2023-02-09 23:21:57 -08:00
|
|
|
bdb_rdatasetiter_t *iterator = NULL;
|
2023-02-08 22:22:40 -08:00
|
|
|
|
2024-11-05 18:50:15 +01:00
|
|
|
REQUIRE(version == NULL || version == (dns_dbversion_t *)&dummy);
|
2023-02-08 22:22:40 -08:00
|
|
|
|
2023-02-09 23:21:57 -08:00
|
|
|
iterator = isc_mem_get(db->mctx, sizeof(bdb_rdatasetiter_t));
|
|
|
|
*iterator = (bdb_rdatasetiter_t){
|
|
|
|
.common.methods = &rdatasetiter_methods,
|
|
|
|
.common.db = db,
|
|
|
|
.common.version = version,
|
|
|
|
.common.options = options,
|
|
|
|
.common.now = now,
|
|
|
|
.common.magic = DNS_RDATASETITER_MAGIC,
|
|
|
|
};
|
2023-02-08 22:22:40 -08:00
|
|
|
|
Decouple database and node lifetimes by adding node-specific vtables
All databases in the codebase follow the same structure: a database is
an associative container from DNS names to nodes, and each node is an
associative container from RR types to RR data.
Each database implementation (qpzone, qpcache, sdlz, builtin, dyndb) has
its own corresponding node type (qpznode, qpcnode, etc). However, some
code needs to work with nodes generically regardless of their specific
type - for example, to acquire locks, manage references, or
register/unregister slabs from the heap.
Currently, these generic node operations are implemented as methods in
the database vtable, which creates problematic coupling between database
and node lifetimes. If a node outlives its parent database, the node
destructor will destroy all RR data, and each RR data destructor will
try to unregister from heaps by calling a virtual function from the
database vtable. Since the database was already freed, this causes a
crash.
This commit breaks the coupling by standardizing the layout of all
database nodes, adding a dedicated vtable for node operations, and
moving node-specific methods from the database vtable to the node
vtable.
2025-06-05 11:51:29 +02:00
|
|
|
bdbnode_attachnode(node, &iterator->common.node DNS__DB_FLARG_PASS);
|
2023-02-08 22:22:40 -08:00
|
|
|
|
|
|
|
*iteratorp = (dns_rdatasetiter_t *)iterator;
|
|
|
|
|
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2023-02-09 23:21:57 -08:00
|
|
|
static dns_dbmethods_t bdb_methods = {
|
2023-02-08 22:22:40 -08:00
|
|
|
.destroy = destroy,
|
|
|
|
.currentversion = currentversion,
|
|
|
|
.attachversion = attachversion,
|
|
|
|
.closeversion = closeversion,
|
|
|
|
.findrdataset = findrdataset,
|
|
|
|
.allrdatasets = allrdatasets,
|
|
|
|
.getoriginnode = getoriginnode,
|
2023-02-09 23:21:57 -08:00
|
|
|
.findnode = findnode,
|
|
|
|
.find = find,
|
2023-02-08 22:22:40 -08:00
|
|
|
};
|
|
|
|
|
|
|
|
static isc_result_t
|
|
|
|
create(isc_mem_t *mctx, const dns_name_t *origin, dns_dbtype_t type,
|
|
|
|
dns_rdataclass_t rdclass, unsigned int argc, char *argv[],
|
2023-02-09 23:21:57 -08:00
|
|
|
void *implementation, dns_db_t **dbp) {
|
2023-02-08 22:22:40 -08:00
|
|
|
isc_result_t result;
|
2023-02-09 23:21:57 -08:00
|
|
|
bool needargs = false;
|
|
|
|
bdb_t *bdb = NULL;
|
2023-02-08 22:22:40 -08:00
|
|
|
|
2023-02-09 23:21:57 -08:00
|
|
|
REQUIRE(implementation != NULL);
|
2023-02-08 22:22:40 -08:00
|
|
|
|
|
|
|
if (type != dns_dbtype_zone) {
|
|
|
|
return ISC_R_NOTIMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
2023-02-09 23:21:57 -08:00
|
|
|
bdb = isc_mem_get(mctx, sizeof(*bdb));
|
|
|
|
*bdb = (bdb_t){
|
|
|
|
.common = { .methods = &bdb_methods, .rdclass = rdclass },
|
|
|
|
.implementation = implementation,
|
2023-02-08 22:22:40 -08:00
|
|
|
};
|
|
|
|
|
2023-02-09 23:21:57 -08:00
|
|
|
isc_refcount_init(&bdb->common.references, 1);
|
|
|
|
isc_mem_attach(mctx, &bdb->common.mctx);
|
2025-02-21 12:09:39 +01:00
|
|
|
dns_name_init(&bdb->common.origin);
|
2025-02-21 12:09:28 +01:00
|
|
|
dns_name_dup(origin, mctx, &bdb->common.origin);
|
2023-02-08 22:22:40 -08:00
|
|
|
|
2023-02-09 23:21:57 -08:00
|
|
|
INSIST(argc >= 1);
|
|
|
|
if (strcmp(argv[0], "authors") == 0) {
|
|
|
|
bdb->lookup = authors_lookup;
|
|
|
|
} else if (strcmp(argv[0], "hostname") == 0) {
|
|
|
|
bdb->lookup = hostname_lookup;
|
|
|
|
} else if (strcmp(argv[0], "id") == 0) {
|
|
|
|
bdb->lookup = id_lookup;
|
|
|
|
} else if (strcmp(argv[0], "version") == 0) {
|
|
|
|
bdb->lookup = version_lookup;
|
|
|
|
} else if (strcmp(argv[0], "dns64") == 0) {
|
|
|
|
needargs = true;
|
|
|
|
bdb->lookup = empty_lookup;
|
|
|
|
} else if (strcmp(argv[0], "empty") == 0) {
|
|
|
|
needargs = true;
|
|
|
|
bdb->lookup = empty_lookup;
|
|
|
|
} else if (strcmp(argv[0], "ipv4only") == 0) {
|
|
|
|
needargs = true;
|
|
|
|
bdb->lookup = ipv4only_lookup;
|
|
|
|
} else {
|
|
|
|
needargs = true;
|
|
|
|
bdb->lookup = ipv4reverse_lookup;
|
2023-02-08 22:22:40 -08:00
|
|
|
}
|
|
|
|
|
2023-02-09 23:21:57 -08:00
|
|
|
if (needargs) {
|
|
|
|
if (argc != 3) {
|
|
|
|
result = DNS_R_SYNTAX;
|
|
|
|
goto cleanup;
|
2023-02-08 22:22:40 -08:00
|
|
|
}
|
|
|
|
|
2025-07-15 12:56:04 +02:00
|
|
|
bdb->server = isc_mem_strdup(isc_g_mctx, argv[1]);
|
|
|
|
bdb->contact = isc_mem_strdup(isc_g_mctx, argv[2]);
|
2023-02-09 23:21:57 -08:00
|
|
|
} else if (argc != 1) {
|
|
|
|
result = DNS_R_SYNTAX;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2023-02-08 22:22:40 -08:00
|
|
|
|
2023-02-09 23:21:57 -08:00
|
|
|
bdb->common.magic = DNS_DB_MAGIC;
|
|
|
|
bdb->common.impmagic = BDB_MAGIC;
|
2023-02-08 22:22:40 -08:00
|
|
|
|
2023-02-09 23:21:57 -08:00
|
|
|
*dbp = (dns_db_t *)bdb;
|
2023-02-08 22:22:40 -08:00
|
|
|
|
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
|
2023-02-09 23:21:57 -08:00
|
|
|
cleanup:
|
|
|
|
dns_name_free(&bdb->common.origin, mctx);
|
|
|
|
if (bdb->server != NULL) {
|
2025-07-15 12:56:04 +02:00
|
|
|
isc_mem_free(isc_g_mctx, bdb->server);
|
2023-02-09 23:21:57 -08:00
|
|
|
}
|
|
|
|
if (bdb->contact != NULL) {
|
2025-07-15 12:56:04 +02:00
|
|
|
isc_mem_free(isc_g_mctx, bdb->contact);
|
2023-02-09 23:21:57 -08:00
|
|
|
}
|
2023-02-08 22:22:40 -08:00
|
|
|
|
2023-02-09 23:21:57 -08:00
|
|
|
isc_mem_putanddetach(&bdb->common.mctx, bdb, sizeof(bdb_t));
|
2023-02-08 22:22:40 -08:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2023-02-09 23:21:57 -08:00
|
|
|
* Builtin database registration functions
|
2023-02-08 22:22:40 -08:00
|
|
|
*/
|
2023-02-09 23:21:57 -08:00
|
|
|
static bdbimplementation_t builtin = { .flags = 0 };
|
|
|
|
static bdbimplementation_t dns64 = { .flags = BDB_DNS64 };
|
2023-02-08 22:22:40 -08:00
|
|
|
|
2023-02-09 23:21:57 -08:00
|
|
|
isc_result_t
|
|
|
|
named_builtin_init(void) {
|
|
|
|
isc_result_t result;
|
2023-02-08 22:22:40 -08:00
|
|
|
|
2025-07-15 12:56:04 +02:00
|
|
|
result = dns_db_register("_builtin", create, &builtin, isc_g_mctx,
|
2023-02-09 23:21:57 -08:00
|
|
|
&builtin.dbimp);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
return result;
|
|
|
|
}
|
2023-02-08 22:22:40 -08:00
|
|
|
|
2025-07-15 12:56:04 +02:00
|
|
|
result = dns_db_register("_dns64", create, &dns64, isc_g_mctx,
|
2023-02-09 23:21:57 -08:00
|
|
|
&dns64.dbimp);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
dns_db_unregister(&builtin.dbimp);
|
|
|
|
return result;
|
2023-02-08 22:22:40 -08:00
|
|
|
}
|
2023-02-09 23:21:57 -08:00
|
|
|
|
2023-02-08 22:22:40 -08:00
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2023-02-09 23:21:57 -08:00
|
|
|
void
|
|
|
|
named_builtin_deinit(void) {
|
|
|
|
if (builtin.dbimp != NULL) {
|
|
|
|
dns_db_unregister(&builtin.dbimp);
|
|
|
|
}
|
|
|
|
if (dns64.dbimp != NULL) {
|
|
|
|
dns_db_unregister(&dns64.dbimp);
|
2023-02-08 22:22:40 -08:00
|
|
|
}
|
2001-11-20 01:18:15 +00:00
|
|
|
}
|