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