mirror of
https://github.com/isc-projects/bind9.git
synced 2026-04-29 18:09:11 -04:00
Instead of an RBT for the forwarders table, use a QP trie. We now use reference counting for dns_forwarders_t. When a forwarders object is retrieved by dns_fwdtable_find(), it must now be explicitly detached by the caller afterward. QP tries require stored objects to include their names, so the the forwarders object now has that. This obviates the need to pass back a separate 'foundname' value from dns_fwdtable_find().
281 lines
7.1 KiB
C
281 lines
7.1 KiB
C
/*
|
|
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
|
*
|
|
* SPDX-License-Identifier: MPL-2.0
|
|
*
|
|
* 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/.
|
|
*
|
|
* See the COPYRIGHT file distributed with this work for additional
|
|
* information regarding copyright ownership.
|
|
*/
|
|
|
|
/*! \file */
|
|
|
|
#include <isc/magic.h>
|
|
#include <isc/mem.h>
|
|
#include <isc/result.h>
|
|
#include <isc/util.h>
|
|
|
|
#include <dns/fixedname.h>
|
|
#include <dns/forward.h>
|
|
#include <dns/name.h>
|
|
#include <dns/qp.h>
|
|
#include <dns/types.h>
|
|
#include <dns/view.h>
|
|
|
|
struct dns_fwdtable {
|
|
/* Unlocked. */
|
|
unsigned int magic;
|
|
isc_mem_t *mctx;
|
|
dns_qpmulti_t *table;
|
|
};
|
|
|
|
#define FWDTABLEMAGIC ISC_MAGIC('F', 'w', 'd', 'T')
|
|
#define VALID_FWDTABLE(ft) ISC_MAGIC_VALID(ft, FWDTABLEMAGIC)
|
|
|
|
static void
|
|
qp_attach(void *uctx, void *pval, uint32_t ival);
|
|
static void
|
|
qp_detach(void *uctx, void *pval, uint32_t ival);
|
|
static size_t
|
|
qp_makekey(dns_qpkey_t key, void *uctx, void *pval, uint32_t ival);
|
|
static void
|
|
qp_triename(void *uctx, char *buf, size_t size);
|
|
|
|
static dns_qpmethods_t qpmethods = {
|
|
qp_attach,
|
|
qp_detach,
|
|
qp_makekey,
|
|
qp_triename,
|
|
};
|
|
|
|
void
|
|
dns_fwdtable_create(isc_mem_t *mctx, dns_view_t *view,
|
|
dns_fwdtable_t **fwdtablep) {
|
|
dns_fwdtable_t *fwdtable = NULL;
|
|
|
|
REQUIRE(fwdtablep != NULL && *fwdtablep == NULL);
|
|
|
|
fwdtable = isc_mem_get(mctx, sizeof(*fwdtable));
|
|
*fwdtable = (dns_fwdtable_t){ .magic = FWDTABLEMAGIC };
|
|
|
|
dns_qpmulti_create(mctx, &qpmethods, view, &fwdtable->table);
|
|
|
|
isc_mem_attach(mctx, &fwdtable->mctx);
|
|
*fwdtablep = fwdtable;
|
|
}
|
|
|
|
static dns_forwarders_t *
|
|
new_forwarders(isc_mem_t *mctx, const dns_name_t *name,
|
|
dns_fwdpolicy_t fwdpolicy) {
|
|
dns_forwarders_t *forwarders = NULL;
|
|
|
|
forwarders = isc_mem_get(mctx, sizeof(*forwarders));
|
|
*forwarders = (dns_forwarders_t){
|
|
.fwdpolicy = fwdpolicy,
|
|
.fwdrs = ISC_LIST_INITIALIZER,
|
|
};
|
|
isc_mem_attach(mctx, &forwarders->mctx);
|
|
isc_refcount_init(&forwarders->references, 1);
|
|
|
|
forwarders->name = dns_fixedname_initname(&forwarders->fn);
|
|
dns_name_copy(name, forwarders->name);
|
|
|
|
return (forwarders);
|
|
}
|
|
|
|
isc_result_t
|
|
dns_fwdtable_addfwd(dns_fwdtable_t *fwdtable, const dns_name_t *name,
|
|
dns_forwarderlist_t *fwdrs, dns_fwdpolicy_t fwdpolicy) {
|
|
isc_result_t result;
|
|
dns_forwarders_t *forwarders = NULL;
|
|
dns_forwarder_t *fwd = NULL, *nfwd = NULL;
|
|
dns_qp_t *qp = NULL;
|
|
|
|
REQUIRE(VALID_FWDTABLE(fwdtable));
|
|
|
|
forwarders = new_forwarders(fwdtable->mctx, name, fwdpolicy);
|
|
|
|
for (fwd = ISC_LIST_HEAD(*fwdrs); fwd != NULL;
|
|
fwd = ISC_LIST_NEXT(fwd, link))
|
|
{
|
|
nfwd = isc_mem_get(fwdtable->mctx, sizeof(*nfwd));
|
|
*nfwd = *fwd;
|
|
|
|
if (fwd->tlsname != NULL) {
|
|
nfwd->tlsname = isc_mem_get(fwdtable->mctx,
|
|
sizeof(*nfwd->tlsname));
|
|
dns_name_init(nfwd->tlsname, NULL);
|
|
dns_name_dup(fwd->tlsname, fwdtable->mctx,
|
|
nfwd->tlsname);
|
|
}
|
|
|
|
ISC_LINK_INIT(nfwd, link);
|
|
ISC_LIST_APPEND(forwarders->fwdrs, nfwd, link);
|
|
}
|
|
|
|
dns_qpmulti_write(fwdtable->table, &qp);
|
|
result = dns_qp_insert(qp, forwarders, 0);
|
|
dns_qp_compact(qp, DNS_QPGC_MAYBE);
|
|
dns_qpmulti_commit(fwdtable->table, &qp);
|
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
dns_forwarders_detach(&forwarders);
|
|
} else {
|
|
goto cleanup;
|
|
}
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
cleanup:
|
|
while (!ISC_LIST_EMPTY(forwarders->fwdrs)) {
|
|
fwd = ISC_LIST_HEAD(forwarders->fwdrs);
|
|
ISC_LIST_UNLINK(forwarders->fwdrs, fwd, link);
|
|
if (fwd->tlsname != NULL) {
|
|
dns_name_free(fwd->tlsname, fwdtable->mctx);
|
|
isc_mem_put(fwdtable->mctx, fwd->tlsname,
|
|
sizeof(*fwd->tlsname));
|
|
}
|
|
isc_mem_put(fwdtable->mctx, fwd, sizeof(*fwd));
|
|
}
|
|
isc_mem_put(fwdtable->mctx, forwarders, sizeof(*forwarders));
|
|
return (result);
|
|
}
|
|
|
|
isc_result_t
|
|
dns_fwdtable_add(dns_fwdtable_t *fwdtable, const dns_name_t *name,
|
|
isc_sockaddrlist_t *addrs, dns_fwdpolicy_t fwdpolicy) {
|
|
isc_result_t result;
|
|
dns_forwarders_t *forwarders = NULL;
|
|
dns_forwarder_t *fwd = NULL;
|
|
isc_sockaddr_t *sa = NULL;
|
|
dns_qp_t *qp = NULL;
|
|
|
|
REQUIRE(VALID_FWDTABLE(fwdtable));
|
|
|
|
forwarders = new_forwarders(fwdtable->mctx, name, fwdpolicy);
|
|
|
|
for (sa = ISC_LIST_HEAD(*addrs); sa != NULL;
|
|
sa = ISC_LIST_NEXT(sa, link))
|
|
{
|
|
fwd = isc_mem_get(fwdtable->mctx, sizeof(*fwd));
|
|
*fwd = (dns_forwarder_t){ .addr = *sa,
|
|
.link = ISC_LINK_INITIALIZER };
|
|
ISC_LIST_APPEND(forwarders->fwdrs, fwd, link);
|
|
}
|
|
|
|
dns_qpmulti_write(fwdtable->table, &qp);
|
|
result = dns_qp_insert(qp, forwarders, 0);
|
|
dns_qp_compact(qp, DNS_QPGC_MAYBE);
|
|
dns_qpmulti_commit(fwdtable->table, &qp);
|
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
dns_forwarders_detach(&forwarders);
|
|
} else {
|
|
goto cleanup;
|
|
}
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
cleanup:
|
|
while (!ISC_LIST_EMPTY(forwarders->fwdrs)) {
|
|
fwd = ISC_LIST_HEAD(forwarders->fwdrs);
|
|
ISC_LIST_UNLINK(forwarders->fwdrs, fwd, link);
|
|
isc_mem_put(fwdtable->mctx, fwd, sizeof(*fwd));
|
|
}
|
|
isc_mem_put(fwdtable->mctx, forwarders, sizeof(*forwarders));
|
|
return (result);
|
|
}
|
|
|
|
isc_result_t
|
|
dns_fwdtable_find(dns_fwdtable_t *fwdtable, const dns_name_t *name,
|
|
dns_forwarders_t **forwardersp) {
|
|
isc_result_t result;
|
|
dns_qpread_t qpr;
|
|
void *pval = NULL;
|
|
|
|
REQUIRE(VALID_FWDTABLE(fwdtable));
|
|
|
|
dns_qpmulti_query(fwdtable->table, &qpr);
|
|
result = dns_qp_findname_ancestor(&qpr, name, 0, &pval, NULL);
|
|
if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
|
|
dns_forwarders_t *fwdrs = pval;
|
|
*forwardersp = fwdrs;
|
|
dns_forwarders_ref(fwdrs);
|
|
}
|
|
dns_qpread_destroy(fwdtable->table, &qpr);
|
|
|
|
return (result);
|
|
}
|
|
|
|
void
|
|
dns_fwdtable_destroy(dns_fwdtable_t **fwdtablep) {
|
|
dns_fwdtable_t *fwdtable = NULL;
|
|
|
|
REQUIRE(fwdtablep != NULL && VALID_FWDTABLE(*fwdtablep));
|
|
|
|
fwdtable = *fwdtablep;
|
|
*fwdtablep = NULL;
|
|
|
|
dns_qpmulti_destroy(&fwdtable->table);
|
|
fwdtable->magic = 0;
|
|
|
|
isc_mem_putanddetach(&fwdtable->mctx, fwdtable, sizeof(*fwdtable));
|
|
}
|
|
|
|
/***
|
|
*** Private
|
|
***/
|
|
|
|
static void
|
|
destroy_forwarders(dns_forwarders_t *forwarders) {
|
|
dns_forwarder_t *fwd = NULL;
|
|
|
|
while (!ISC_LIST_EMPTY(forwarders->fwdrs)) {
|
|
fwd = ISC_LIST_HEAD(forwarders->fwdrs);
|
|
ISC_LIST_UNLINK(forwarders->fwdrs, fwd, link);
|
|
if (fwd->tlsname != NULL) {
|
|
dns_name_free(fwd->tlsname, forwarders->mctx);
|
|
isc_mem_put(forwarders->mctx, fwd->tlsname,
|
|
sizeof(*fwd->tlsname));
|
|
}
|
|
isc_mem_put(forwarders->mctx, fwd, sizeof(*fwd));
|
|
}
|
|
isc_mem_putanddetach(&forwarders->mctx, forwarders,
|
|
sizeof(*forwarders));
|
|
}
|
|
|
|
#if DNS_FORWARD_TRACE
|
|
ISC_REFCOUNT_TRACE_IMPL(dns_forwarders, destroy_forwarders);
|
|
#else
|
|
ISC_REFCOUNT_IMPL(dns_forwarders, destroy_forwarders);
|
|
#endif
|
|
|
|
static void
|
|
qp_attach(void *uctx ISC_ATTR_UNUSED, void *pval,
|
|
uint32_t ival ISC_ATTR_UNUSED) {
|
|
dns_forwarders_t *forwarders = pval;
|
|
dns_forwarders_ref(forwarders);
|
|
}
|
|
|
|
static void
|
|
qp_detach(void *uctx ISC_ATTR_UNUSED, void *pval,
|
|
uint32_t ival ISC_ATTR_UNUSED) {
|
|
dns_forwarders_t *forwarders = pval;
|
|
dns_forwarders_detach(&forwarders);
|
|
}
|
|
|
|
static size_t
|
|
qp_makekey(dns_qpkey_t key, void *uctx ISC_ATTR_UNUSED, void *pval,
|
|
uint32_t ival ISC_ATTR_UNUSED) {
|
|
dns_forwarders_t *fwd = pval;
|
|
return (dns_qpkey_fromname(key, fwd->name));
|
|
}
|
|
|
|
static void
|
|
qp_triename(void *uctx, char *buf, size_t size) {
|
|
dns_view_t *view = uctx;
|
|
snprintf(buf, size, "view %s forwarder table", view->name);
|
|
}
|