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 <stdbool.h>
15
16 #include <isc/mem.h>
17 #include <isc/netmgr.h>
18 #include <isc/util.h>
19
20 #include <dns/acl.h>
21
22 #include <ns/listenlist.h>
23
24 static void
25 destroy(ns_listenlist_t *list);
26
27 isc_result_t
ns_listenelt_create(isc_mem_t * mctx,in_port_t port,isc_dscp_t dscp,dns_acl_t * acl,bool tls,const ns_listen_tls_params_t * tls_params,ns_listenelt_t ** target)28 ns_listenelt_create(isc_mem_t *mctx, in_port_t port, isc_dscp_t dscp,
29 dns_acl_t *acl, bool tls,
30 const ns_listen_tls_params_t *tls_params,
31 ns_listenelt_t **target) {
32 ns_listenelt_t *elt = NULL;
33 isc_result_t result = ISC_R_SUCCESS;
34 isc_tlsctx_t *sslctx = NULL;
35
36 REQUIRE(target != NULL && *target == NULL);
37 REQUIRE(!tls || tls_params != NULL);
38
39 if (tls) {
40 result = isc_tlsctx_createserver(tls_params->key,
41 tls_params->cert, &sslctx);
42 if (result != ISC_R_SUCCESS) {
43 return (result);
44 }
45
46 if (tls_params->protocols != 0) {
47 isc_tlsctx_set_protocols(sslctx, tls_params->protocols);
48 }
49
50 if (tls_params->dhparam_file != NULL) {
51 if (!isc_tlsctx_load_dhparams(sslctx,
52 tls_params->dhparam_file))
53 {
54 isc_tlsctx_free(&sslctx);
55 return (ISC_R_FAILURE);
56 }
57 }
58
59 if (tls_params->ciphers != NULL) {
60 isc_tlsctx_set_cipherlist(sslctx, tls_params->ciphers);
61 }
62
63 if (tls_params->prefer_server_ciphers_set) {
64 isc_tlsctx_prefer_server_ciphers(
65 sslctx, tls_params->prefer_server_ciphers);
66 }
67
68 if (tls_params->session_tickets_set) {
69 isc_tlsctx_session_tickets(sslctx,
70 tls_params->session_tickets);
71 }
72 }
73
74 elt = isc_mem_get(mctx, sizeof(*elt));
75 elt->mctx = mctx;
76 ISC_LINK_INIT(elt, link);
77 elt->port = port;
78 elt->is_http = false;
79 elt->dscp = dscp;
80 elt->acl = acl;
81 elt->sslctx = sslctx;
82 elt->http_endpoints = NULL;
83 elt->http_endpoints_number = 0;
84 elt->http_quota = NULL;
85
86 *target = elt;
87 return (ISC_R_SUCCESS);
88 }
89
90 isc_result_t
ns_listenelt_create_http(isc_mem_t * mctx,in_port_t http_port,isc_dscp_t dscp,dns_acl_t * acl,bool tls,const ns_listen_tls_params_t * tls_params,char ** endpoints,size_t nendpoints,isc_quota_t * quota,const uint32_t max_streams,ns_listenelt_t ** target)91 ns_listenelt_create_http(isc_mem_t *mctx, in_port_t http_port, isc_dscp_t dscp,
92 dns_acl_t *acl, bool tls,
93 const ns_listen_tls_params_t *tls_params,
94 char **endpoints, size_t nendpoints,
95 isc_quota_t *quota, const uint32_t max_streams,
96 ns_listenelt_t **target) {
97 isc_result_t result;
98
99 REQUIRE(target != NULL && *target == NULL);
100 REQUIRE(endpoints != NULL && *endpoints != NULL);
101 REQUIRE(nendpoints > 0);
102
103 result = ns_listenelt_create(mctx, http_port, dscp, acl, tls,
104 tls_params, target);
105 if (result == ISC_R_SUCCESS) {
106 (*target)->is_http = true;
107 (*target)->http_endpoints = endpoints;
108 (*target)->http_endpoints_number = nendpoints;
109 (*target)->http_quota = quota;
110 (*target)->max_concurrent_streams = max_streams;
111 } else {
112 size_t i;
113 for (i = 0; i < nendpoints; i++) {
114 isc_mem_free(mctx, endpoints[i]);
115 }
116 isc_mem_free(mctx, endpoints);
117 }
118 return (result);
119 }
120
121 void
ns_listenelt_destroy(ns_listenelt_t * elt)122 ns_listenelt_destroy(ns_listenelt_t *elt) {
123 if (elt->acl != NULL) {
124 dns_acl_detach(&elt->acl);
125 }
126 if (elt->sslctx != NULL) {
127 isc_tlsctx_free(&elt->sslctx);
128 }
129 if (elt->http_endpoints != NULL) {
130 size_t i;
131 INSIST(elt->http_endpoints_number > 0);
132 for (i = 0; i < elt->http_endpoints_number; i++) {
133 isc_mem_free(elt->mctx, elt->http_endpoints[i]);
134 }
135 isc_mem_free(elt->mctx, elt->http_endpoints);
136 }
137 isc_mem_put(elt->mctx, elt, sizeof(*elt));
138 }
139
140 isc_result_t
ns_listenlist_create(isc_mem_t * mctx,ns_listenlist_t ** target)141 ns_listenlist_create(isc_mem_t *mctx, ns_listenlist_t **target) {
142 ns_listenlist_t *list = NULL;
143 REQUIRE(target != NULL && *target == NULL);
144 list = isc_mem_get(mctx, sizeof(*list));
145 list->mctx = mctx;
146 list->refcount = 1;
147 ISC_LIST_INIT(list->elts);
148 *target = list;
149 return (ISC_R_SUCCESS);
150 }
151
152 static void
destroy(ns_listenlist_t * list)153 destroy(ns_listenlist_t *list) {
154 ns_listenelt_t *elt, *next;
155 for (elt = ISC_LIST_HEAD(list->elts); elt != NULL; elt = next) {
156 next = ISC_LIST_NEXT(elt, link);
157 ns_listenelt_destroy(elt);
158 }
159 isc_mem_put(list->mctx, list, sizeof(*list));
160 }
161
162 void
ns_listenlist_attach(ns_listenlist_t * source,ns_listenlist_t ** target)163 ns_listenlist_attach(ns_listenlist_t *source, ns_listenlist_t **target) {
164 INSIST(source->refcount > 0);
165 source->refcount++;
166 *target = source;
167 }
168
169 void
ns_listenlist_detach(ns_listenlist_t ** listp)170 ns_listenlist_detach(ns_listenlist_t **listp) {
171 ns_listenlist_t *list = *listp;
172 *listp = NULL;
173 INSIST(list->refcount > 0);
174 list->refcount--;
175 if (list->refcount == 0) {
176 destroy(list);
177 }
178 }
179
180 isc_result_t
ns_listenlist_default(isc_mem_t * mctx,in_port_t port,isc_dscp_t dscp,bool enabled,ns_listenlist_t ** target)181 ns_listenlist_default(isc_mem_t *mctx, in_port_t port, isc_dscp_t dscp,
182 bool enabled, ns_listenlist_t **target) {
183 isc_result_t result;
184 dns_acl_t *acl = NULL;
185 ns_listenelt_t *elt = NULL;
186 ns_listenlist_t *list = NULL;
187
188 REQUIRE(target != NULL && *target == NULL);
189 if (enabled) {
190 result = dns_acl_any(mctx, &acl);
191 } else {
192 result = dns_acl_none(mctx, &acl);
193 }
194 if (result != ISC_R_SUCCESS) {
195 goto cleanup;
196 }
197
198 result = ns_listenelt_create(mctx, port, dscp, acl, false, NULL, &elt);
199 if (result != ISC_R_SUCCESS) {
200 goto cleanup_acl;
201 }
202
203 result = ns_listenlist_create(mctx, &list);
204 if (result != ISC_R_SUCCESS) {
205 goto cleanup_listenelt;
206 }
207
208 ISC_LIST_APPEND(list->elts, elt, link);
209
210 *target = list;
211 return (ISC_R_SUCCESS);
212
213 cleanup_listenelt:
214 ns_listenelt_destroy(elt);
215 cleanup_acl:
216 dns_acl_detach(&acl);
217 cleanup:
218 return (result);
219 }
220