1 /*
2 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3 *
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
7 *
8 * See the COPYRIGHT file distributed with this work for additional
9 * information regarding copyright ownership.
10 */
11
12 /*! \file */
13
14 #include <inttypes.h>
15
16 #include <isc/buffer.h>
17 #include <isc/string.h>
18 #include <isc/util.h>
19
20 #include <dns/name.h>
21 #include <dns/transport.h>
22
23 #include <isccfg/cfg.h>
24
25 #include <named/log.h>
26 #include <named/transportconf.h>
27
28 #define create_name(id, name) \
29 isc_buffer_t namesrc, namebuf; \
30 char namedata[DNS_NAME_FORMATSIZE + 1]; \
31 dns_name_init(name, NULL); \
32 isc_buffer_constinit(&namesrc, id, strlen(id)); \
33 isc_buffer_add(&namesrc, strlen(id)); \
34 isc_buffer_init(&namebuf, namedata, sizeof(namedata)); \
35 result = (dns_name_fromtext(name, &namesrc, dns_rootname, \
36 DNS_NAME_DOWNCASE, &namebuf)); \
37 if (result != ISC_R_SUCCESS) { \
38 goto failure; \
39 }
40
41 #define parse_transport_option(map, transport, name, setter) \
42 { \
43 const cfg_obj_t *obj = NULL; \
44 cfg_map_get(map, name, &obj); \
45 if (obj != NULL) { \
46 setter(transport, cfg_obj_asstring(obj)); \
47 } \
48 }
49
50 static isc_result_t
add_doh_transports(const cfg_obj_t * transportlist,dns_transport_list_t * list)51 add_doh_transports(const cfg_obj_t *transportlist, dns_transport_list_t *list) {
52 const cfg_obj_t *doh = NULL;
53 const char *dohid = NULL;
54 isc_result_t result;
55
56 for (const cfg_listelt_t *element = cfg_list_first(transportlist);
57 element != NULL; element = cfg_list_next(element))
58 {
59 dns_name_t dohname;
60 dns_transport_t *transport;
61
62 doh = cfg_listelt_value(element);
63 dohid = cfg_obj_asstring(cfg_map_getname(doh));
64
65 create_name(dohid, &dohname);
66
67 transport = dns_transport_new(&dohname, DNS_TRANSPORT_HTTP,
68 list);
69
70 parse_transport_option(doh, transport, "key-file",
71 dns_transport_set_keyfile);
72 parse_transport_option(doh, transport, "cert-file",
73 dns_transport_set_certfile);
74 parse_transport_option(doh, transport, "ca-file",
75 dns_transport_set_cafile);
76 parse_transport_option(doh, transport, "hostname",
77 dns_transport_set_hostname);
78 }
79
80 return (ISC_R_SUCCESS);
81 failure:
82 cfg_obj_log(doh, named_g_lctx, ISC_LOG_ERROR,
83 "configuring DoH '%s': %s", dohid,
84 isc_result_totext(result));
85
86 return (result);
87 }
88
89 static isc_result_t
add_tls_transports(const cfg_obj_t * transportlist,dns_transport_list_t * list)90 add_tls_transports(const cfg_obj_t *transportlist, dns_transport_list_t *list) {
91 const cfg_obj_t *tls = NULL;
92 const char *tlsid = NULL;
93 isc_result_t result;
94
95 for (const cfg_listelt_t *element = cfg_list_first(transportlist);
96 element != NULL; element = cfg_list_next(element))
97 {
98 dns_name_t tlsname;
99 dns_transport_t *transport;
100
101 tls = cfg_listelt_value(element);
102 tlsid = cfg_obj_asstring(cfg_map_getname(tls));
103
104 if (!strcmp(tlsid, "ephemeral")) {
105 result = ISC_R_UNEXPECTEDTOKEN;
106 goto failure;
107 }
108
109 create_name(tlsid, &tlsname);
110
111 transport = dns_transport_new(&tlsname, DNS_TRANSPORT_TLS,
112 list);
113
114 parse_transport_option(tls, transport, "key-file",
115 dns_transport_set_keyfile);
116 parse_transport_option(tls, transport, "cert-file",
117 dns_transport_set_certfile);
118 parse_transport_option(tls, transport, "ca-file",
119 dns_transport_set_cafile);
120 parse_transport_option(tls, transport, "hostname",
121 dns_transport_set_hostname);
122 }
123
124 return (ISC_R_SUCCESS);
125 failure:
126 cfg_obj_log(tls, named_g_lctx, ISC_LOG_ERROR,
127 "configuring tls '%s': %s", tlsid,
128 isc_result_totext(result));
129
130 return (result);
131 }
132
133 #define CHECK(f) \
134 if ((result = f) != ISC_R_SUCCESS) { \
135 goto failure; \
136 }
137
138 static isc_result_t
transport_list_fromconfig(const cfg_obj_t * config,dns_transport_list_t * list)139 transport_list_fromconfig(const cfg_obj_t *config, dns_transport_list_t *list) {
140 const cfg_obj_t *obj = NULL;
141 isc_result_t result = ISC_R_SUCCESS;
142
143 if (result == ISC_R_SUCCESS &&
144 cfg_map_get(config, "tls", &obj) == ISC_R_SUCCESS)
145 {
146 result = add_tls_transports(obj, list);
147 obj = NULL;
148 }
149
150 if (result == ISC_R_SUCCESS &&
151 cfg_map_get(config, "doh", &obj) == ISC_R_SUCCESS)
152 {
153 result = add_doh_transports(obj, list);
154 obj = NULL;
155 }
156
157 return (result);
158 }
159
160 static void
transport_list_add_ephemeral(dns_transport_list_t * list)161 transport_list_add_ephemeral(dns_transport_list_t *list) {
162 isc_result_t result;
163 dns_name_t tlsname;
164
165 create_name("ephemeral", &tlsname);
166
167 (void)dns_transport_new(&tlsname, DNS_TRANSPORT_TLS, list);
168
169 return;
170 failure:
171 RUNTIME_CHECK(result == ISC_R_SUCCESS);
172 }
173
174 isc_result_t
named_transports_fromconfig(const cfg_obj_t * config,const cfg_obj_t * vconfig,isc_mem_t * mctx,dns_transport_list_t ** listp)175 named_transports_fromconfig(const cfg_obj_t *config, const cfg_obj_t *vconfig,
176 isc_mem_t *mctx, dns_transport_list_t **listp) {
177 isc_result_t result;
178 dns_transport_list_t *list = dns_transport_list_new(mctx);
179
180 REQUIRE(listp != NULL && *listp == NULL);
181
182 transport_list_add_ephemeral(list);
183
184 if (config != NULL) {
185 result = transport_list_fromconfig(config, list);
186 if (result != ISC_R_SUCCESS) {
187 goto failure;
188 }
189 }
190
191 if (vconfig != NULL) {
192 config = cfg_tuple_get(vconfig, "options");
193 transport_list_fromconfig(config, list);
194 }
195
196 *listp = list;
197 return (ISC_R_SUCCESS);
198 failure:
199 dns_transport_list_detach(&list);
200 return (result);
201 }
202