Home | History | Annotate | Line # | Download | only in irs
      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 
     51 ISC_THREAD_LOCAL irs_context_t *irs_context = NULL;
     52 
     53 struct 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 
     71 static void
     72 ctxs_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 
     95 static isc_result_t
     96 ctxs_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 
    125 fail:
    126 	ctxs_destroy(mctxp, actxp, netmgrp, taskmgrp, socketmgrp, timermgrp);
    127 
    128 	return (result);
    129 }
    130 
    131 isc_result_t
    132 irs_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 
    149 isc_result_t
    150 irs_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 
    241 fail:
    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 
    260 void
    261 irs_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 
    282 isc_mem_t *
    283 irs_context_getmctx(irs_context_t *context) {
    284 	REQUIRE(IRS_CONTEXT_VALID(context));
    285 
    286 	return (context->mctx);
    287 }
    288 
    289 isc_appctx_t *
    290 irs_context_getappctx(irs_context_t *context) {
    291 	REQUIRE(IRS_CONTEXT_VALID(context));
    292 
    293 	return (context->actx);
    294 }
    295 
    296 isc_taskmgr_t *
    297 irs_context_gettaskmgr(irs_context_t *context) {
    298 	REQUIRE(IRS_CONTEXT_VALID(context));
    299 
    300 	return (context->taskmgr);
    301 }
    302 
    303 isc_timermgr_t *
    304 irs_context_gettimermgr(irs_context_t *context) {
    305 	REQUIRE(IRS_CONTEXT_VALID(context));
    306 
    307 	return (context->timermgr);
    308 }
    309 
    310 isc_task_t *
    311 irs_context_gettask(irs_context_t *context) {
    312 	REQUIRE(IRS_CONTEXT_VALID(context));
    313 
    314 	return (context->task);
    315 }
    316 
    317 dns_client_t *
    318 irs_context_getdnsclient(irs_context_t *context) {
    319 	REQUIRE(IRS_CONTEXT_VALID(context));
    320 
    321 	return (context->dnsclient);
    322 }
    323 
    324 irs_resconf_t *
    325 irs_context_getresconf(irs_context_t *context) {
    326 	REQUIRE(IRS_CONTEXT_VALID(context));
    327 
    328 	return (context->resconf);
    329 }
    330 
    331 irs_dnsconf_t *
    332 irs_context_getdnsconf(irs_context_t *context) {
    333 	REQUIRE(IRS_CONTEXT_VALID(context));
    334 
    335 	return (context->dnsconf);
    336 }
    337