Home | History | Annotate | Line # | Download | only in named
      1 /*	$NetBSD: transportconf.c,v 1.4 2026/01/29 18:36:27 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 	CHECK(dns_name_fromtext(name, &namesrc, dns_rootname,  \
     40 				DNS_NAME_DOWNCASE, &namebuf));
     41 
     42 #define parse_transport_option(map, transport, name, setter)      \
     43 	{                                                         \
     44 		const cfg_obj_t *obj = NULL;                      \
     45 		cfg_map_get(map, name, &obj);                     \
     46 		if (obj != NULL) {                                \
     47 			setter(transport, cfg_obj_asstring(obj)); \
     48 		}                                                 \
     49 	}
     50 
     51 #define parse_transport_tls_versions(map, transport, name, setter)                \
     52 	{                                                                         \
     53 		const cfg_obj_t *obj = NULL;                                      \
     54 		cfg_map_get(map, name, &obj);                                     \
     55 		if (obj != NULL) {                                                \
     56 			{                                                         \
     57 				uint32_t tls_protos = 0;                          \
     58 				const cfg_listelt_t *proto = NULL;                \
     59 				INSIST(obj != NULL);                              \
     60 				for (proto = cfg_list_first(obj); proto != 0;     \
     61 				     proto = cfg_list_next(proto))                \
     62 				{                                                 \
     63 					const cfg_obj_t *tls_proto_obj =          \
     64 						cfg_listelt_value(proto);         \
     65 					const char *tls_sver =                    \
     66 						cfg_obj_asstring(                 \
     67 							tls_proto_obj);           \
     68 					const isc_tls_protocol_version_t ver =    \
     69 						isc_tls_protocol_name_to_version( \
     70 							tls_sver);                \
     71 					INSIST(ver !=                             \
     72 					       ISC_TLS_PROTO_VER_UNDEFINED);      \
     73 					INSIST(isc_tls_protocol_supported(        \
     74 						ver));                            \
     75 					tls_protos |= ver;                        \
     76 				}                                                 \
     77 				if (tls_protos != 0) {                            \
     78 					setter(transport, tls_protos);            \
     79 				}                                                 \
     80 			}                                                         \
     81 		}                                                                 \
     82 	}
     83 
     84 #define parse_transport_bool_option(map, transport, name, setter)  \
     85 	{                                                          \
     86 		const cfg_obj_t *obj = NULL;                       \
     87 		cfg_map_get(map, name, &obj);                      \
     88 		if (obj != NULL) {                                 \
     89 			setter(transport, cfg_obj_asboolean(obj)); \
     90 		}                                                  \
     91 	}
     92 
     93 static isc_result_t
     94 add_doh_transports(const cfg_obj_t *transportlist, dns_transport_list_t *list) {
     95 	const cfg_obj_t *doh = NULL;
     96 	const char *dohid = NULL;
     97 	isc_result_t result;
     98 
     99 	for (const cfg_listelt_t *element = cfg_list_first(transportlist);
    100 	     element != NULL; element = cfg_list_next(element))
    101 	{
    102 		dns_name_t dohname;
    103 		dns_transport_t *transport;
    104 
    105 		doh = cfg_listelt_value(element);
    106 		dohid = cfg_obj_asstring(cfg_map_getname(doh));
    107 
    108 		create_name(dohid, &dohname);
    109 
    110 		transport = dns_transport_new(&dohname, DNS_TRANSPORT_HTTP,
    111 					      list);
    112 
    113 		dns_transport_set_tlsname(transport, dohid);
    114 		parse_transport_option(doh, transport, "key-file",
    115 				       dns_transport_set_keyfile);
    116 		parse_transport_option(doh, transport, "cert-file",
    117 				       dns_transport_set_certfile);
    118 		parse_transport_tls_versions(doh, transport, "protocols",
    119 					     dns_transport_set_tls_versions);
    120 		parse_transport_option(doh, transport, "ciphers",
    121 				       dns_transport_set_ciphers);
    122 		parse_transport_option(doh, transport, "cipher-suites",
    123 				       dns_transport_set_cipher_suites);
    124 		parse_transport_bool_option(
    125 			doh, transport, "prefer-server-ciphers",
    126 			dns_transport_set_prefer_server_ciphers);
    127 		parse_transport_option(doh, transport, "ca-file",
    128 				       dns_transport_set_cafile);
    129 		parse_transport_option(doh, transport, "remote-hostname",
    130 				       dns_transport_set_remote_hostname);
    131 	}
    132 
    133 	return ISC_R_SUCCESS;
    134 cleanup:
    135 	cfg_obj_log(doh, named_g_lctx, ISC_LOG_ERROR,
    136 		    "configuring DoH '%s': %s", dohid,
    137 		    isc_result_totext(result));
    138 
    139 	return result;
    140 }
    141 
    142 static isc_result_t
    143 add_tls_transports(const cfg_obj_t *transportlist, dns_transport_list_t *list) {
    144 	const cfg_obj_t *tls = NULL;
    145 	const char *tlsid = NULL;
    146 	isc_result_t result;
    147 
    148 	for (const cfg_listelt_t *element = cfg_list_first(transportlist);
    149 	     element != NULL; element = cfg_list_next(element))
    150 	{
    151 		dns_name_t tlsname;
    152 		dns_transport_t *transport;
    153 
    154 		tls = cfg_listelt_value(element);
    155 		tlsid = cfg_obj_asstring(cfg_map_getname(tls));
    156 
    157 		if (!strcmp(tlsid, "ephemeral")) {
    158 			CHECK(ISC_R_UNEXPECTEDTOKEN);
    159 		}
    160 
    161 		create_name(tlsid, &tlsname);
    162 
    163 		transport = dns_transport_new(&tlsname, DNS_TRANSPORT_TLS,
    164 					      list);
    165 
    166 		dns_transport_set_tlsname(transport, tlsid);
    167 		parse_transport_option(tls, transport, "key-file",
    168 				       dns_transport_set_keyfile);
    169 		parse_transport_option(tls, transport, "cert-file",
    170 				       dns_transport_set_certfile);
    171 		parse_transport_tls_versions(tls, transport, "protocols",
    172 					     dns_transport_set_tls_versions);
    173 		parse_transport_option(tls, transport, "ciphers",
    174 				       dns_transport_set_ciphers);
    175 		parse_transport_option(tls, transport, "cipher-suites",
    176 				       dns_transport_set_cipher_suites);
    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 cleanup:
    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 static isc_result_t
    196 transport_list_fromconfig(const cfg_obj_t *config, dns_transport_list_t *list) {
    197 	const cfg_obj_t *obj = NULL;
    198 	isc_result_t result = ISC_R_SUCCESS;
    199 
    200 	if (result == ISC_R_SUCCESS &&
    201 	    cfg_map_get(config, "tls", &obj) == ISC_R_SUCCESS)
    202 	{
    203 		result = add_tls_transports(obj, list);
    204 		obj = NULL;
    205 	}
    206 
    207 	if (result == ISC_R_SUCCESS &&
    208 	    cfg_map_get(config, "doh", &obj) == ISC_R_SUCCESS)
    209 	{
    210 		result = add_doh_transports(obj, list);
    211 		obj = NULL;
    212 	}
    213 
    214 	return result;
    215 }
    216 
    217 static void
    218 transport_list_add_ephemeral(dns_transport_list_t *list) {
    219 	isc_result_t result;
    220 	dns_name_t tlsname;
    221 	dns_transport_t *transport;
    222 
    223 	create_name("ephemeral", &tlsname);
    224 
    225 	transport = dns_transport_new(&tlsname, DNS_TRANSPORT_TLS, list);
    226 	dns_transport_set_tlsname(transport, "ephemeral");
    227 
    228 	return;
    229 cleanup:
    230 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
    231 }
    232 
    233 isc_result_t
    234 named_transports_fromconfig(const cfg_obj_t *config, const cfg_obj_t *vconfig,
    235 			    isc_mem_t *mctx, dns_transport_list_t **listp) {
    236 	isc_result_t result;
    237 	dns_transport_list_t *list = dns_transport_list_new(mctx);
    238 
    239 	REQUIRE(listp != NULL && *listp == NULL);
    240 
    241 	transport_list_add_ephemeral(list);
    242 
    243 	if (config != NULL) {
    244 		CHECK(transport_list_fromconfig(config, list));
    245 	}
    246 
    247 	if (vconfig != NULL) {
    248 		config = cfg_tuple_get(vconfig, "options");
    249 		transport_list_fromconfig(config, list);
    250 	}
    251 
    252 	*listp = list;
    253 	return ISC_R_SUCCESS;
    254 cleanup:
    255 	dns_transport_list_detach(&list);
    256 	return result;
    257 }
    258