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