2009-09-01 00:22:28 +00:00
|
|
|
/*
|
2011-03-12 04:59:49 +00:00
|
|
|
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
2009-09-01 00:22:28 +00:00
|
|
|
*
|
2009-09-02 23:48:03 +00:00
|
|
|
* SPDX-License-Identifier: MPL-2.0
|
2021-06-03 08:37:05 +02:00
|
|
|
*
|
2009-09-02 23:48:03 +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
|
2009-09-01 00:22:28 +00:00
|
|
|
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
2018-02-23 09:53:12 +01:00
|
|
|
*
|
2009-09-02 23:48:03 +00:00
|
|
|
* See the COPYRIGHT file distributed with this work for additional
|
2016-12-13 15:47:03 +11:00
|
|
|
* information regarding copyright ownership.
|
2009-09-01 00:22:28 +00:00
|
|
|
*/
|
|
|
|
|
2018-04-17 08:29:14 -07:00
|
|
|
#include <stdbool.h>
|
2010-05-19 07:13:15 +00:00
|
|
|
#include <stddef.h>
|
|
|
|
|
2022-10-27 11:45:33 -07:00
|
|
|
#include <isc/async.h>
|
2014-02-16 13:03:17 -08:00
|
|
|
#include <isc/buffer.h>
|
2024-11-11 14:06:28 +01:00
|
|
|
#include <isc/counter.h>
|
2024-11-14 19:51:29 +01:00
|
|
|
#include <isc/loop.h>
|
2019-12-20 11:37:11 -08:00
|
|
|
#include <isc/md.h>
|
2009-09-01 00:22:28 +00:00
|
|
|
#include <isc/mem.h>
|
|
|
|
#include <isc/mutex.h>
|
2022-07-26 13:03:45 +02:00
|
|
|
#include <isc/netmgr.h>
|
2019-03-08 13:13:32 +01:00
|
|
|
#include <isc/portset.h>
|
2019-08-06 17:35:20 +02:00
|
|
|
#include <isc/refcount.h>
|
2021-10-04 17:14:53 +02:00
|
|
|
#include <isc/result.h>
|
2015-08-17 18:26:44 -07:00
|
|
|
#include <isc/safe.h>
|
2009-09-01 00:22:28 +00:00
|
|
|
#include <isc/sockaddr.h>
|
|
|
|
#include <isc/util.h>
|
|
|
|
|
|
|
|
#include <dns/adb.h>
|
|
|
|
#include <dns/client.h>
|
|
|
|
#include <dns/db.h>
|
|
|
|
#include <dns/dispatch.h>
|
|
|
|
#include <dns/forward.h>
|
|
|
|
#include <dns/keytable.h>
|
|
|
|
#include <dns/message.h>
|
|
|
|
#include <dns/name.h>
|
|
|
|
#include <dns/rdata.h>
|
|
|
|
#include <dns/rdatalist.h>
|
|
|
|
#include <dns/rdataset.h>
|
|
|
|
#include <dns/rdatasetiter.h>
|
|
|
|
#include <dns/rdatastruct.h>
|
|
|
|
#include <dns/rdatatype.h>
|
|
|
|
#include <dns/request.h>
|
|
|
|
#include <dns/resolver.h>
|
|
|
|
#include <dns/tsig.h>
|
|
|
|
#include <dns/view.h>
|
|
|
|
|
|
|
|
#include <dst/dst.h>
|
|
|
|
|
|
|
|
#define DNS_CLIENT_MAGIC ISC_MAGIC('D', 'N', 'S', 'c')
|
|
|
|
#define DNS_CLIENT_VALID(c) ISC_MAGIC_VALID(c, DNS_CLIENT_MAGIC)
|
|
|
|
|
|
|
|
#define RCTX_MAGIC ISC_MAGIC('R', 'c', 't', 'x')
|
|
|
|
#define RCTX_VALID(c) ISC_MAGIC_VALID(c, RCTX_MAGIC)
|
|
|
|
|
|
|
|
#define UCTX_MAGIC ISC_MAGIC('U', 'c', 't', 'x')
|
|
|
|
#define UCTX_VALID(c) ISC_MAGIC_VALID(c, UCTX_MAGIC)
|
|
|
|
|
2019-09-18 19:45:20 -07:00
|
|
|
#define CHECK(r) \
|
|
|
|
do { \
|
|
|
|
result = (r); \
|
|
|
|
if (result != ISC_R_SUCCESS) \
|
|
|
|
goto cleanup; \
|
|
|
|
} while (0)
|
|
|
|
|
2009-09-01 00:22:28 +00:00
|
|
|
/*%
|
|
|
|
* DNS client object
|
|
|
|
*/
|
|
|
|
struct dns_client {
|
|
|
|
unsigned int magic;
|
|
|
|
unsigned int attributes;
|
|
|
|
isc_mem_t *mctx;
|
2022-10-27 11:45:33 -07:00
|
|
|
isc_loop_t *loop;
|
2009-09-01 00:22:28 +00:00
|
|
|
dns_dispatchmgr_t *dispatchmgr;
|
|
|
|
dns_dispatch_t *dispatchv4;
|
|
|
|
dns_dispatch_t *dispatchv6;
|
2020-02-12 13:59:18 +01:00
|
|
|
|
2009-09-01 00:22:28 +00:00
|
|
|
unsigned int find_timeout;
|
|
|
|
unsigned int find_udpretries;
|
2024-06-25 14:30:20 -07:00
|
|
|
uint8_t max_restarts;
|
2024-11-11 14:06:28 +01:00
|
|
|
uint8_t max_queries;
|
2020-02-12 13:59:18 +01:00
|
|
|
|
2019-08-06 17:35:20 +02:00
|
|
|
isc_refcount_t references;
|
|
|
|
|
2022-07-26 13:03:45 +02:00
|
|
|
dns_view_t *view;
|
2009-09-01 00:22:28 +00:00
|
|
|
ISC_LIST(struct resctx) resctxs;
|
|
|
|
};
|
|
|
|
|
|
|
|
#define DEF_FIND_TIMEOUT 5
|
|
|
|
#define DEF_FIND_UDPRETRIES 3
|
2024-06-25 14:30:20 -07:00
|
|
|
#define DEF_MAX_RESTARTS 11
|
2024-11-11 14:06:28 +01:00
|
|
|
#define DEF_MAX_QUERIES 200
|
2009-09-01 00:22:28 +00:00
|
|
|
|
|
|
|
/*%
|
|
|
|
* Internal state for a single name resolution procedure
|
|
|
|
*/
|
|
|
|
typedef struct resctx {
|
|
|
|
unsigned int magic;
|
|
|
|
dns_client_t *client;
|
2018-04-17 08:29:14 -07:00
|
|
|
bool want_dnssec;
|
|
|
|
bool want_validation;
|
|
|
|
bool want_cdflag;
|
|
|
|
bool want_tcp;
|
2009-09-01 00:22:28 +00:00
|
|
|
|
|
|
|
ISC_LINK(struct resctx) link;
|
|
|
|
dns_view_t *view;
|
|
|
|
unsigned int restarts;
|
|
|
|
dns_fixedname_t name;
|
|
|
|
dns_rdatatype_t type;
|
|
|
|
dns_fetch_t *fetch;
|
|
|
|
dns_namelist_t namelist;
|
|
|
|
isc_result_t result;
|
2024-11-11 14:06:28 +01:00
|
|
|
isc_counter_t *qc;
|
2022-10-27 11:45:33 -07:00
|
|
|
dns_clientresume_t *rev;
|
2009-09-01 00:22:28 +00:00
|
|
|
dns_rdataset_t *rdataset;
|
|
|
|
dns_rdataset_t *sigrdataset;
|
|
|
|
} resctx_t;
|
|
|
|
|
|
|
|
/*%
|
|
|
|
* Argument of an internal event for synchronous name resolution.
|
|
|
|
*/
|
|
|
|
typedef struct resarg {
|
2022-07-26 13:03:45 +02:00
|
|
|
isc_mem_t *mctx;
|
2009-09-01 00:22:28 +00:00
|
|
|
dns_client_t *client;
|
2022-07-26 13:03:45 +02:00
|
|
|
const dns_name_t *name;
|
2009-09-01 00:22:28 +00:00
|
|
|
|
|
|
|
isc_result_t result;
|
|
|
|
isc_result_t vresult;
|
|
|
|
dns_namelist_t *namelist;
|
|
|
|
dns_clientrestrans_t *trans;
|
2022-07-26 13:03:45 +02:00
|
|
|
dns_client_resolve_cb resolve_cb;
|
2009-09-01 00:22:28 +00:00
|
|
|
} resarg_t;
|
|
|
|
|
|
|
|
static void
|
2022-10-28 01:33:40 -07:00
|
|
|
client_resfind(resctx_t *rctx, dns_fetchresponse_t *event);
|
2021-08-12 13:51:47 -07:00
|
|
|
static void
|
|
|
|
destroyrestrans(dns_clientrestrans_t **transp);
|
2009-09-01 00:22:28 +00:00
|
|
|
|
2019-03-08 13:13:32 +01:00
|
|
|
/*
|
|
|
|
* Try honoring the operating system's preferred ephemeral port range.
|
|
|
|
*/
|
|
|
|
static isc_result_t
|
|
|
|
setsourceports(isc_mem_t *mctx, dns_dispatchmgr_t *manager) {
|
|
|
|
isc_portset_t *v4portset = NULL, *v6portset = NULL;
|
|
|
|
in_port_t udpport_low, udpport_high;
|
|
|
|
isc_result_t result;
|
|
|
|
|
2025-01-07 19:03:07 -08:00
|
|
|
isc_portset_create(mctx, &v4portset);
|
2019-03-08 13:13:32 +01:00
|
|
|
result = isc_net_getudpportrange(AF_INET, &udpport_low, &udpport_high);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
isc_portset_addrange(v4portset, udpport_low, udpport_high);
|
|
|
|
|
2025-01-07 19:03:07 -08:00
|
|
|
isc_portset_create(mctx, &v6portset);
|
2019-03-08 13:13:32 +01:00
|
|
|
result = isc_net_getudpportrange(AF_INET6, &udpport_low, &udpport_high);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
isc_portset_addrange(v6portset, udpport_low, udpport_high);
|
|
|
|
|
|
|
|
result = dns_dispatchmgr_setavailports(manager, v4portset, v6portset);
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
if (v4portset != NULL) {
|
|
|
|
isc_portset_destroy(mctx, &v4portset);
|
|
|
|
}
|
|
|
|
if (v6portset != NULL) {
|
|
|
|
isc_portset_destroy(mctx, &v6portset);
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2009-09-01 00:22:28 +00:00
|
|
|
static isc_result_t
|
|
|
|
getudpdispatch(int family, dns_dispatchmgr_t *dispatchmgr,
|
2021-07-26 20:23:18 -07:00
|
|
|
dns_dispatch_t **dispp, const isc_sockaddr_t *localaddr) {
|
2020-12-16 01:32:06 -08:00
|
|
|
dns_dispatch_t *disp = NULL;
|
2009-09-01 00:22:28 +00:00
|
|
|
isc_result_t result;
|
2013-11-13 10:52:22 -08:00
|
|
|
isc_sockaddr_t anyaddr;
|
2009-09-01 00:22:28 +00:00
|
|
|
|
2013-11-13 10:52:22 -08:00
|
|
|
if (localaddr == NULL) {
|
2016-12-30 15:45:08 +11:00
|
|
|
isc_sockaddr_anyofpf(&anyaddr, family);
|
2013-11-13 10:52:22 -08:00
|
|
|
localaddr = &anyaddr;
|
|
|
|
}
|
2009-09-01 00:22:28 +00:00
|
|
|
|
2021-08-03 18:24:27 -07:00
|
|
|
result = dns_dispatch_createudp(dispatchmgr, localaddr, &disp);
|
2009-09-01 00:22:28 +00:00
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
*dispp = disp;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2009-09-01 00:22:28 +00:00
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
2025-07-14 17:12:35 +02:00
|
|
|
createview(isc_mem_t *mctx, dns_rdataclass_t rdclass,
|
2025-07-14 10:50:21 +02:00
|
|
|
isc_tlsctx_cache_t *tlsctx_client_cache,
|
2022-12-08 14:18:22 +00:00
|
|
|
dns_dispatchmgr_t *dispatchmgr, dns_dispatch_t *dispatchv4,
|
|
|
|
dns_dispatch_t *dispatchv6, dns_view_t **viewp) {
|
2009-09-01 00:22:28 +00:00
|
|
|
isc_result_t result;
|
|
|
|
dns_view_t *view = NULL;
|
|
|
|
|
2025-07-14 10:50:21 +02:00
|
|
|
dns_view_create(mctx, dispatchmgr, rdclass, DNS_CLIENTVIEW_NAME, &view);
|
2009-09-03 21:45:46 +00:00
|
|
|
|
2009-10-27 22:46:13 +00:00
|
|
|
/* Initialize view security roots */
|
2023-04-15 14:49:45 -07:00
|
|
|
dns_view_initsecroots(view);
|
2009-09-01 00:22:28 +00:00
|
|
|
|
2025-07-14 17:12:35 +02:00
|
|
|
CHECK(dns_view_createresolver(view, 0, tlsctx_client_cache, dispatchv4,
|
|
|
|
dispatchv6));
|
2024-03-05 16:17:33 -08:00
|
|
|
CHECK(dns_db_create(mctx, CACHEDB_DEFAULT, dns_rootname,
|
|
|
|
dns_dbtype_cache, rdclass, 0, NULL,
|
|
|
|
&view->cachedb));
|
2009-09-01 00:22:28 +00:00
|
|
|
|
|
|
|
*viewp = view;
|
|
|
|
return ISC_R_SUCCESS;
|
2022-07-26 13:03:45 +02:00
|
|
|
|
2023-04-15 14:49:45 -07:00
|
|
|
cleanup:
|
2022-07-26 13:03:45 +02:00
|
|
|
dns_view_detach(&view);
|
|
|
|
return result;
|
2009-09-01 00:22:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
isc_result_t
|
2025-07-14 17:12:35 +02:00
|
|
|
dns_client_create(isc_mem_t *mctx, unsigned int options,
|
2025-07-14 10:50:21 +02:00
|
|
|
isc_tlsctx_cache_t *tlsctx_client_cache,
|
2021-01-14 13:02:57 -08:00
|
|
|
dns_client_t **clientp, const isc_sockaddr_t *localaddr4,
|
2021-03-22 18:16:28 -07:00
|
|
|
const isc_sockaddr_t *localaddr6) {
|
2009-09-01 00:22:28 +00:00
|
|
|
isc_result_t result;
|
2021-03-22 18:16:28 -07:00
|
|
|
dns_client_t *client = NULL;
|
2009-09-01 00:22:28 +00:00
|
|
|
dns_dispatch_t *dispatchv4 = NULL;
|
|
|
|
dns_dispatch_t *dispatchv6 = NULL;
|
|
|
|
dns_view_t *view = NULL;
|
|
|
|
|
|
|
|
REQUIRE(mctx != NULL);
|
2022-12-08 14:18:22 +00:00
|
|
|
REQUIRE(tlsctx_client_cache != NULL);
|
2009-09-01 00:22:28 +00:00
|
|
|
REQUIRE(clientp != NULL && *clientp == NULL);
|
|
|
|
|
2020-04-22 13:26:19 +02:00
|
|
|
UNUSED(options);
|
|
|
|
|
2009-09-01 00:22:28 +00:00
|
|
|
client = isc_mem_get(mctx, sizeof(*client));
|
2021-01-14 13:02:57 -08:00
|
|
|
*client = (dns_client_t){
|
2025-07-14 10:50:21 +02:00
|
|
|
.loop = isc_loop_get(0),
|
2024-06-25 14:30:20 -07:00
|
|
|
.max_restarts = DEF_MAX_RESTARTS,
|
2024-11-11 14:06:28 +01:00
|
|
|
.max_queries = DEF_MAX_QUERIES,
|
2021-01-14 13:02:57 -08:00
|
|
|
};
|
2009-09-01 00:22:28 +00:00
|
|
|
|
2025-07-14 17:12:35 +02:00
|
|
|
result = dns_dispatchmgr_create(mctx, &client->dispatchmgr);
|
2009-09-01 00:22:28 +00:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2022-10-28 01:33:40 -07:00
|
|
|
goto cleanup_client;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2021-05-25 22:54:17 -07:00
|
|
|
(void)setsourceports(mctx, client->dispatchmgr);
|
2009-09-01 00:22:28 +00:00
|
|
|
|
2013-11-13 10:52:22 -08:00
|
|
|
/*
|
|
|
|
* If only one address family is specified, use it.
|
|
|
|
* If neither family is specified, or if both are, use both.
|
|
|
|
*/
|
2010-04-13 19:06:48 +00:00
|
|
|
client->dispatchv4 = NULL;
|
2013-11-13 10:52:22 -08:00
|
|
|
if (localaddr4 != NULL || localaddr6 == NULL) {
|
2021-07-26 20:23:18 -07:00
|
|
|
result = getudpdispatch(AF_INET, client->dispatchmgr,
|
2021-01-14 13:02:57 -08:00
|
|
|
&dispatchv4, localaddr4);
|
2019-08-06 17:35:20 +02:00
|
|
|
if (result == ISC_R_SUCCESS) {
|
2013-11-13 10:52:22 -08:00
|
|
|
client->dispatchv4 = dispatchv4;
|
2019-08-06 17:35:20 +02:00
|
|
|
}
|
2013-11-13 10:52:22 -08:00
|
|
|
}
|
|
|
|
|
2010-04-13 19:06:48 +00:00
|
|
|
client->dispatchv6 = NULL;
|
2013-11-13 10:52:22 -08:00
|
|
|
if (localaddr6 != NULL || localaddr4 == NULL) {
|
2021-07-26 20:23:18 -07:00
|
|
|
result = getudpdispatch(AF_INET6, client->dispatchmgr,
|
2021-01-14 13:02:57 -08:00
|
|
|
&dispatchv6, localaddr6);
|
2019-08-06 17:35:20 +02:00
|
|
|
if (result == ISC_R_SUCCESS) {
|
2013-11-13 10:52:22 -08:00
|
|
|
client->dispatchv6 = dispatchv6;
|
2019-08-06 17:35:20 +02:00
|
|
|
}
|
2013-11-13 10:52:22 -08:00
|
|
|
}
|
2010-04-13 19:06:48 +00:00
|
|
|
|
|
|
|
/* We need at least one of the dispatchers */
|
|
|
|
if (dispatchv4 == NULL && dispatchv6 == NULL) {
|
|
|
|
INSIST(result != ISC_R_SUCCESS);
|
2019-08-06 17:35:20 +02:00
|
|
|
goto cleanup_dispatchmgr;
|
2010-04-13 19:06:48 +00:00
|
|
|
}
|
2009-09-01 00:22:28 +00:00
|
|
|
|
2019-08-06 17:35:20 +02:00
|
|
|
isc_refcount_init(&client->references, 1);
|
|
|
|
|
2009-09-01 00:22:28 +00:00
|
|
|
/* Create the default view for class IN */
|
2025-07-14 17:12:35 +02:00
|
|
|
result = createview(mctx, dns_rdataclass_in, tlsctx_client_cache,
|
2024-03-26 00:13:45 -07:00
|
|
|
client->dispatchmgr, dispatchv4, dispatchv6, &view);
|
2019-08-06 17:35:20 +02:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
goto cleanup_references;
|
|
|
|
}
|
|
|
|
|
2022-07-26 13:03:45 +02:00
|
|
|
client->view = view;
|
2009-09-01 00:22:28 +00:00
|
|
|
|
|
|
|
dns_view_freeze(view); /* too early? */
|
|
|
|
|
|
|
|
ISC_LIST_INIT(client->resctxs);
|
|
|
|
|
|
|
|
isc_mem_attach(mctx, &client->mctx);
|
|
|
|
|
|
|
|
client->find_timeout = DEF_FIND_TIMEOUT;
|
|
|
|
client->find_udpretries = DEF_FIND_UDPRETRIES;
|
|
|
|
|
|
|
|
client->magic = DNS_CLIENT_MAGIC;
|
|
|
|
|
|
|
|
*clientp = client;
|
|
|
|
|
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
|
2019-08-06 17:35:20 +02:00
|
|
|
cleanup_references:
|
2019-12-05 13:29:45 +11:00
|
|
|
isc_refcount_decrementz(&client->references);
|
2019-08-06 17:35:20 +02:00
|
|
|
isc_refcount_destroy(&client->references);
|
|
|
|
cleanup_dispatchmgr:
|
|
|
|
if (dispatchv4 != NULL) {
|
2009-09-01 00:22:28 +00:00
|
|
|
dns_dispatch_detach(&dispatchv4);
|
2019-08-06 17:35:20 +02:00
|
|
|
}
|
|
|
|
if (dispatchv6 != NULL) {
|
2009-09-01 00:22:28 +00:00
|
|
|
dns_dispatch_detach(&dispatchv6);
|
2019-08-06 17:35:20 +02:00
|
|
|
}
|
2021-05-25 22:54:17 -07:00
|
|
|
dns_dispatchmgr_detach(&client->dispatchmgr);
|
2022-10-28 01:33:40 -07:00
|
|
|
cleanup_client:
|
2009-09-01 00:22:28 +00:00
|
|
|
isc_mem_put(mctx, client, sizeof(*client));
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2019-08-06 17:35:20 +02:00
|
|
|
destroyclient(dns_client_t *client) {
|
|
|
|
isc_refcount_destroy(&client->references);
|
|
|
|
|
2022-07-26 13:03:45 +02:00
|
|
|
dns_view_detach(&client->view);
|
2009-09-01 00:22:28 +00:00
|
|
|
|
|
|
|
if (client->dispatchv4 != NULL) {
|
|
|
|
dns_dispatch_detach(&client->dispatchv4);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2009-09-01 00:22:28 +00:00
|
|
|
if (client->dispatchv6 != NULL) {
|
|
|
|
dns_dispatch_detach(&client->dispatchv6);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2009-09-01 00:22:28 +00:00
|
|
|
|
2021-05-25 22:54:17 -07:00
|
|
|
dns_dispatchmgr_detach(&client->dispatchmgr);
|
2009-09-01 00:22:28 +00:00
|
|
|
|
|
|
|
client->magic = 0;
|
2009-09-02 23:48:03 +00:00
|
|
|
|
2009-09-01 00:22:28 +00:00
|
|
|
isc_mem_putanddetach(&client->mctx, client, sizeof(*client));
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2021-08-12 13:51:47 -07:00
|
|
|
dns_client_detach(dns_client_t **clientp) {
|
|
|
|
dns_client_t *client = NULL;
|
2009-09-01 00:22:28 +00:00
|
|
|
|
|
|
|
REQUIRE(clientp != NULL);
|
2021-08-12 13:51:47 -07:00
|
|
|
REQUIRE(DNS_CLIENT_VALID(*clientp));
|
|
|
|
|
2009-09-01 00:22:28 +00:00
|
|
|
client = *clientp;
|
2019-08-06 17:35:20 +02:00
|
|
|
*clientp = NULL;
|
2009-09-01 00:22:28 +00:00
|
|
|
|
2019-08-06 17:35:20 +02:00
|
|
|
if (isc_refcount_decrement(&client->references) == 1) {
|
|
|
|
destroyclient(client);
|
2009-09-01 00:22:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
isc_result_t
|
|
|
|
dns_client_setservers(dns_client_t *client, dns_rdataclass_t rdclass,
|
2017-07-21 11:52:24 +10:00
|
|
|
const dns_name_t *name_space, isc_sockaddrlist_t *addrs) {
|
2009-09-01 00:22:28 +00:00
|
|
|
isc_result_t result;
|
|
|
|
|
|
|
|
REQUIRE(DNS_CLIENT_VALID(client));
|
|
|
|
REQUIRE(addrs != NULL);
|
2022-07-26 13:03:45 +02:00
|
|
|
REQUIRE(rdclass == dns_rdataclass_in);
|
2009-09-01 00:22:28 +00:00
|
|
|
|
2017-07-21 11:52:24 +10:00
|
|
|
if (name_space == NULL) {
|
|
|
|
name_space = dns_rootname;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2009-09-01 00:22:28 +00:00
|
|
|
|
2022-07-26 13:03:45 +02:00
|
|
|
result = dns_fwdtable_add(client->view->fwdtable, name_space, addrs,
|
2009-09-01 00:22:28 +00:00
|
|
|
dns_fwdpolicy_only);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2024-06-25 14:30:20 -07:00
|
|
|
void
|
|
|
|
dns_client_setmaxrestarts(dns_client_t *client, uint8_t max_restarts) {
|
|
|
|
REQUIRE(DNS_CLIENT_VALID(client));
|
|
|
|
REQUIRE(max_restarts > 0);
|
|
|
|
|
|
|
|
client->max_restarts = max_restarts;
|
|
|
|
}
|
|
|
|
|
2024-11-11 14:06:28 +01:00
|
|
|
void
|
|
|
|
dns_client_setmaxqueries(dns_client_t *client, uint8_t max_queries) {
|
|
|
|
REQUIRE(DNS_CLIENT_VALID(client));
|
|
|
|
REQUIRE(max_queries > 0);
|
|
|
|
|
|
|
|
client->max_queries = max_queries;
|
|
|
|
}
|
|
|
|
|
2009-09-01 00:22:28 +00:00
|
|
|
static isc_result_t
|
|
|
|
getrdataset(isc_mem_t *mctx, dns_rdataset_t **rdatasetp) {
|
|
|
|
dns_rdataset_t *rdataset;
|
|
|
|
|
|
|
|
REQUIRE(mctx != NULL);
|
|
|
|
REQUIRE(rdatasetp != NULL && *rdatasetp == NULL);
|
|
|
|
|
|
|
|
rdataset = isc_mem_get(mctx, sizeof(*rdataset));
|
|
|
|
|
|
|
|
dns_rdataset_init(rdataset);
|
|
|
|
|
|
|
|
*rdatasetp = rdataset;
|
|
|
|
|
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
putrdataset(isc_mem_t *mctx, dns_rdataset_t **rdatasetp) {
|
|
|
|
dns_rdataset_t *rdataset;
|
|
|
|
|
|
|
|
REQUIRE(rdatasetp != NULL);
|
|
|
|
rdataset = *rdatasetp;
|
2020-02-08 04:37:54 -08:00
|
|
|
*rdatasetp = NULL;
|
2009-09-01 00:22:28 +00:00
|
|
|
REQUIRE(rdataset != NULL);
|
|
|
|
|
|
|
|
if (dns_rdataset_isassociated(rdataset)) {
|
|
|
|
dns_rdataset_disassociate(rdataset);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2009-09-01 00:22:28 +00:00
|
|
|
|
|
|
|
isc_mem_put(mctx, rdataset, sizeof(*rdataset));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2022-10-28 01:33:40 -07:00
|
|
|
fetch_done(void *arg) {
|
|
|
|
dns_fetchresponse_t *resp = (dns_fetchresponse_t *)arg;
|
|
|
|
resctx_t *rctx = resp->arg;
|
2009-09-01 00:22:28 +00:00
|
|
|
|
|
|
|
REQUIRE(RCTX_VALID(rctx));
|
|
|
|
|
2022-10-28 01:33:40 -07:00
|
|
|
client_resfind(rctx, resp);
|
2009-09-01 00:22:28 +00:00
|
|
|
}
|
|
|
|
|
2021-10-11 13:43:12 +02:00
|
|
|
static isc_result_t
|
2009-09-01 00:22:28 +00:00
|
|
|
start_fetch(resctx_t *rctx) {
|
|
|
|
isc_result_t result;
|
2014-02-16 13:03:17 -08:00
|
|
|
int fopts = 0;
|
2009-09-01 00:22:28 +00:00
|
|
|
|
|
|
|
REQUIRE(rctx->fetch == NULL);
|
|
|
|
|
2014-02-16 13:03:17 -08:00
|
|
|
if (!rctx->want_cdflag) {
|
|
|
|
fopts |= DNS_FETCHOPT_NOCDFLAG;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2014-02-16 13:03:17 -08:00
|
|
|
if (!rctx->want_validation) {
|
|
|
|
fopts |= DNS_FETCHOPT_NOVALIDATE;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2014-11-21 09:37:04 -08:00
|
|
|
if (rctx->want_tcp) {
|
|
|
|
fopts |= DNS_FETCHOPT_TCP;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2014-02-16 13:03:17 -08:00
|
|
|
|
2009-09-01 00:22:28 +00:00
|
|
|
result = dns_resolver_createfetch(
|
|
|
|
rctx->view->resolver, dns_fixedname_name(&rctx->name),
|
2024-11-11 14:06:28 +01:00
|
|
|
rctx->type, NULL, NULL, NULL, NULL, 0, fopts, 0, NULL, rctx->qc,
|
2025-01-29 11:11:32 +01:00
|
|
|
rctx->client->loop, fetch_done, rctx, NULL, rctx->rdataset,
|
2022-10-27 11:45:33 -07:00
|
|
|
rctx->sigrdataset, &rctx->fetch);
|
2009-09-01 00:22:28 +00:00
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
|
|
|
view_find(resctx_t *rctx, dns_db_t **dbp, dns_dbnode_t **nodep,
|
|
|
|
dns_name_t *foundname) {
|
|
|
|
isc_result_t result;
|
|
|
|
dns_name_t *name = dns_fixedname_name(&rctx->name);
|
|
|
|
dns_rdatatype_t type;
|
|
|
|
|
|
|
|
if (rctx->type == dns_rdatatype_rrsig) {
|
|
|
|
type = dns_rdatatype_any;
|
|
|
|
} else {
|
|
|
|
type = rctx->type;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2009-09-01 00:22:28 +00:00
|
|
|
|
2018-04-17 08:29:14 -07:00
|
|
|
result = dns_view_find(rctx->view, name, type, 0, 0, false, false, dbp,
|
|
|
|
nodep, foundname, rctx->rdataset,
|
2009-09-01 00:22:28 +00:00
|
|
|
rctx->sigrdataset);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2022-10-28 01:33:40 -07:00
|
|
|
client_resfind(resctx_t *rctx, dns_fetchresponse_t *resp) {
|
|
|
|
isc_mem_t *mctx = NULL;
|
2011-03-11 06:11:27 +00:00
|
|
|
isc_result_t tresult, result = ISC_R_SUCCESS;
|
2009-09-01 00:22:28 +00:00
|
|
|
isc_result_t vresult = ISC_R_SUCCESS;
|
2018-04-17 08:29:14 -07:00
|
|
|
bool want_restart;
|
|
|
|
bool send_event = false;
|
2021-04-22 18:58:01 -07:00
|
|
|
dns_name_t *name = NULL, *prefix = NULL;
|
2009-09-01 00:22:28 +00:00
|
|
|
dns_fixedname_t foundname, fixed;
|
2021-04-22 18:58:01 -07:00
|
|
|
dns_rdataset_t *trdataset = NULL;
|
2009-09-01 00:22:28 +00:00
|
|
|
dns_rdata_t rdata = DNS_RDATA_INIT;
|
|
|
|
unsigned int nlabels;
|
|
|
|
int order;
|
|
|
|
dns_namereln_t namereln;
|
|
|
|
dns_rdata_cname_t cname;
|
|
|
|
dns_rdata_dname_t dname;
|
|
|
|
|
|
|
|
REQUIRE(RCTX_VALID(rctx));
|
|
|
|
|
|
|
|
mctx = rctx->view->mctx;
|
|
|
|
|
|
|
|
name = dns_fixedname_name(&rctx->name);
|
|
|
|
|
|
|
|
do {
|
|
|
|
dns_name_t *fname = NULL;
|
|
|
|
dns_name_t *ansname = NULL;
|
|
|
|
dns_db_t *db = NULL;
|
|
|
|
dns_dbnode_t *node = NULL;
|
|
|
|
|
|
|
|
rctx->restarts++;
|
2018-04-17 08:29:14 -07:00
|
|
|
want_restart = false;
|
2009-09-01 00:22:28 +00:00
|
|
|
|
2022-10-28 01:33:40 -07:00
|
|
|
if (resp == NULL) {
|
2018-03-28 14:38:09 +02:00
|
|
|
fname = dns_fixedname_initname(&foundname);
|
2009-09-01 00:22:28 +00:00
|
|
|
INSIST(!dns_rdataset_isassociated(rctx->rdataset));
|
|
|
|
INSIST(rctx->sigrdataset == NULL ||
|
|
|
|
!dns_rdataset_isassociated(rctx->sigrdataset));
|
|
|
|
result = view_find(rctx, &db, &node, fname);
|
|
|
|
if (result == ISC_R_NOTFOUND) {
|
|
|
|
/*
|
|
|
|
* We don't know anything about the name.
|
|
|
|
* Launch a fetch.
|
|
|
|
*/
|
|
|
|
if (node != NULL) {
|
|
|
|
INSIST(db != 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
|
|
|
dns_db_detachnode(&node);
|
2009-09-01 00:22:28 +00:00
|
|
|
}
|
|
|
|
if (db != NULL) {
|
|
|
|
dns_db_detach(&db);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2009-09-01 00:22:28 +00:00
|
|
|
result = start_fetch(rctx);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
putrdataset(mctx, &rctx->rdataset);
|
|
|
|
if (rctx->sigrdataset != NULL) {
|
|
|
|
putrdataset(mctx,
|
|
|
|
&rctx->sigrdataset);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2018-04-17 08:29:14 -07:00
|
|
|
send_event = true;
|
2009-09-01 00:22:28 +00:00
|
|
|
}
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
} else {
|
2022-10-28 01:33:40 -07:00
|
|
|
INSIST(resp != NULL);
|
|
|
|
INSIST(resp->fetch == rctx->fetch);
|
2009-09-01 00:22:28 +00:00
|
|
|
dns_resolver_destroyfetch(&rctx->fetch);
|
2022-10-28 01:33:40 -07:00
|
|
|
db = resp->db;
|
|
|
|
node = resp->node;
|
|
|
|
result = resp->result;
|
|
|
|
vresult = resp->vresult;
|
|
|
|
fname = resp->foundname;
|
|
|
|
INSIST(resp->rdataset == rctx->rdataset);
|
|
|
|
INSIST(resp->sigrdataset == rctx->sigrdataset);
|
2024-11-08 18:18:30 +01:00
|
|
|
dns_resolver_freefresp(&resp);
|
2009-09-01 00:22:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2022-07-26 13:03:45 +02:00
|
|
|
* Get some resource for copying the
|
|
|
|
* result.
|
2009-09-01 00:22:28 +00:00
|
|
|
*/
|
2022-07-26 13:03:45 +02:00
|
|
|
dns_name_t *aname = dns_fixedname_name(&rctx->name);
|
2019-10-12 00:15:51 +02:00
|
|
|
|
2022-07-26 13:03:45 +02:00
|
|
|
ansname = isc_mem_get(mctx, sizeof(*ansname));
|
2025-02-21 12:09:39 +01:00
|
|
|
dns_name_init(ansname);
|
2019-10-12 00:15:51 +02:00
|
|
|
|
2022-07-26 13:03:45 +02:00
|
|
|
dns_name_dup(aname, mctx, ansname);
|
2009-09-01 00:22:28 +00:00
|
|
|
|
|
|
|
switch (result) {
|
|
|
|
case ISC_R_SUCCESS:
|
2018-04-17 08:29:14 -07:00
|
|
|
send_event = true;
|
2009-09-01 00:22:28 +00:00
|
|
|
/*
|
|
|
|
* This case is handled in the main line below.
|
|
|
|
*/
|
|
|
|
break;
|
|
|
|
case DNS_R_CNAME:
|
|
|
|
/*
|
|
|
|
* Add the CNAME to the answer list.
|
|
|
|
*/
|
|
|
|
trdataset = rctx->rdataset;
|
|
|
|
ISC_LIST_APPEND(ansname->list, rctx->rdataset, link);
|
|
|
|
rctx->rdataset = NULL;
|
|
|
|
if (rctx->sigrdataset != NULL) {
|
|
|
|
ISC_LIST_APPEND(ansname->list,
|
|
|
|
rctx->sigrdataset, link);
|
|
|
|
rctx->sigrdataset = NULL;
|
|
|
|
}
|
|
|
|
ISC_LIST_APPEND(rctx->namelist, ansname, link);
|
|
|
|
ansname = NULL;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Copy the CNAME's target into the lookup's
|
|
|
|
* query name and start over.
|
|
|
|
*/
|
|
|
|
tresult = dns_rdataset_first(trdataset);
|
|
|
|
if (tresult != ISC_R_SUCCESS) {
|
|
|
|
goto done;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2009-09-01 00:22:28 +00:00
|
|
|
dns_rdataset_current(trdataset, &rdata);
|
|
|
|
tresult = dns_rdata_tostruct(&rdata, &cname, NULL);
|
|
|
|
dns_rdata_reset(&rdata);
|
|
|
|
if (tresult != ISC_R_SUCCESS) {
|
|
|
|
goto done;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2021-05-21 17:20:44 -07:00
|
|
|
dns_name_copy(&cname.cname, name);
|
2009-09-01 00:22:28 +00:00
|
|
|
dns_rdata_freestruct(&cname);
|
2019-09-27 08:37:26 +02:00
|
|
|
want_restart = true;
|
2009-09-01 00:22:28 +00:00
|
|
|
goto done;
|
|
|
|
case DNS_R_DNAME:
|
|
|
|
/*
|
|
|
|
* Add the DNAME to the answer list.
|
|
|
|
*/
|
|
|
|
trdataset = rctx->rdataset;
|
|
|
|
ISC_LIST_APPEND(ansname->list, rctx->rdataset, link);
|
|
|
|
rctx->rdataset = NULL;
|
|
|
|
if (rctx->sigrdataset != NULL) {
|
|
|
|
ISC_LIST_APPEND(ansname->list,
|
|
|
|
rctx->sigrdataset, link);
|
|
|
|
rctx->sigrdataset = NULL;
|
|
|
|
}
|
|
|
|
ISC_LIST_APPEND(rctx->namelist, ansname, link);
|
|
|
|
ansname = NULL;
|
|
|
|
|
|
|
|
namereln = dns_name_fullcompare(name, fname, &order,
|
|
|
|
&nlabels);
|
|
|
|
INSIST(namereln == dns_namereln_subdomain);
|
|
|
|
/*
|
|
|
|
* Get the target name of the DNAME.
|
|
|
|
*/
|
|
|
|
tresult = dns_rdataset_first(trdataset);
|
|
|
|
if (tresult != ISC_R_SUCCESS) {
|
|
|
|
result = tresult;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
dns_rdataset_current(trdataset, &rdata);
|
|
|
|
tresult = dns_rdata_tostruct(&rdata, &dname, NULL);
|
|
|
|
dns_rdata_reset(&rdata);
|
|
|
|
if (tresult != ISC_R_SUCCESS) {
|
|
|
|
result = tresult;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Construct the new query name and start over.
|
|
|
|
*/
|
2018-03-28 14:38:09 +02:00
|
|
|
prefix = dns_fixedname_initname(&fixed);
|
2009-09-01 00:22:28 +00:00
|
|
|
dns_name_split(name, nlabels, prefix, NULL);
|
|
|
|
tresult = dns_name_concatenate(prefix, &dname.dname,
|
2025-02-21 00:56:47 -08:00
|
|
|
name);
|
2009-09-01 00:22:28 +00:00
|
|
|
dns_rdata_freestruct(&dname);
|
|
|
|
if (tresult == ISC_R_SUCCESS) {
|
2018-04-17 08:29:14 -07:00
|
|
|
want_restart = true;
|
2009-09-01 00:22:28 +00:00
|
|
|
} else {
|
|
|
|
result = tresult;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2009-09-01 00:22:28 +00:00
|
|
|
goto done;
|
|
|
|
case DNS_R_NCACHENXDOMAIN:
|
|
|
|
case DNS_R_NCACHENXRRSET:
|
|
|
|
ISC_LIST_APPEND(ansname->list, rctx->rdataset, link);
|
|
|
|
ISC_LIST_APPEND(rctx->namelist, ansname, link);
|
|
|
|
ansname = NULL;
|
|
|
|
rctx->rdataset = NULL;
|
|
|
|
/* What about sigrdataset? */
|
|
|
|
if (rctx->sigrdataset != NULL) {
|
|
|
|
putrdataset(mctx, &rctx->sigrdataset);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2018-04-17 08:29:14 -07:00
|
|
|
send_event = true;
|
2009-09-01 00:22:28 +00:00
|
|
|
goto done;
|
|
|
|
default:
|
|
|
|
if (rctx->rdataset != NULL) {
|
|
|
|
putrdataset(mctx, &rctx->rdataset);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2009-09-01 00:22:28 +00:00
|
|
|
if (rctx->sigrdataset != NULL) {
|
|
|
|
putrdataset(mctx, &rctx->sigrdataset);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2018-04-17 08:29:14 -07:00
|
|
|
send_event = true;
|
2009-09-01 00:22:28 +00:00
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rctx->type == dns_rdatatype_any) {
|
|
|
|
int n = 0;
|
|
|
|
dns_rdatasetiter_t *rdsiter = NULL;
|
|
|
|
|
2022-11-16 10:47:40 +11:00
|
|
|
tresult = dns_db_allrdatasets(db, node, NULL, 0, 0,
|
2009-09-01 00:22:28 +00:00
|
|
|
&rdsiter);
|
|
|
|
if (tresult != ISC_R_SUCCESS) {
|
|
|
|
result = tresult;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
tresult = dns_rdatasetiter_first(rdsiter);
|
|
|
|
while (tresult == ISC_R_SUCCESS) {
|
|
|
|
dns_rdatasetiter_current(rdsiter,
|
|
|
|
rctx->rdataset);
|
|
|
|
if (rctx->rdataset->type != 0) {
|
|
|
|
ISC_LIST_APPEND(ansname->list,
|
|
|
|
rctx->rdataset, link);
|
|
|
|
n++;
|
|
|
|
rctx->rdataset = NULL;
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* We're not interested in this
|
|
|
|
* rdataset.
|
|
|
|
*/
|
|
|
|
dns_rdataset_disassociate(
|
|
|
|
rctx->rdataset);
|
|
|
|
}
|
|
|
|
tresult = dns_rdatasetiter_next(rdsiter);
|
|
|
|
|
|
|
|
if (tresult == ISC_R_SUCCESS &&
|
2022-11-02 19:33:14 +01:00
|
|
|
rctx->rdataset == NULL)
|
|
|
|
{
|
2009-09-01 00:22:28 +00:00
|
|
|
tresult = getrdataset(mctx,
|
|
|
|
&rctx->rdataset);
|
|
|
|
if (tresult != ISC_R_SUCCESS) {
|
|
|
|
result = tresult;
|
2011-03-11 06:11:27 +00:00
|
|
|
POST(result);
|
2009-09-01 00:22:28 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-04-17 00:13:14 +10:00
|
|
|
if (rctx->rdataset != NULL) {
|
|
|
|
putrdataset(mctx, &rctx->rdataset);
|
|
|
|
}
|
|
|
|
if (rctx->sigrdataset != NULL) {
|
|
|
|
putrdataset(mctx, &rctx->sigrdataset);
|
|
|
|
}
|
2009-09-01 00:22:28 +00:00
|
|
|
if (n == 0) {
|
|
|
|
/*
|
|
|
|
* We didn't match any rdatasets (which means
|
|
|
|
* something went wrong in this
|
|
|
|
* implementation).
|
|
|
|
*/
|
|
|
|
result = DNS_R_SERVFAIL; /* better code? */
|
2011-03-11 06:11:27 +00:00
|
|
|
POST(result);
|
2009-09-01 00:22:28 +00:00
|
|
|
} else {
|
|
|
|
ISC_LIST_APPEND(rctx->namelist, ansname, link);
|
|
|
|
ansname = NULL;
|
|
|
|
}
|
|
|
|
dns_rdatasetiter_destroy(&rdsiter);
|
|
|
|
if (tresult != ISC_R_NOMORE) {
|
|
|
|
result = DNS_R_SERVFAIL; /* ditto */
|
|
|
|
} else {
|
|
|
|
result = ISC_R_SUCCESS;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2009-09-01 00:22:28 +00:00
|
|
|
goto done;
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* This is the "normal" case -- an ordinary question
|
|
|
|
* to which we've got the answer.
|
|
|
|
*/
|
|
|
|
ISC_LIST_APPEND(ansname->list, rctx->rdataset, link);
|
|
|
|
rctx->rdataset = NULL;
|
|
|
|
if (rctx->sigrdataset != NULL) {
|
|
|
|
ISC_LIST_APPEND(ansname->list,
|
|
|
|
rctx->sigrdataset, link);
|
|
|
|
rctx->sigrdataset = NULL;
|
|
|
|
}
|
|
|
|
ISC_LIST_APPEND(rctx->namelist, ansname, link);
|
|
|
|
ansname = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
done:
|
|
|
|
/*
|
|
|
|
* Free temporary resources
|
|
|
|
*/
|
|
|
|
if (ansname != NULL) {
|
2025-05-23 13:02:22 -07:00
|
|
|
ISC_LIST_FOREACH(ansname->list, rdataset, link) {
|
2009-09-01 00:22:28 +00:00
|
|
|
ISC_LIST_UNLINK(ansname->list, rdataset, link);
|
|
|
|
putrdataset(mctx, &rdataset);
|
|
|
|
}
|
|
|
|
dns_name_free(ansname, mctx);
|
|
|
|
isc_mem_put(mctx, ansname, sizeof(*ansname));
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
dns_db_detachnode(&node);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2009-09-01 00:22:28 +00:00
|
|
|
if (db != NULL) {
|
|
|
|
dns_db_detach(&db);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2009-09-01 00:22:28 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Limit the number of restarts.
|
|
|
|
*/
|
2024-06-25 14:30:20 -07:00
|
|
|
if (want_restart &&
|
|
|
|
rctx->restarts == rctx->client->max_restarts)
|
|
|
|
{
|
2018-04-17 08:29:14 -07:00
|
|
|
want_restart = false;
|
2009-09-01 00:22:28 +00:00
|
|
|
result = ISC_R_QUOTA;
|
2018-04-17 08:29:14 -07:00
|
|
|
send_event = true;
|
2009-09-01 00:22:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Prepare further find with new resources
|
|
|
|
*/
|
|
|
|
if (want_restart) {
|
|
|
|
INSIST(rctx->rdataset == NULL &&
|
|
|
|
rctx->sigrdataset == NULL);
|
|
|
|
|
|
|
|
result = getrdataset(mctx, &rctx->rdataset);
|
|
|
|
if (result == ISC_R_SUCCESS && rctx->want_dnssec) {
|
|
|
|
result = getrdataset(mctx, &rctx->sigrdataset);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
putrdataset(mctx, &rctx->rdataset);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
2018-04-17 08:29:14 -07:00
|
|
|
want_restart = false;
|
|
|
|
send_event = true;
|
2009-09-01 00:22:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} while (want_restart);
|
|
|
|
|
|
|
|
if (send_event) {
|
2025-05-23 13:02:22 -07:00
|
|
|
ISC_LIST_FOREACH(rctx->namelist, n, link) {
|
2025-03-20 15:46:35 -07:00
|
|
|
ISC_LIST_UNLINK(rctx->namelist, n, link);
|
|
|
|
ISC_LIST_APPEND(rctx->rev->answerlist, n, link);
|
2009-09-01 00:22:28 +00:00
|
|
|
}
|
|
|
|
|
2022-10-27 11:45:33 -07:00
|
|
|
rctx->rev->result = result;
|
|
|
|
rctx->rev->vresult = vresult;
|
|
|
|
isc_async_run(rctx->client->loop, rctx->rev->cb, rctx->rev);
|
2009-09-01 00:22:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2022-10-27 11:45:33 -07:00
|
|
|
resolve_done(void *arg) {
|
|
|
|
dns_clientresume_t *rev = (dns_clientresume_t *)arg;
|
|
|
|
resarg_t *resarg = rev->arg;
|
2022-07-26 13:03:45 +02:00
|
|
|
isc_result_t result;
|
2009-09-01 00:22:28 +00:00
|
|
|
|
|
|
|
resarg->result = rev->result;
|
|
|
|
resarg->vresult = rev->vresult;
|
2025-03-19 20:29:17 +01:00
|
|
|
|
2025-05-23 13:02:22 -07:00
|
|
|
ISC_LIST_FOREACH(rev->answerlist, name, link) {
|
2009-09-01 00:22:28 +00:00
|
|
|
ISC_LIST_UNLINK(rev->answerlist, name, link);
|
|
|
|
ISC_LIST_APPEND(*resarg->namelist, name, link);
|
|
|
|
}
|
|
|
|
|
2022-10-27 11:45:33 -07:00
|
|
|
isc_mem_put(resarg->mctx, rev, sizeof(*rev));
|
2022-07-26 13:03:45 +02:00
|
|
|
destroyrestrans(&resarg->trans);
|
2009-09-01 00:22:28 +00:00
|
|
|
|
2022-07-26 13:03:45 +02:00
|
|
|
result = resarg->result;
|
|
|
|
|
|
|
|
if (result != ISC_R_SUCCESS && resarg->vresult != ISC_R_SUCCESS) {
|
2013-05-09 08:41:24 +10:00
|
|
|
/*
|
2022-07-26 13:03:45 +02:00
|
|
|
* If this lookup failed due to some error in DNSSEC
|
|
|
|
* validation, return the validation error code.
|
|
|
|
* XXX: or should we pass the validation result separately?
|
2009-09-01 00:22:28 +00:00
|
|
|
*/
|
2022-07-26 13:03:45 +02:00
|
|
|
result = resarg->vresult;
|
2009-09-01 00:22:28 +00:00
|
|
|
}
|
2021-08-12 13:51:47 -07:00
|
|
|
|
2022-07-26 13:03:45 +02:00
|
|
|
resarg->resolve_cb(resarg->client, resarg->name, resarg->namelist,
|
|
|
|
result);
|
|
|
|
|
|
|
|
dns_client_detach(&resarg->client);
|
|
|
|
|
|
|
|
isc_mem_putanddetach(&resarg->mctx, resarg, sizeof(*resarg));
|
2009-09-01 00:22:28 +00:00
|
|
|
}
|
|
|
|
|
2023-10-31 14:20:51 +01:00
|
|
|
static isc_result_t
|
|
|
|
startresolve(dns_client_t *client, const dns_name_t *name,
|
|
|
|
dns_rdataclass_t rdclass, dns_rdatatype_t type,
|
|
|
|
unsigned int options, isc_job_cb cb, void *arg,
|
|
|
|
dns_clientrestrans_t **transp) {
|
2022-10-27 11:45:33 -07:00
|
|
|
dns_clientresume_t *rev = NULL;
|
2009-09-01 00:22:28 +00:00
|
|
|
resctx_t *rctx = NULL;
|
2022-10-27 11:45:33 -07:00
|
|
|
isc_mem_t *mctx = NULL;
|
2009-09-01 00:22:28 +00:00
|
|
|
isc_result_t result;
|
2022-10-27 11:45:33 -07:00
|
|
|
dns_rdataset_t *rdataset = NULL, *sigrdataset = NULL;
|
2018-04-17 08:29:14 -07:00
|
|
|
bool want_dnssec, want_validation, want_cdflag, want_tcp;
|
2009-09-01 00:22:28 +00:00
|
|
|
|
|
|
|
REQUIRE(DNS_CLIENT_VALID(client));
|
|
|
|
REQUIRE(transp != NULL && *transp == NULL);
|
2022-07-26 13:03:45 +02:00
|
|
|
REQUIRE(rdclass == dns_rdataclass_in);
|
2009-09-01 00:22:28 +00:00
|
|
|
|
|
|
|
mctx = client->mctx;
|
2018-10-11 11:57:57 +02:00
|
|
|
want_dnssec = ((options & DNS_CLIENTRESOPT_NODNSSEC) == 0);
|
|
|
|
want_validation = ((options & DNS_CLIENTRESOPT_NOVALIDATE) == 0);
|
|
|
|
want_cdflag = ((options & DNS_CLIENTRESOPT_NOCDFLAG) == 0);
|
|
|
|
want_tcp = ((options & DNS_CLIENTRESOPT_TCP) != 0);
|
2009-09-01 00:22:28 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Prepare some intermediate resources
|
|
|
|
*/
|
2022-10-27 11:45:33 -07:00
|
|
|
rev = isc_mem_get(mctx, sizeof(*rev));
|
|
|
|
*rev = (dns_clientresume_t){
|
|
|
|
.result = DNS_R_SERVFAIL,
|
|
|
|
.answerlist = ISC_LIST_INITIALIZER,
|
|
|
|
.cb = cb,
|
|
|
|
.arg = arg,
|
|
|
|
};
|
2009-09-01 00:22:28 +00:00
|
|
|
|
|
|
|
rctx = isc_mem_get(mctx, sizeof(*rctx));
|
2022-07-26 13:03:45 +02:00
|
|
|
*rctx = (resctx_t){
|
|
|
|
.client = client,
|
2022-10-27 11:45:33 -07:00
|
|
|
.rev = rev,
|
2022-07-26 13:03:45 +02:00
|
|
|
.type = type,
|
|
|
|
.want_dnssec = want_dnssec,
|
|
|
|
.want_validation = want_validation,
|
|
|
|
.want_cdflag = want_cdflag,
|
|
|
|
.want_tcp = want_tcp,
|
2022-10-27 11:45:33 -07:00
|
|
|
.namelist = ISC_LIST_INITIALIZER,
|
|
|
|
.link = ISC_LINK_INITIALIZER,
|
2022-07-26 13:03:45 +02:00
|
|
|
};
|
2009-09-01 00:22:28 +00:00
|
|
|
|
|
|
|
result = getrdataset(mctx, &rdataset);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
goto cleanup;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2009-09-01 00:22:28 +00:00
|
|
|
rctx->rdataset = rdataset;
|
|
|
|
|
|
|
|
if (want_dnssec) {
|
|
|
|
result = getrdataset(mctx, &sigrdataset);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
goto cleanup;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2009-09-01 00:22:28 +00:00
|
|
|
}
|
|
|
|
rctx->sigrdataset = sigrdataset;
|
|
|
|
|
|
|
|
dns_fixedname_init(&rctx->name);
|
2021-05-21 17:20:44 -07:00
|
|
|
dns_name_copy(name, dns_fixedname_name(&rctx->name));
|
2009-09-01 00:22:28 +00:00
|
|
|
|
2022-07-26 13:03:45 +02:00
|
|
|
dns_view_attach(client->view, &rctx->view);
|
2009-09-01 00:22:28 +00:00
|
|
|
|
|
|
|
rctx->magic = RCTX_MAGIC;
|
2019-08-06 17:35:20 +02:00
|
|
|
isc_refcount_increment(&client->references);
|
2009-09-01 00:22:28 +00:00
|
|
|
|
2025-02-19 06:49:38 +01:00
|
|
|
isc_counter_create(mctx, client->max_queries, &rctx->qc);
|
2024-11-11 14:06:28 +01:00
|
|
|
|
2009-09-01 00:22:28 +00:00
|
|
|
ISC_LIST_APPEND(client->resctxs, rctx, link);
|
|
|
|
|
|
|
|
*transp = (dns_clientrestrans_t *)rctx;
|
2013-05-09 08:41:24 +10:00
|
|
|
client_resfind(rctx, NULL);
|
2009-09-01 00:22:28 +00:00
|
|
|
|
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
if (rdataset != NULL) {
|
|
|
|
putrdataset(client->mctx, &rdataset);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2009-09-01 00:22:28 +00:00
|
|
|
if (sigrdataset != NULL) {
|
|
|
|
putrdataset(client->mctx, &sigrdataset);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2024-11-11 14:06:28 +01:00
|
|
|
if (rctx->qc != NULL) {
|
|
|
|
isc_counter_detach(&rctx->qc);
|
|
|
|
}
|
2020-07-02 16:21:20 +10:00
|
|
|
isc_mem_put(mctx, rctx, sizeof(*rctx));
|
2022-10-27 11:45:33 -07:00
|
|
|
isc_mem_put(mctx, rev, sizeof(*rev));
|
2009-09-01 00:22:28 +00:00
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2023-10-31 14:20:51 +01:00
|
|
|
isc_result_t
|
|
|
|
dns_client_resolve(dns_client_t *client, const dns_name_t *name,
|
|
|
|
dns_rdataclass_t rdclass, dns_rdatatype_t type,
|
|
|
|
unsigned int options, dns_namelist_t *namelist,
|
|
|
|
dns_client_resolve_cb resolve_cb) {
|
|
|
|
isc_result_t result;
|
|
|
|
resarg_t *resarg = NULL;
|
|
|
|
|
|
|
|
REQUIRE(DNS_CLIENT_VALID(client));
|
|
|
|
REQUIRE(namelist != NULL && ISC_LIST_EMPTY(*namelist));
|
|
|
|
REQUIRE(rdclass == dns_rdataclass_in);
|
|
|
|
|
|
|
|
resarg = isc_mem_get(client->mctx, sizeof(*resarg));
|
|
|
|
|
|
|
|
*resarg = (resarg_t){
|
|
|
|
.client = client,
|
|
|
|
.name = name,
|
|
|
|
.result = DNS_R_SERVFAIL,
|
|
|
|
.namelist = namelist,
|
|
|
|
.resolve_cb = resolve_cb,
|
|
|
|
};
|
|
|
|
|
|
|
|
isc_mem_attach(client->mctx, &resarg->mctx);
|
|
|
|
|
|
|
|
result = startresolve(client, name, rdclass, type, options,
|
|
|
|
resolve_done, resarg, &resarg->trans);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
isc_mem_put(client->mctx, resarg, sizeof(*resarg));
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2009-09-01 00:22:28 +00:00
|
|
|
void
|
2009-09-02 23:48:03 +00:00
|
|
|
dns_client_freeresanswer(dns_client_t *client, dns_namelist_t *namelist) {
|
2009-09-01 00:22:28 +00:00
|
|
|
REQUIRE(DNS_CLIENT_VALID(client));
|
|
|
|
REQUIRE(namelist != NULL);
|
|
|
|
|
2025-05-23 13:02:22 -07:00
|
|
|
ISC_LIST_FOREACH(*namelist, name, link) {
|
2009-09-01 00:22:28 +00:00
|
|
|
ISC_LIST_UNLINK(*namelist, name, link);
|
2025-03-19 20:29:17 +01:00
|
|
|
|
2025-05-23 13:02:22 -07:00
|
|
|
ISC_LIST_FOREACH(name->list, rdataset, link) {
|
2009-09-01 00:22:28 +00:00
|
|
|
ISC_LIST_UNLINK(name->list, rdataset, link);
|
|
|
|
putrdataset(client->mctx, &rdataset);
|
|
|
|
}
|
2025-03-20 15:46:35 -07:00
|
|
|
|
2009-09-01 00:22:28 +00:00
|
|
|
dns_name_free(name, client->mctx);
|
|
|
|
isc_mem_put(client->mctx, name, sizeof(*name));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-12 13:51:47 -07:00
|
|
|
/*%
|
|
|
|
* Destroy name resolution transaction state identified by '*transp'.
|
|
|
|
*
|
|
|
|
* The caller must have received the CLIENTRESDONE event (either because the
|
|
|
|
* resolution completed or because cancelresolve() was called).
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
destroyrestrans(dns_clientrestrans_t **transp) {
|
|
|
|
resctx_t *rctx = NULL;
|
|
|
|
isc_mem_t *mctx = NULL;
|
|
|
|
dns_client_t *client = NULL;
|
2009-09-01 00:22:28 +00:00
|
|
|
|
|
|
|
REQUIRE(transp != NULL);
|
2021-08-12 13:51:47 -07:00
|
|
|
|
2009-09-01 00:22:28 +00:00
|
|
|
rctx = (resctx_t *)*transp;
|
2019-08-06 17:35:20 +02:00
|
|
|
*transp = NULL;
|
2021-08-12 13:51:47 -07:00
|
|
|
|
2009-09-01 00:22:28 +00:00
|
|
|
REQUIRE(RCTX_VALID(rctx));
|
|
|
|
REQUIRE(rctx->fetch == NULL);
|
2021-08-12 13:51:47 -07:00
|
|
|
|
2009-09-01 00:22:28 +00:00
|
|
|
client = rctx->client;
|
2021-08-12 13:51:47 -07:00
|
|
|
|
2009-09-01 00:22:28 +00:00
|
|
|
REQUIRE(DNS_CLIENT_VALID(client));
|
|
|
|
|
|
|
|
mctx = client->mctx;
|
|
|
|
dns_view_detach(&rctx->view);
|
|
|
|
|
|
|
|
INSIST(ISC_LINK_LINKED(rctx, link));
|
|
|
|
ISC_LIST_UNLINK(client->resctxs, rctx, link);
|
|
|
|
|
|
|
|
INSIST(ISC_LIST_EMPTY(rctx->namelist));
|
|
|
|
|
|
|
|
rctx->magic = 0;
|
|
|
|
|
2024-11-11 14:06:28 +01:00
|
|
|
if (rctx->qc != NULL) {
|
|
|
|
isc_counter_detach(&rctx->qc);
|
|
|
|
}
|
2009-09-01 00:22:28 +00:00
|
|
|
isc_mem_put(mctx, rctx, sizeof(*rctx));
|
|
|
|
}
|
|
|
|
|
|
|
|
isc_result_t
|
|
|
|
dns_client_addtrustedkey(dns_client_t *client, dns_rdataclass_t rdclass,
|
2019-09-18 19:45:20 -07:00
|
|
|
dns_rdatatype_t rdtype, const dns_name_t *keyname,
|
|
|
|
isc_buffer_t *databuf) {
|
2009-09-01 00:22:28 +00:00
|
|
|
REQUIRE(DNS_CLIENT_VALID(client));
|
2022-07-26 13:03:45 +02:00
|
|
|
REQUIRE(rdclass == dns_rdataclass_in);
|
2009-09-01 00:22:28 +00:00
|
|
|
|
2023-01-31 13:30:12 -08:00
|
|
|
return dns_view_addtrustedkey(client->view, rdtype, keyname, databuf);
|
2009-09-01 00:22:28 +00:00
|
|
|
}
|