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