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