transportconf.c revision 1.1.1.1 1 /* $NetBSD: transportconf.c,v 1.1.1.1 2024/02/21 21:54:33 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
20 #include <isc/buffer.h>
21 #include <isc/string.h>
22 #include <isc/util.h>
23
24 #include <dns/name.h>
25 #include <dns/transport.h>
26
27 #include <isccfg/cfg.h>
28
29 #include <named/log.h>
30 #include <named/transportconf.h>
31
32 #define create_name(id, name) \
33 isc_buffer_t namesrc, namebuf; \
34 char namedata[DNS_NAME_FORMATSIZE + 1]; \
35 dns_name_init(name, NULL); \
36 isc_buffer_constinit(&namesrc, id, strlen(id)); \
37 isc_buffer_add(&namesrc, strlen(id)); \
38 isc_buffer_init(&namebuf, namedata, sizeof(namedata)); \
39 result = (dns_name_fromtext(name, &namesrc, dns_rootname, \
40 DNS_NAME_DOWNCASE, &namebuf)); \
41 if (result != ISC_R_SUCCESS) { \
42 goto failure; \
43 }
44
45 #define parse_transport_option(map, transport, name, setter) \
46 { \
47 const cfg_obj_t *obj = NULL; \
48 cfg_map_get(map, name, &obj); \
49 if (obj != NULL) { \
50 setter(transport, cfg_obj_asstring(obj)); \
51 } \
52 }
53
54 #define parse_transport_tls_versions(map, transport, name, setter) \
55 { \
56 const cfg_obj_t *obj = NULL; \
57 cfg_map_get(map, name, &obj); \
58 if (obj != NULL) { \
59 { \
60 uint32_t tls_protos = 0; \
61 const cfg_listelt_t *proto = NULL; \
62 INSIST(obj != NULL); \
63 for (proto = cfg_list_first(obj); proto != 0; \
64 proto = cfg_list_next(proto)) \
65 { \
66 const cfg_obj_t *tls_proto_obj = \
67 cfg_listelt_value(proto); \
68 const char *tls_sver = \
69 cfg_obj_asstring( \
70 tls_proto_obj); \
71 const isc_tls_protocol_version_t ver = \
72 isc_tls_protocol_name_to_version( \
73 tls_sver); \
74 INSIST(ver != \
75 ISC_TLS_PROTO_VER_UNDEFINED); \
76 INSIST(isc_tls_protocol_supported( \
77 ver)); \
78 tls_protos |= ver; \
79 } \
80 if (tls_protos != 0) { \
81 setter(transport, tls_protos); \
82 } \
83 } \
84 } \
85 }
86
87 #define parse_transport_bool_option(map, transport, name, setter) \
88 { \
89 const cfg_obj_t *obj = NULL; \
90 cfg_map_get(map, name, &obj); \
91 if (obj != NULL) { \
92 setter(transport, cfg_obj_asboolean(obj)); \
93 } \
94 }
95
96 static isc_result_t
97 add_doh_transports(const cfg_obj_t *transportlist, dns_transport_list_t *list) {
98 const cfg_obj_t *doh = NULL;
99 const char *dohid = NULL;
100 isc_result_t result;
101
102 for (const cfg_listelt_t *element = cfg_list_first(transportlist);
103 element != NULL; element = cfg_list_next(element))
104 {
105 dns_name_t dohname;
106 dns_transport_t *transport;
107
108 doh = cfg_listelt_value(element);
109 dohid = cfg_obj_asstring(cfg_map_getname(doh));
110
111 create_name(dohid, &dohname);
112
113 transport = dns_transport_new(&dohname, DNS_TRANSPORT_HTTP,
114 list);
115
116 dns_transport_set_tlsname(transport, dohid);
117 parse_transport_option(doh, transport, "key-file",
118 dns_transport_set_keyfile);
119 parse_transport_option(doh, transport, "cert-file",
120 dns_transport_set_certfile);
121 parse_transport_tls_versions(doh, transport, "protocols",
122 dns_transport_set_tls_versions);
123 parse_transport_option(doh, transport, "ciphers",
124 dns_transport_set_ciphers);
125 parse_transport_bool_option(
126 doh, transport, "prefer-server-ciphers",
127 dns_transport_set_prefer_server_ciphers)
128 parse_transport_option(doh, transport, "ca-file",
129 dns_transport_set_cafile);
130 parse_transport_option(doh, transport, "remote-hostname",
131 dns_transport_set_remote_hostname);
132 }
133
134 return (ISC_R_SUCCESS);
135 failure:
136 cfg_obj_log(doh, named_g_lctx, ISC_LOG_ERROR,
137 "configuring DoH '%s': %s", dohid,
138 isc_result_totext(result));
139
140 return (result);
141 }
142
143 static isc_result_t
144 add_tls_transports(const cfg_obj_t *transportlist, dns_transport_list_t *list) {
145 const cfg_obj_t *tls = NULL;
146 const char *tlsid = NULL;
147 isc_result_t result;
148
149 for (const cfg_listelt_t *element = cfg_list_first(transportlist);
150 element != NULL; element = cfg_list_next(element))
151 {
152 dns_name_t tlsname;
153 dns_transport_t *transport;
154
155 tls = cfg_listelt_value(element);
156 tlsid = cfg_obj_asstring(cfg_map_getname(tls));
157
158 if (!strcmp(tlsid, "ephemeral")) {
159 result = ISC_R_UNEXPECTEDTOKEN;
160 goto failure;
161 }
162
163 create_name(tlsid, &tlsname);
164
165 transport = dns_transport_new(&tlsname, DNS_TRANSPORT_TLS,
166 list);
167
168 dns_transport_set_tlsname(transport, tlsid);
169 parse_transport_option(tls, transport, "key-file",
170 dns_transport_set_keyfile);
171 parse_transport_option(tls, transport, "cert-file",
172 dns_transport_set_certfile);
173 parse_transport_tls_versions(tls, transport, "protocols",
174 dns_transport_set_tls_versions);
175 parse_transport_option(tls, transport, "ciphers",
176 dns_transport_set_ciphers);
177 parse_transport_bool_option(
178 tls, transport, "prefer-server-ciphers",
179 dns_transport_set_prefer_server_ciphers)
180 parse_transport_option(tls, transport, "ca-file",
181 dns_transport_set_cafile);
182 parse_transport_option(tls, transport, "remote-hostname",
183 dns_transport_set_remote_hostname);
184 }
185
186 return (ISC_R_SUCCESS);
187 failure:
188 cfg_obj_log(tls, named_g_lctx, ISC_LOG_ERROR,
189 "configuring tls '%s': %s", tlsid,
190 isc_result_totext(result));
191
192 return (result);
193 }
194
195 #define CHECK(f) \
196 if ((result = f) != ISC_R_SUCCESS) { \
197 goto failure; \
198 }
199
200 static isc_result_t
201 transport_list_fromconfig(const cfg_obj_t *config, dns_transport_list_t *list) {
202 const cfg_obj_t *obj = NULL;
203 isc_result_t result = ISC_R_SUCCESS;
204
205 if (result == ISC_R_SUCCESS &&
206 cfg_map_get(config, "tls", &obj) == ISC_R_SUCCESS)
207 {
208 result = add_tls_transports(obj, list);
209 obj = NULL;
210 }
211
212 if (result == ISC_R_SUCCESS &&
213 cfg_map_get(config, "doh", &obj) == ISC_R_SUCCESS)
214 {
215 result = add_doh_transports(obj, list);
216 obj = NULL;
217 }
218
219 return (result);
220 }
221
222 static void
223 transport_list_add_ephemeral(dns_transport_list_t *list) {
224 isc_result_t result;
225 dns_name_t tlsname;
226 dns_transport_t *transport;
227
228 create_name("ephemeral", &tlsname);
229
230 transport = dns_transport_new(&tlsname, DNS_TRANSPORT_TLS, list);
231 dns_transport_set_tlsname(transport, "ephemeral");
232
233 return;
234 failure:
235 RUNTIME_CHECK(result == ISC_R_SUCCESS);
236 }
237
238 isc_result_t
239 named_transports_fromconfig(const cfg_obj_t *config, const cfg_obj_t *vconfig,
240 isc_mem_t *mctx, dns_transport_list_t **listp) {
241 isc_result_t result;
242 dns_transport_list_t *list = dns_transport_list_new(mctx);
243
244 REQUIRE(listp != NULL && *listp == NULL);
245
246 transport_list_add_ephemeral(list);
247
248 if (config != NULL) {
249 result = transport_list_fromconfig(config, list);
250 if (result != ISC_R_SUCCESS) {
251 goto failure;
252 }
253 }
254
255 if (vconfig != NULL) {
256 config = cfg_tuple_get(vconfig, "options");
257 transport_list_fromconfig(config, list);
258 }
259
260 *listp = list;
261 return (ISC_R_SUCCESS);
262 failure:
263 dns_transport_list_detach(&list);
264 return (result);
265 }
266