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
configure_key(isc_mem_t * mctx,const cfg_obj_t * key,irs_dnsconf_t * conf,dns_rdataclass_t rdclass)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
configure_keygroup(irs_dnsconf_t * conf,const cfg_obj_t * keys,dns_rdataclass_t rdclass)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
configure_dnsseckeys(irs_dnsconf_t * conf,cfg_obj_t * cfgobj,dns_rdataclass_t rdclass)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
irs_dnsconf_load(isc_mem_t * mctx,const char * filename,irs_dnsconf_t ** confp)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
irs_dnsconf_destroy(irs_dnsconf_t ** confp)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 *
irs_dnsconf_gettrustedkeys(irs_dnsconf_t * conf)289 irs_dnsconf_gettrustedkeys(irs_dnsconf_t *conf) {
290 REQUIRE(IRS_DNSCONF_VALID(conf));
291
292 return (&conf->trusted_keylist);
293 }
294