Home | History | Annotate | Line # | Download | only in named
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