1/*	$NetBSD: context.c,v 1.1 2024/02/18 20:57:47 christos Exp $	*/
2
3/*
4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5 *
6 * SPDX-License-Identifier: MPL-2.0
7 *
8 * This Source Code Form is subject to the terms of the Mozilla Public
9 * License, v. 2.0.  If a copy of the MPL was not distributed with this
10 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
11 *
12 * See the COPYRIGHT file distributed with this work for additional
13 * information regarding copyright ownership.
14 */
15
16#include <stdbool.h>
17
18#include <isc/app.h>
19#include <isc/lib.h>
20#include <isc/magic.h>
21#include <isc/managers.h>
22#include <isc/mem.h>
23#include <isc/netmgr.h>
24#include <isc/once.h>
25#include <isc/socket.h>
26#include <isc/task.h>
27#include <isc/thread.h>
28#include <isc/timer.h>
29#include <isc/util.h>
30
31#include <dns/client.h>
32#include <dns/lib.h>
33
34#include <irs/context.h>
35#include <irs/dnsconf.h>
36#include <irs/resconf.h>
37
38#define IRS_CONTEXT_MAGIC    ISC_MAGIC('I', 'R', 'S', 'c')
39#define IRS_CONTEXT_VALID(c) ISC_MAGIC_VALID(c, IRS_CONTEXT_MAGIC)
40
41#ifndef RESOLV_CONF
42/*% location of resolve.conf */
43#define RESOLV_CONF "/etc/resolv.conf"
44#endif /* ifndef RESOLV_CONF */
45
46#ifndef DNS_CONF
47/*% location of dns.conf */
48#define DNS_CONF "/etc/dns.conf"
49#endif /* ifndef DNS_CONF */
50
51ISC_THREAD_LOCAL irs_context_t *irs_context = NULL;
52
53struct irs_context {
54	/*
55	 * An IRS context is a thread-specific object, and does not need to
56	 * be locked.
57	 */
58	unsigned int magic;
59	isc_mem_t *mctx;
60	isc_appctx_t *actx;
61	isc_nm_t *netmgr;
62	isc_taskmgr_t *taskmgr;
63	isc_task_t *task;
64	isc_socketmgr_t *socketmgr;
65	isc_timermgr_t *timermgr;
66	dns_client_t *dnsclient;
67	irs_resconf_t *resconf;
68	irs_dnsconf_t *dnsconf;
69};
70
71static void
72ctxs_destroy(isc_mem_t **mctxp, isc_appctx_t **actxp, isc_nm_t **netmgrp,
73	     isc_taskmgr_t **taskmgrp, isc_socketmgr_t **socketmgrp,
74	     isc_timermgr_t **timermgrp) {
75	isc_managers_destroy(netmgrp == NULL ? NULL : netmgrp,
76			     taskmgrp == NULL ? NULL : taskmgrp);
77
78	if (timermgrp != NULL) {
79		isc_timermgr_destroy(timermgrp);
80	}
81
82	if (socketmgrp != NULL) {
83		isc_socketmgr_destroy(socketmgrp);
84	}
85
86	if (actxp != NULL) {
87		isc_appctx_destroy(actxp);
88	}
89
90	if (mctxp != NULL) {
91		isc_mem_destroy(mctxp);
92	}
93}
94
95static isc_result_t
96ctxs_init(isc_mem_t **mctxp, isc_appctx_t **actxp, isc_nm_t **netmgrp,
97	  isc_taskmgr_t **taskmgrp, isc_socketmgr_t **socketmgrp,
98	  isc_timermgr_t **timermgrp) {
99	isc_result_t result;
100
101	isc_mem_create(mctxp);
102
103	result = isc_appctx_create(*mctxp, actxp);
104	if (result != ISC_R_SUCCESS) {
105		goto fail;
106	}
107
108	result = isc_managers_create(*mctxp, 1, 0, netmgrp, taskmgrp);
109	if (result != ISC_R_SUCCESS) {
110		goto fail;
111	}
112
113	result = isc_socketmgr_create(*mctxp, socketmgrp);
114	if (result != ISC_R_SUCCESS) {
115		goto fail;
116	}
117
118	result = isc_timermgr_create(*mctxp, timermgrp);
119	if (result != ISC_R_SUCCESS) {
120		goto fail;
121	}
122
123	return (ISC_R_SUCCESS);
124
125fail:
126	ctxs_destroy(mctxp, actxp, netmgrp, taskmgrp, socketmgrp, timermgrp);
127
128	return (result);
129}
130
131isc_result_t
132irs_context_get(irs_context_t **contextp) {
133	isc_result_t result;
134
135	REQUIRE(contextp != NULL && *contextp == NULL);
136
137	if (irs_context == NULL) {
138		result = irs_context_create(&irs_context);
139		if (result != ISC_R_SUCCESS) {
140			return (result);
141		}
142	}
143
144	*contextp = irs_context;
145
146	return (ISC_R_SUCCESS);
147}
148
149isc_result_t
150irs_context_create(irs_context_t **contextp) {
151	isc_result_t result;
152	irs_context_t *context;
153	isc_appctx_t *actx = NULL;
154	isc_mem_t *mctx = NULL;
155	isc_nm_t *netmgr = NULL;
156	isc_taskmgr_t *taskmgr = NULL;
157	isc_socketmgr_t *socketmgr = NULL;
158	isc_timermgr_t *timermgr = NULL;
159	dns_client_t *client = NULL;
160	isc_sockaddrlist_t *nameservers;
161	irs_dnsconf_dnskeylist_t *trustedkeys;
162	irs_dnsconf_dnskey_t *trustedkey;
163
164	isc_lib_register();
165	result = dns_lib_init();
166	if (result != ISC_R_SUCCESS) {
167		return (result);
168	}
169
170	result = ctxs_init(&mctx, &actx, &netmgr, &taskmgr, &socketmgr,
171			   &timermgr);
172	if (result != ISC_R_SUCCESS) {
173		return (result);
174	}
175
176	result = isc_app_ctxstart(actx);
177	if (result != ISC_R_SUCCESS) {
178		ctxs_destroy(&mctx, &actx, &netmgr, &taskmgr, &socketmgr,
179			     &timermgr);
180		return (result);
181	}
182
183	context = isc_mem_get(mctx, sizeof(*context));
184
185	context->mctx = mctx;
186	context->actx = actx;
187	context->taskmgr = taskmgr;
188	context->socketmgr = socketmgr;
189	context->timermgr = timermgr;
190	context->resconf = NULL;
191	context->dnsconf = NULL;
192	context->task = NULL;
193	result = isc_task_create(taskmgr, 0, &context->task);
194	if (result != ISC_R_SUCCESS) {
195		goto fail;
196	}
197
198	/* Create a DNS client object */
199	result = dns_client_create(mctx, actx, taskmgr, socketmgr, timermgr, 0,
200				   &client, NULL, NULL);
201	if (result != ISC_R_SUCCESS) {
202		goto fail;
203	}
204	context->dnsclient = client;
205
206	/* Read resolver configuration file */
207	result = irs_resconf_load(mctx, RESOLV_CONF, &context->resconf);
208	if (result != ISC_R_SUCCESS) {
209		goto fail;
210	}
211	/* Set nameservers */
212	nameservers = irs_resconf_getnameservers(context->resconf);
213	result = dns_client_setservers(client, dns_rdataclass_in, NULL,
214				       nameservers);
215	if (result != ISC_R_SUCCESS) {
216		goto fail;
217	}
218
219	/* Read advanced DNS configuration (if any) */
220	result = irs_dnsconf_load(mctx, DNS_CONF, &context->dnsconf);
221	if (result != ISC_R_SUCCESS) {
222		goto fail;
223	}
224	trustedkeys = irs_dnsconf_gettrustedkeys(context->dnsconf);
225	for (trustedkey = ISC_LIST_HEAD(*trustedkeys); trustedkey != NULL;
226	     trustedkey = ISC_LIST_NEXT(trustedkey, link))
227	{
228		result = dns_client_addtrustedkey(
229			client, dns_rdataclass_in, dns_rdatatype_dnskey,
230			trustedkey->keyname, trustedkey->keydatabuf);
231		if (result != ISC_R_SUCCESS) {
232			goto fail;
233		}
234	}
235
236	context->magic = IRS_CONTEXT_MAGIC;
237	*contextp = context;
238
239	return (ISC_R_SUCCESS);
240
241fail:
242	if (context->task != NULL) {
243		isc_task_detach(&context->task);
244	}
245	if (context->resconf != NULL) {
246		irs_resconf_destroy(&context->resconf);
247	}
248	if (context->dnsconf != NULL) {
249		irs_dnsconf_destroy(&context->dnsconf);
250	}
251	if (client != NULL) {
252		dns_client_destroy(&client);
253	}
254	ctxs_destroy(NULL, &actx, &netmgr, &taskmgr, &socketmgr, &timermgr);
255	isc_mem_putanddetach(&mctx, context, sizeof(*context));
256
257	return (result);
258}
259
260void
261irs_context_destroy(irs_context_t **contextp) {
262	irs_context_t *context;
263
264	REQUIRE(contextp != NULL);
265	context = *contextp;
266	REQUIRE(IRS_CONTEXT_VALID(context));
267	*contextp = irs_context = NULL;
268
269	isc_task_detach(&context->task);
270	irs_dnsconf_destroy(&context->dnsconf);
271	irs_resconf_destroy(&context->resconf);
272	dns_client_destroy(&context->dnsclient);
273
274	ctxs_destroy(NULL, &context->actx, &context->netmgr, &context->taskmgr,
275		     &context->socketmgr, &context->timermgr);
276
277	context->magic = 0;
278
279	isc_mem_putanddetach(&context->mctx, context, sizeof(*context));
280}
281
282isc_mem_t *
283irs_context_getmctx(irs_context_t *context) {
284	REQUIRE(IRS_CONTEXT_VALID(context));
285
286	return (context->mctx);
287}
288
289isc_appctx_t *
290irs_context_getappctx(irs_context_t *context) {
291	REQUIRE(IRS_CONTEXT_VALID(context));
292
293	return (context->actx);
294}
295
296isc_taskmgr_t *
297irs_context_gettaskmgr(irs_context_t *context) {
298	REQUIRE(IRS_CONTEXT_VALID(context));
299
300	return (context->taskmgr);
301}
302
303isc_timermgr_t *
304irs_context_gettimermgr(irs_context_t *context) {
305	REQUIRE(IRS_CONTEXT_VALID(context));
306
307	return (context->timermgr);
308}
309
310isc_task_t *
311irs_context_gettask(irs_context_t *context) {
312	REQUIRE(IRS_CONTEXT_VALID(context));
313
314	return (context->task);
315}
316
317dns_client_t *
318irs_context_getdnsclient(irs_context_t *context) {
319	REQUIRE(IRS_CONTEXT_VALID(context));
320
321	return (context->dnsclient);
322}
323
324irs_resconf_t *
325irs_context_getresconf(irs_context_t *context) {
326	REQUIRE(IRS_CONTEXT_VALID(context));
327
328	return (context->resconf);
329}
330
331irs_dnsconf_t *
332irs_context_getdnsconf(irs_context_t *context) {
333	REQUIRE(IRS_CONTEXT_VALID(context));
334
335	return (context->dnsconf);
336}
337