Home | History | Annotate | Line # | Download | only in irs
      1 /*	$NetBSD: dnsconf.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 /*! \file */
     17 
     18 #include <inttypes.h>
     19 #include <string.h>
     20 
     21 #include <isc/base64.h>
     22 #include <isc/buffer.h>
     23 #include <isc/file.h>
     24 #include <isc/mem.h>
     25 #include <isc/util.h>
     26 
     27 #include <dns/fixedname.h>
     28 #include <dns/name.h>
     29 #include <dns/rdata.h>
     30 #include <dns/rdatastruct.h>
     31 
     32 #include <isccfg/dnsconf.h>
     33 
     34 #include <irs/dnsconf.h>
     35 
     36 #define IRS_DNSCONF_MAGIC    ISC_MAGIC('D', 'c', 'f', 'g')
     37 #define IRS_DNSCONF_VALID(c) ISC_MAGIC_VALID(c, IRS_DNSCONF_MAGIC)
     38 
     39 /*!
     40  * configuration data structure
     41  */
     42 
     43 struct irs_dnsconf {
     44 	unsigned int magic;
     45 	isc_mem_t *mctx;
     46 	irs_dnsconf_dnskeylist_t trusted_keylist;
     47 };
     48 
     49 static isc_result_t
     50 configure_key(isc_mem_t *mctx, const cfg_obj_t *key, irs_dnsconf_t *conf,
     51 	      dns_rdataclass_t rdclass) {
     52 	isc_result_t result;
     53 	uint32_t flags, proto, alg;
     54 	dns_fixedname_t fkeyname;
     55 	dns_name_t *keyname_base = NULL, *keyname = NULL;
     56 	const char *keystr = NULL, *keynamestr = NULL;
     57 	unsigned char keydata[4096];
     58 	isc_buffer_t keydatabuf_base, *keydatabuf = NULL;
     59 	dns_rdata_dnskey_t keystruct;
     60 	unsigned char rrdata[4096];
     61 	isc_buffer_t rrdatabuf;
     62 	isc_region_t r;
     63 	isc_buffer_t namebuf;
     64 	irs_dnsconf_dnskey_t *keyent = NULL;
     65 
     66 	flags = cfg_obj_asuint32(cfg_tuple_get(key, "flags"));
     67 	proto = cfg_obj_asuint32(cfg_tuple_get(key, "protocol"));
     68 	alg = cfg_obj_asuint32(cfg_tuple_get(key, "algorithm"));
     69 	keynamestr = cfg_obj_asstring(cfg_tuple_get(key, "name"));
     70 
     71 	keystruct.common.rdclass = rdclass;
     72 	keystruct.common.rdtype = dns_rdatatype_dnskey;
     73 	keystruct.mctx = NULL;
     74 	ISC_LINK_INIT(&keystruct.common, link);
     75 
     76 	if (flags > 0xffff) {
     77 		return (ISC_R_RANGE);
     78 	}
     79 	if (proto > 0xff) {
     80 		return (ISC_R_RANGE);
     81 	}
     82 	if (alg > 0xff) {
     83 		return (ISC_R_RANGE);
     84 	}
     85 	keystruct.flags = (uint16_t)flags;
     86 	keystruct.protocol = (uint8_t)proto;
     87 	keystruct.algorithm = (uint8_t)alg;
     88 
     89 	isc_buffer_init(&keydatabuf_base, keydata, sizeof(keydata));
     90 	isc_buffer_init(&rrdatabuf, rrdata, sizeof(rrdata));
     91 
     92 	/* Configure key value */
     93 	keystr = cfg_obj_asstring(cfg_tuple_get(key, "key"));
     94 	result = isc_base64_decodestring(keystr, &keydatabuf_base);
     95 	if (result != ISC_R_SUCCESS) {
     96 		return (result);
     97 	}
     98 	isc_buffer_usedregion(&keydatabuf_base, &r);
     99 	keystruct.datalen = r.length;
    100 	keystruct.data = r.base;
    101 
    102 	result = dns_rdata_fromstruct(NULL, keystruct.common.rdclass,
    103 				      keystruct.common.rdtype, &keystruct,
    104 				      &rrdatabuf);
    105 	if (result != ISC_R_SUCCESS) {
    106 		return (result);
    107 	}
    108 	isc_buffer_usedregion(&rrdatabuf, &r);
    109 	isc_buffer_allocate(mctx, &keydatabuf, r.length);
    110 	result = isc_buffer_copyregion(keydatabuf, &r);
    111 	if (result != ISC_R_SUCCESS) {
    112 		goto cleanup;
    113 	}
    114 
    115 	/* Configure key name */
    116 	keyname_base = dns_fixedname_initname(&fkeyname);
    117 	isc_buffer_constinit(&namebuf, keynamestr, strlen(keynamestr));
    118 	isc_buffer_add(&namebuf, strlen(keynamestr));
    119 	result = dns_name_fromtext(keyname_base, &namebuf, dns_rootname, 0,
    120 				   NULL);
    121 	if (result != ISC_R_SUCCESS) {
    122 		return (result);
    123 	}
    124 	keyname = isc_mem_get(mctx, sizeof(*keyname));
    125 	dns_name_init(keyname, NULL);
    126 	dns_name_dup(keyname_base, mctx, keyname);
    127 
    128 	/* Add the key data to the list */
    129 	keyent = isc_mem_get(mctx, sizeof(*keyent));
    130 	keyent->keyname = keyname;
    131 	keyent->keydatabuf = keydatabuf;
    132 
    133 	ISC_LIST_APPEND(conf->trusted_keylist, keyent, link);
    134 
    135 cleanup:
    136 	if (keydatabuf != NULL) {
    137 		isc_buffer_free(&keydatabuf);
    138 	}
    139 	if (keyname != NULL) {
    140 		isc_mem_put(mctx, keyname, sizeof(*keyname));
    141 	}
    142 
    143 	return (result);
    144 }
    145 
    146 static isc_result_t
    147 configure_keygroup(irs_dnsconf_t *conf, const cfg_obj_t *keys,
    148 		   dns_rdataclass_t rdclass) {
    149 	isc_result_t result;
    150 	const cfg_obj_t *key, *keylist;
    151 	const cfg_listelt_t *element, *element2;
    152 	isc_mem_t *mctx = conf->mctx;
    153 
    154 	for (element = cfg_list_first(keys); element != NULL;
    155 	     element = cfg_list_next(element))
    156 	{
    157 		keylist = cfg_listelt_value(element);
    158 		for (element2 = cfg_list_first(keylist); element2 != NULL;
    159 		     element2 = cfg_list_next(element2))
    160 		{
    161 			key = cfg_listelt_value(element2);
    162 			result = configure_key(mctx, key, conf, rdclass);
    163 			if (result != ISC_R_SUCCESS) {
    164 				return (result);
    165 			}
    166 		}
    167 	}
    168 
    169 	return (ISC_R_SUCCESS);
    170 }
    171 
    172 static isc_result_t
    173 configure_dnsseckeys(irs_dnsconf_t *conf, cfg_obj_t *cfgobj,
    174 		     dns_rdataclass_t rdclass) {
    175 	isc_result_t result;
    176 	const cfg_obj_t *keys = NULL;
    177 
    178 	cfg_map_get(cfgobj, "trusted-keys", &keys);
    179 	if (keys == NULL) {
    180 		return (ISC_R_SUCCESS);
    181 	}
    182 
    183 	result = configure_keygroup(conf, keys, rdclass);
    184 	if (result != ISC_R_SUCCESS) {
    185 		return (result);
    186 	}
    187 
    188 	keys = NULL;
    189 	cfg_map_get(cfgobj, "trust-anchors", &keys);
    190 	if (keys == NULL) {
    191 		return (ISC_R_SUCCESS);
    192 	}
    193 
    194 	result = configure_keygroup(conf, keys, rdclass);
    195 	if (result != ISC_R_SUCCESS) {
    196 		return (result);
    197 	}
    198 
    199 	keys = NULL;
    200 	cfg_map_get(cfgobj, "managed-keys", &keys);
    201 	if (keys == NULL) {
    202 		return (ISC_R_SUCCESS);
    203 	}
    204 
    205 	result = configure_keygroup(conf, keys, rdclass);
    206 	if (result != ISC_R_SUCCESS) {
    207 		return (result);
    208 	}
    209 
    210 	return (ISC_R_SUCCESS);
    211 }
    212 
    213 isc_result_t
    214 irs_dnsconf_load(isc_mem_t *mctx, const char *filename, irs_dnsconf_t **confp) {
    215 	irs_dnsconf_t *conf;
    216 	cfg_parser_t *parser = NULL;
    217 	cfg_obj_t *cfgobj = NULL;
    218 	isc_result_t result = ISC_R_SUCCESS;
    219 
    220 	REQUIRE(confp != NULL && *confp == NULL);
    221 
    222 	conf = isc_mem_get(mctx, sizeof(*conf));
    223 
    224 	conf->mctx = mctx;
    225 	ISC_LIST_INIT(conf->trusted_keylist);
    226 
    227 	/*
    228 	 * If the specified file does not exist, we'll simply with an empty
    229 	 * configuration.
    230 	 */
    231 	if (!isc_file_exists(filename)) {
    232 		goto cleanup;
    233 	}
    234 
    235 	result = cfg_parser_create(mctx, NULL, &parser);
    236 	if (result != ISC_R_SUCCESS) {
    237 		goto cleanup;
    238 	}
    239 
    240 	result = cfg_parse_file(parser, filename, &cfg_type_dnsconf, &cfgobj);
    241 	if (result != ISC_R_SUCCESS) {
    242 		goto cleanup;
    243 	}
    244 
    245 	result = configure_dnsseckeys(conf, cfgobj, dns_rdataclass_in);
    246 
    247 cleanup:
    248 	if (parser != NULL) {
    249 		if (cfgobj != NULL) {
    250 			cfg_obj_destroy(parser, &cfgobj);
    251 		}
    252 		cfg_parser_destroy(&parser);
    253 	}
    254 
    255 	conf->magic = IRS_DNSCONF_MAGIC;
    256 
    257 	if (result == ISC_R_SUCCESS) {
    258 		*confp = conf;
    259 	} else {
    260 		irs_dnsconf_destroy(&conf);
    261 	}
    262 
    263 	return (result);
    264 }
    265 
    266 void
    267 irs_dnsconf_destroy(irs_dnsconf_t **confp) {
    268 	irs_dnsconf_t *conf;
    269 	irs_dnsconf_dnskey_t *keyent;
    270 
    271 	REQUIRE(confp != NULL);
    272 	conf = *confp;
    273 	*confp = NULL;
    274 	REQUIRE(IRS_DNSCONF_VALID(conf));
    275 
    276 	while ((keyent = ISC_LIST_HEAD(conf->trusted_keylist)) != NULL) {
    277 		ISC_LIST_UNLINK(conf->trusted_keylist, keyent, link);
    278 
    279 		isc_buffer_free(&keyent->keydatabuf);
    280 		dns_name_free(keyent->keyname, conf->mctx);
    281 		isc_mem_put(conf->mctx, keyent->keyname, sizeof(dns_name_t));
    282 		isc_mem_put(conf->mctx, keyent, sizeof(*keyent));
    283 	}
    284 
    285 	isc_mem_put(conf->mctx, conf, sizeof(*conf));
    286 }
    287 
    288 irs_dnsconf_dnskeylist_t *
    289 irs_dnsconf_gettrustedkeys(irs_dnsconf_t *conf) {
    290 	REQUIRE(IRS_DNSCONF_VALID(conf));
    291 
    292 	return (&conf->trusted_keylist);
    293 }
    294