mirror of
https://github.com/isc-projects/bind9.git
synced 2026-06-09 11:42:06 -04:00
Merge branch 'artem-tlsctx-caching' into 'main'
Add TLS context cache Closes #3067 See merge request isc-projects/bind9!5672
This commit is contained in:
commit
3addc36533
19 changed files with 664 additions and 106 deletions
6
CHANGES
6
CHANGES
|
|
@ -1,3 +1,9 @@
|
|||
5784. [func] Implement TLS-contexts reuse. Reusing the
|
||||
previously created TLS context objects can reduce
|
||||
initialisation time for some configurations and enables
|
||||
TLS session resumption for incoming zone transfers over
|
||||
TLS (XoT). [GL #3067]
|
||||
|
||||
5783. [func] named is now able to log TLS pre-master secrets for
|
||||
debugging purposes. This requires setting the
|
||||
SSLKEYLOGFILE environment variable appropriately.
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
#include <isc/magic.h>
|
||||
#include <isc/quota.h>
|
||||
#include <isc/sockaddr.h>
|
||||
#include <isc/tls.h>
|
||||
#include <isc/types.h>
|
||||
|
||||
#include <dns/acl.h>
|
||||
|
|
@ -109,6 +110,9 @@ struct named_server {
|
|||
dns_dtenv_t *dtenv; /*%< Dnstap environment */
|
||||
|
||||
char *lockfile;
|
||||
|
||||
isc_tlsctx_cache_t *tlsctx_server_cache;
|
||||
isc_tlsctx_cache_t *tlsctx_client_cache;
|
||||
};
|
||||
|
||||
#define NAMED_SERVER_MAGIC ISC_MAGIC('S', 'V', 'E', 'R')
|
||||
|
|
|
|||
|
|
@ -403,19 +403,21 @@ named_server_reload(isc_task_t *task, isc_event_t *event);
|
|||
|
||||
#ifdef HAVE_LIBNGHTTP2
|
||||
static isc_result_t
|
||||
listenelt_http(const cfg_obj_t *http, bool tls,
|
||||
const ns_listen_tls_params_t *tls_params, in_port_t port,
|
||||
listenelt_http(const cfg_obj_t *http, const uint16_t family, bool tls,
|
||||
const ns_listen_tls_params_t *tls_params,
|
||||
isc_tlsctx_cache_t *tlsctx_cache, in_port_t port,
|
||||
isc_mem_t *mctx, ns_listenelt_t **target);
|
||||
#endif
|
||||
|
||||
static isc_result_t
|
||||
listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config,
|
||||
cfg_aclconfctx_t *actx, isc_mem_t *mctx, uint16_t family,
|
||||
ns_listenelt_t **target);
|
||||
isc_tlsctx_cache_t *tlsctx_cache, ns_listenelt_t **target);
|
||||
|
||||
static isc_result_t
|
||||
listenlist_fromconfig(const cfg_obj_t *listenlist, const cfg_obj_t *config,
|
||||
cfg_aclconfctx_t *actx, isc_mem_t *mctx, uint16_t family,
|
||||
isc_tlsctx_cache_t *tlsctx_cache,
|
||||
ns_listenlist_t **target);
|
||||
|
||||
static isc_result_t
|
||||
|
|
@ -8422,6 +8424,22 @@ load_configuration(const char *filename, named_server_t *server,
|
|||
*/
|
||||
CHECK(bind9_check_namedconf(config, false, named_g_lctx, named_g_mctx));
|
||||
|
||||
/* Let's recreate the TLS context cache */
|
||||
if (server->tlsctx_server_cache != NULL) {
|
||||
isc_tlsctx_cache_detach(&server->tlsctx_server_cache);
|
||||
}
|
||||
|
||||
server->tlsctx_server_cache = isc_tlsctx_cache_new(named_g_mctx);
|
||||
|
||||
if (server->tlsctx_client_cache != NULL) {
|
||||
isc_tlsctx_cache_detach(&server->tlsctx_client_cache);
|
||||
}
|
||||
|
||||
server->tlsctx_client_cache = isc_tlsctx_cache_new(named_g_mctx);
|
||||
|
||||
dns_zonemgr_set_tlsctx_cache(server->zonemgr,
|
||||
server->tlsctx_client_cache);
|
||||
|
||||
/*
|
||||
* Fill in the maps array, used for resolving defaults.
|
||||
*/
|
||||
|
|
@ -8874,13 +8892,15 @@ load_configuration(const char *filename, named_server_t *server,
|
|||
if (clistenon != NULL) {
|
||||
CHECK(listenlist_fromconfig(
|
||||
clistenon, config, named_g_aclconfctx,
|
||||
named_g_mctx, AF_INET, &listenon));
|
||||
named_g_mctx, AF_INET,
|
||||
server->tlsctx_server_cache, &listenon));
|
||||
} else {
|
||||
/*
|
||||
* Not specified, use default.
|
||||
*/
|
||||
CHECK(ns_listenlist_default(named_g_mctx, listen_port,
|
||||
-1, true, &listenon));
|
||||
-1, true, AF_INET,
|
||||
&listenon));
|
||||
}
|
||||
if (listenon != NULL) {
|
||||
ns_interfacemgr_setlistenon4(server->interfacemgr,
|
||||
|
|
@ -8901,13 +8921,15 @@ load_configuration(const char *filename, named_server_t *server,
|
|||
if (clistenon != NULL) {
|
||||
CHECK(listenlist_fromconfig(
|
||||
clistenon, config, named_g_aclconfctx,
|
||||
named_g_mctx, AF_INET6, &listenon));
|
||||
named_g_mctx, AF_INET6,
|
||||
server->tlsctx_server_cache, &listenon));
|
||||
} else {
|
||||
/*
|
||||
* Not specified, use default.
|
||||
*/
|
||||
CHECK(ns_listenlist_default(named_g_mctx, listen_port,
|
||||
-1, true, &listenon));
|
||||
-1, true, AF_INET6,
|
||||
&listenon));
|
||||
}
|
||||
if (listenon != NULL) {
|
||||
ns_interfacemgr_setlistenon6(server->interfacemgr,
|
||||
|
|
@ -10167,6 +10189,10 @@ named_server_create(isc_mem_t *mctx, named_server_t **serverp) {
|
|||
server->dtenv = NULL;
|
||||
|
||||
server->magic = NAMED_SERVER_MAGIC;
|
||||
|
||||
server->tlsctx_server_cache = NULL;
|
||||
server->tlsctx_client_cache = NULL;
|
||||
|
||||
*serverp = server;
|
||||
}
|
||||
|
||||
|
|
@ -10221,6 +10247,14 @@ named_server_destroy(named_server_t **serverp) {
|
|||
INSIST(ISC_LIST_EMPTY(server->viewlist));
|
||||
INSIST(ISC_LIST_EMPTY(server->cachelist));
|
||||
|
||||
if (server->tlsctx_server_cache != NULL) {
|
||||
isc_tlsctx_cache_detach(&server->tlsctx_server_cache);
|
||||
}
|
||||
|
||||
if (server->tlsctx_client_cache != NULL) {
|
||||
isc_tlsctx_cache_detach(&server->tlsctx_client_cache);
|
||||
}
|
||||
|
||||
server->magic = 0;
|
||||
isc_mem_put(server->mctx, server, sizeof(*server));
|
||||
*serverp = NULL;
|
||||
|
|
@ -10860,6 +10894,7 @@ named_server_togglequerylog(named_server_t *server, isc_lex_t *lex) {
|
|||
static isc_result_t
|
||||
listenlist_fromconfig(const cfg_obj_t *listenlist, const cfg_obj_t *config,
|
||||
cfg_aclconfctx_t *actx, isc_mem_t *mctx, uint16_t family,
|
||||
isc_tlsctx_cache_t *tlsctx_cache,
|
||||
ns_listenlist_t **target) {
|
||||
isc_result_t result;
|
||||
const cfg_listelt_t *element;
|
||||
|
|
@ -10878,7 +10913,7 @@ listenlist_fromconfig(const cfg_obj_t *listenlist, const cfg_obj_t *config,
|
|||
ns_listenelt_t *delt = NULL;
|
||||
const cfg_obj_t *listener = cfg_listelt_value(element);
|
||||
result = listenelt_fromconfig(listener, config, actx, mctx,
|
||||
family, &delt);
|
||||
family, tlsctx_cache, &delt);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
|
@ -10925,6 +10960,7 @@ find_maplist(const cfg_obj_t *config, const char *listname, const char *name) {
|
|||
static isc_result_t
|
||||
listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config,
|
||||
cfg_aclconfctx_t *actx, isc_mem_t *mctx, uint16_t family,
|
||||
isc_tlsctx_cache_t *tlsctx_cache,
|
||||
ns_listenelt_t **target) {
|
||||
isc_result_t result;
|
||||
const cfg_obj_t *ltup = NULL;
|
||||
|
|
@ -10942,6 +10978,7 @@ listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config,
|
|||
ns_listenelt_t *delt = NULL;
|
||||
uint32_t tls_protos = 0;
|
||||
ns_listen_tls_params_t tls_params = { 0 };
|
||||
const char *tlsname = NULL;
|
||||
|
||||
REQUIRE(target != NULL && *target == NULL);
|
||||
|
||||
|
|
@ -10950,7 +10987,7 @@ listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config,
|
|||
|
||||
tlsobj = cfg_tuple_get(ltup, "tls");
|
||||
if (tlsobj != NULL && cfg_obj_isstring(tlsobj)) {
|
||||
const char *tlsname = cfg_obj_asstring(tlsobj);
|
||||
tlsname = cfg_obj_asstring(tlsobj);
|
||||
|
||||
if (strcasecmp(tlsname, "none") == 0) {
|
||||
no_tls = true;
|
||||
|
|
@ -11033,6 +11070,7 @@ listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config,
|
|||
}
|
||||
|
||||
tls_params = (ns_listen_tls_params_t){
|
||||
.name = tlsname,
|
||||
.key = key,
|
||||
.cert = cert,
|
||||
.protocols = tls_protos,
|
||||
|
|
@ -11126,14 +11164,15 @@ listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config,
|
|||
|
||||
#ifdef HAVE_LIBNGHTTP2
|
||||
if (http) {
|
||||
CHECK(listenelt_http(http_server, do_tls, &tls_params, port,
|
||||
mctx, &delt));
|
||||
CHECK(listenelt_http(http_server, family, do_tls, &tls_params,
|
||||
tlsctx_cache, port, mctx, &delt));
|
||||
}
|
||||
#endif /* HAVE_LIBNGHTTP2 */
|
||||
|
||||
if (!http) {
|
||||
CHECK(ns_listenelt_create(mctx, port, dscp, NULL, do_tls,
|
||||
&tls_params, &delt));
|
||||
CHECK(ns_listenelt_create(mctx, port, dscp, NULL, family,
|
||||
do_tls, &tls_params, tlsctx_cache,
|
||||
&delt));
|
||||
}
|
||||
|
||||
result = cfg_acl_fromconfig2(cfg_tuple_get(listener, "acl"), config,
|
||||
|
|
@ -11151,8 +11190,9 @@ cleanup:
|
|||
|
||||
#ifdef HAVE_LIBNGHTTP2
|
||||
static isc_result_t
|
||||
listenelt_http(const cfg_obj_t *http, bool tls,
|
||||
const ns_listen_tls_params_t *tls_params, in_port_t port,
|
||||
listenelt_http(const cfg_obj_t *http, const uint16_t family, bool tls,
|
||||
const ns_listen_tls_params_t *tls_params,
|
||||
isc_tlsctx_cache_t *tlsctx_cache, in_port_t port,
|
||||
isc_mem_t *mctx, ns_listenelt_t **target) {
|
||||
isc_result_t result = ISC_R_SUCCESS;
|
||||
ns_listenelt_t *delt = NULL;
|
||||
|
|
@ -11224,9 +11264,9 @@ listenelt_http(const cfg_obj_t *http, bool tls,
|
|||
quota = isc_mem_get(mctx, sizeof(isc_quota_t));
|
||||
isc_quota_init(quota, max_clients);
|
||||
}
|
||||
result = ns_listenelt_create_http(mctx, port, named_g_dscp, NULL, tls,
|
||||
tls_params, endpoints, len, quota,
|
||||
max_streams, &delt);
|
||||
result = ns_listenelt_create_http(
|
||||
mctx, port, named_g_dscp, NULL, family, tls, tls_params,
|
||||
tlsctx_cache, endpoints, len, quota, max_streams, &delt);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
goto error;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -108,6 +108,7 @@ add_doh_transports(const cfg_obj_t *transportlist, dns_transport_list_t *list) {
|
|||
transport = dns_transport_new(&dohname, DNS_TRANSPORT_HTTP,
|
||||
list);
|
||||
|
||||
dns_transport_set_tlsname(transport, dohid);
|
||||
parse_transport_option(doh, transport, "key-file",
|
||||
dns_transport_set_keyfile);
|
||||
parse_transport_option(doh, transport, "cert-file",
|
||||
|
|
@ -165,6 +166,7 @@ add_tls_transports(const cfg_obj_t *transportlist, dns_transport_list_t *list) {
|
|||
transport = dns_transport_new(&tlsname, DNS_TRANSPORT_TLS,
|
||||
list);
|
||||
|
||||
dns_transport_set_tlsname(transport, tlsid);
|
||||
parse_transport_option(tls, transport, "key-file",
|
||||
dns_transport_set_keyfile);
|
||||
parse_transport_option(tls, transport, "cert-file",
|
||||
|
|
@ -228,10 +230,12 @@ static void
|
|||
transport_list_add_ephemeral(dns_transport_list_t *list) {
|
||||
isc_result_t result;
|
||||
dns_name_t tlsname;
|
||||
dns_transport_t *transport;
|
||||
|
||||
create_name("ephemeral", &tlsname);
|
||||
|
||||
(void)dns_transport_new(&tlsname, DNS_TRANSPORT_TLS, list);
|
||||
transport = dns_transport_new(&tlsname, DNS_TRANSPORT_TLS, list);
|
||||
dns_transport_set_tlsname(transport, "ephemeral");
|
||||
|
||||
return;
|
||||
failure:
|
||||
|
|
|
|||
|
|
@ -54,6 +54,8 @@ dns_http_mode_t
|
|||
dns_transport_get_mode(dns_transport_t *transport);
|
||||
char *
|
||||
dns_transport_get_ciphers(dns_transport_t *transport);
|
||||
char *
|
||||
dns_transport_get_tlsname(dns_transport_t *transport);
|
||||
uint32_t
|
||||
dns_transport_get_tls_versions(const dns_transport_t *transport);
|
||||
bool
|
||||
|
|
@ -82,6 +84,9 @@ void
|
|||
dns_transport_set_mode(dns_transport_t *transport, dns_http_mode_t mode);
|
||||
void
|
||||
dns_transport_set_ciphers(dns_transport_t *transport, const char *ciphers);
|
||||
void
|
||||
dns_transport_set_tlsname(dns_transport_t *transport, const char *tlsname);
|
||||
|
||||
void
|
||||
dns_transport_set_tls_versions(dns_transport_t *transport,
|
||||
const uint32_t tls_versions);
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
***/
|
||||
|
||||
#include <isc/lang.h>
|
||||
#include <isc/tls.h>
|
||||
|
||||
#include <dns/transport.h>
|
||||
#include <dns/types.h>
|
||||
|
|
@ -49,7 +50,8 @@ dns_xfrin_create(dns_zone_t *zone, dns_rdatatype_t xfrtype,
|
|||
const isc_sockaddr_t *primaryaddr,
|
||||
const isc_sockaddr_t *sourceaddr, isc_dscp_t dscp,
|
||||
dns_tsigkey_t *tsigkey, dns_transport_t *transport,
|
||||
isc_mem_t *mctx, isc_nm_t *netmgr, dns_xfrindone_t done,
|
||||
isc_tlsctx_cache_t *tlsctx_cache, isc_mem_t *mctx,
|
||||
isc_nm_t *netmgr, dns_xfrindone_t done,
|
||||
dns_xfrin_ctx_t **xfrp);
|
||||
/*%<
|
||||
* Attempt to start an incoming zone transfer of 'zone'
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
#include <isc/formatcheck.h>
|
||||
#include <isc/lang.h>
|
||||
#include <isc/rwlock.h>
|
||||
#include <isc/tls.h>
|
||||
|
||||
#include <dns/catz.h>
|
||||
#include <dns/master.h>
|
||||
|
|
@ -2068,6 +2069,18 @@ dns_zonemgr_unreachabledel(dns_zonemgr_t *zmgr, isc_sockaddr_t *remote,
|
|||
*\li 'local' to be a valid sockaddr.
|
||||
*/
|
||||
|
||||
void
|
||||
dns_zonemgr_set_tlsctx_cache(dns_zonemgr_t *zmgr,
|
||||
isc_tlsctx_cache_t *tlsctx_cache);
|
||||
/*%<
|
||||
* Set the TLS client context cache used for zone transfers via
|
||||
* encrypted transports (e.g. XoT).
|
||||
*
|
||||
* Requires:
|
||||
*\li 'zmgr' is a valid zone manager.
|
||||
*\li 'tlsctx_cache' is a valid TLS context cache.
|
||||
*/
|
||||
|
||||
void
|
||||
dns_zone_forcereload(dns_zone_t *zone);
|
||||
/*%<
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ struct dns_transport {
|
|||
isc_mem_t *mctx;
|
||||
dns_transport_type_t type;
|
||||
struct {
|
||||
char *tlsname;
|
||||
char *certfile;
|
||||
char *keyfile;
|
||||
char *cafile;
|
||||
|
|
@ -269,6 +270,22 @@ dns_transport_set_ciphers(dns_transport_t *transport, const char *ciphers) {
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
dns_transport_set_tlsname(dns_transport_t *transport, const char *tlsname) {
|
||||
REQUIRE(VALID_TRANSPORT(transport));
|
||||
REQUIRE(transport->type == DNS_TRANSPORT_TLS ||
|
||||
transport->type == DNS_TRANSPORT_HTTP);
|
||||
|
||||
if (transport->tls.tlsname != NULL) {
|
||||
isc_mem_free(transport->mctx, transport->tls.tlsname);
|
||||
}
|
||||
|
||||
if (tlsname != NULL) {
|
||||
transport->tls.tlsname = isc_mem_strdup(transport->mctx,
|
||||
tlsname);
|
||||
}
|
||||
}
|
||||
|
||||
char *
|
||||
dns_transport_get_ciphers(dns_transport_t *transport) {
|
||||
REQUIRE(VALID_TRANSPORT(transport));
|
||||
|
|
@ -276,6 +293,13 @@ dns_transport_get_ciphers(dns_transport_t *transport) {
|
|||
return (transport->tls.ciphers);
|
||||
}
|
||||
|
||||
char *
|
||||
dns_transport_get_tlsname(dns_transport_t *transport) {
|
||||
REQUIRE(VALID_TRANSPORT(transport));
|
||||
|
||||
return (transport->tls.tlsname);
|
||||
}
|
||||
|
||||
void
|
||||
dns_transport_set_prefer_server_ciphers(dns_transport_t *transport,
|
||||
const bool prefer) {
|
||||
|
|
@ -330,6 +354,10 @@ transport_destroy(dns_transport_t *transport) {
|
|||
isc_mem_free(transport->mctx, transport->tls.ciphers);
|
||||
}
|
||||
|
||||
if (transport->tls.tlsname != NULL) {
|
||||
isc_mem_free(transport->mctx, transport->tls.tlsname);
|
||||
}
|
||||
|
||||
isc_mem_putanddetach(&transport->mctx, transport, sizeof(*transport));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -163,7 +163,6 @@ struct dns_xfrin_ctx {
|
|||
unsigned int sincetsig; /*%< recvd since the last TSIG */
|
||||
|
||||
dns_transport_t *transport;
|
||||
isc_tlsctx_t *tlsctx;
|
||||
|
||||
dns_xfrindone_t done;
|
||||
|
||||
|
|
@ -183,6 +182,8 @@ struct dns_xfrin_ctx {
|
|||
|
||||
dns_rdata_t firstsoa;
|
||||
unsigned char *firstsoa_data;
|
||||
|
||||
isc_tlsctx_cache_t *tlsctx_cache;
|
||||
};
|
||||
|
||||
#define XFRIN_MAGIC ISC_MAGIC('X', 'f', 'r', 'I')
|
||||
|
|
@ -199,7 +200,7 @@ xfrin_create(isc_mem_t *mctx, dns_zone_t *zone, dns_db_t *db, isc_nm_t *netmgr,
|
|||
dns_rdatatype_t reqtype, const isc_sockaddr_t *primaryaddr,
|
||||
const isc_sockaddr_t *sourceaddr, isc_dscp_t dscp,
|
||||
dns_tsigkey_t *tsigkey, dns_transport_t *transport,
|
||||
dns_xfrin_ctx_t **xfrp);
|
||||
isc_tlsctx_cache_t *tlsctx_cache, dns_xfrin_ctx_t **xfrp);
|
||||
|
||||
static isc_result_t
|
||||
axfr_init(dns_xfrin_ctx_t *xfr);
|
||||
|
|
@ -693,7 +694,8 @@ dns_xfrin_create(dns_zone_t *zone, dns_rdatatype_t xfrtype,
|
|||
const isc_sockaddr_t *primaryaddr,
|
||||
const isc_sockaddr_t *sourceaddr, isc_dscp_t dscp,
|
||||
dns_tsigkey_t *tsigkey, dns_transport_t *transport,
|
||||
isc_mem_t *mctx, isc_nm_t *netmgr, dns_xfrindone_t done,
|
||||
isc_tlsctx_cache_t *tlsctx_cache, isc_mem_t *mctx,
|
||||
isc_nm_t *netmgr, dns_xfrindone_t done,
|
||||
dns_xfrin_ctx_t **xfrp) {
|
||||
dns_name_t *zonename = dns_zone_getorigin(zone);
|
||||
dns_xfrin_ctx_t *xfr = NULL;
|
||||
|
|
@ -712,7 +714,7 @@ dns_xfrin_create(dns_zone_t *zone, dns_rdatatype_t xfrtype,
|
|||
|
||||
xfrin_create(mctx, zone, db, netmgr, zonename, dns_zone_getclass(zone),
|
||||
xfrtype, primaryaddr, sourceaddr, dscp, tsigkey, transport,
|
||||
&xfr);
|
||||
tlsctx_cache, &xfr);
|
||||
|
||||
if (db != NULL) {
|
||||
xfr->zone_had_db = true;
|
||||
|
|
@ -860,7 +862,7 @@ xfrin_create(isc_mem_t *mctx, dns_zone_t *zone, dns_db_t *db, isc_nm_t *netmgr,
|
|||
dns_rdatatype_t reqtype, const isc_sockaddr_t *primaryaddr,
|
||||
const isc_sockaddr_t *sourceaddr, isc_dscp_t dscp,
|
||||
dns_tsigkey_t *tsigkey, dns_transport_t *transport,
|
||||
dns_xfrin_ctx_t **xfrp) {
|
||||
isc_tlsctx_cache_t *tlsctx_cache, dns_xfrin_ctx_t **xfrp) {
|
||||
dns_xfrin_ctx_t *xfr = NULL;
|
||||
|
||||
xfr = isc_mem_get(mctx, sizeof(*xfr));
|
||||
|
|
@ -918,6 +920,8 @@ xfrin_create(isc_mem_t *mctx, dns_zone_t *zone, dns_db_t *db, isc_nm_t *netmgr,
|
|||
isc_buffer_init(&xfr->qbuffer, &xfr->qbuffer_data[2],
|
||||
sizeof(xfr->qbuffer_data) - 2);
|
||||
|
||||
isc_tlsctx_cache_attach(tlsctx_cache, &xfr->tlsctx_cache);
|
||||
|
||||
xfr->magic = XFRIN_MAGIC;
|
||||
|
||||
*xfrp = xfr;
|
||||
|
|
@ -928,6 +932,7 @@ xfrin_start(dns_xfrin_ctx_t *xfr) {
|
|||
isc_result_t result;
|
||||
dns_xfrin_ctx_t *connect_xfr = NULL;
|
||||
dns_transport_type_t transport_type = DNS_TRANSPORT_TCP;
|
||||
isc_tlsctx_t *tlsctx = NULL, *found = NULL;
|
||||
|
||||
(void)isc_refcount_increment0(&xfr->connects);
|
||||
dns_xfrin_attach(xfr, &connect_xfr);
|
||||
|
|
@ -948,32 +953,79 @@ xfrin_start(dns_xfrin_ctx_t *xfr) {
|
|||
break;
|
||||
case DNS_TRANSPORT_TLS: {
|
||||
uint32_t tls_versions;
|
||||
const char *ciphers;
|
||||
const char *ciphers = NULL;
|
||||
bool prefer_server_ciphers;
|
||||
CHECK(isc_tlsctx_createclient(&xfr->tlsctx));
|
||||
if (xfr->transport != NULL) {
|
||||
const uint16_t family = isc_sockaddr_pf(&xfr->primaryaddr) ==
|
||||
PF_INET6
|
||||
? AF_INET6
|
||||
: AF_INET;
|
||||
const char *tlsname = NULL;
|
||||
|
||||
INSIST(xfr->transport != NULL);
|
||||
tlsname = dns_transport_get_tlsname(xfr->transport);
|
||||
INSIST(tlsname != NULL && *tlsname != '\0');
|
||||
|
||||
/*
|
||||
* Let's try to re-use the already created context. This way
|
||||
* we have a chance to resume the TLS session, bypassing the
|
||||
* full TLS handshake procedure, making establishing
|
||||
* subsequent TLS connections for XoT faster.
|
||||
*/
|
||||
result = isc_tlsctx_cache_find(xfr->tlsctx_cache, tlsname,
|
||||
isc_tlsctx_cache_tls, family,
|
||||
&tlsctx);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
/*
|
||||
* So, no context exists. Let's create one using the
|
||||
* parameters from the configuration file and try to
|
||||
* store it for further reuse.
|
||||
*/
|
||||
CHECK(isc_tlsctx_createclient(&tlsctx));
|
||||
tls_versions =
|
||||
dns_transport_get_tls_versions(xfr->transport);
|
||||
if (tls_versions != 0) {
|
||||
isc_tlsctx_set_protocols(xfr->tlsctx,
|
||||
tls_versions);
|
||||
isc_tlsctx_set_protocols(tlsctx, tls_versions);
|
||||
}
|
||||
ciphers = dns_transport_get_ciphers(xfr->transport);
|
||||
if (ciphers != NULL) {
|
||||
isc_tlsctx_set_cipherlist(xfr->tlsctx, ciphers);
|
||||
isc_tlsctx_set_cipherlist(tlsctx, ciphers);
|
||||
}
|
||||
|
||||
if (dns_transport_get_prefer_server_ciphers(
|
||||
xfr->transport, &prefer_server_ciphers))
|
||||
{
|
||||
isc_tlsctx_prefer_server_ciphers(
|
||||
xfr->tlsctx, prefer_server_ciphers);
|
||||
tlsctx, prefer_server_ciphers);
|
||||
}
|
||||
isc_tlsctx_enable_dot_client_alpn(tlsctx);
|
||||
|
||||
result = isc_tlsctx_cache_add(
|
||||
xfr->tlsctx_cache, tlsname,
|
||||
isc_tlsctx_cache_tls, family, tlsctx, &found);
|
||||
if (result == ISC_R_EXISTS) {
|
||||
/*
|
||||
* It seems the entry has just been created
|
||||
* from within another thread while we were
|
||||
* initialising ours. Although this is
|
||||
* unlikely, it could happen after
|
||||
* startup/re-initialisation. In such a case,
|
||||
* discard the new context and use the already
|
||||
* established one from now on.
|
||||
*
|
||||
* Such situation will not occur after the
|
||||
* initial 'warm-up', so it is not critical
|
||||
* performance-wise.
|
||||
*/
|
||||
INSIST(found != NULL);
|
||||
isc_tlsctx_free(&tlsctx);
|
||||
tlsctx = found;
|
||||
} else {
|
||||
INSIST(result == ISC_R_SUCCESS);
|
||||
}
|
||||
}
|
||||
isc_tlsctx_enable_dot_client_alpn(xfr->tlsctx);
|
||||
isc_nm_tlsdnsconnect(xfr->netmgr, &xfr->sourceaddr,
|
||||
&xfr->primaryaddr, xfrin_connect_done,
|
||||
connect_xfr, 30000, 0, xfr->tlsctx);
|
||||
connect_xfr, 30000, 0, tlsctx);
|
||||
} break;
|
||||
default:
|
||||
INSIST(0);
|
||||
|
|
@ -983,8 +1035,13 @@ xfrin_start(dns_xfrin_ctx_t *xfr) {
|
|||
return (ISC_R_SUCCESS);
|
||||
|
||||
failure:
|
||||
if (xfr->tlsctx != NULL) {
|
||||
isc_tlsctx_free(&xfr->tlsctx);
|
||||
/*
|
||||
* The 'found' context is being managed by the TLS context cache.
|
||||
* Thus, we should keep it as it is, as it will get destroyed
|
||||
* alongside the cache.
|
||||
*/
|
||||
if (tlsctx != NULL && found != tlsctx) {
|
||||
isc_tlsctx_free(&tlsctx);
|
||||
}
|
||||
isc_refcount_decrement0(&xfr->connects);
|
||||
dns_xfrin_detach(&connect_xfr);
|
||||
|
|
@ -1032,10 +1089,6 @@ xfrin_connect_done(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) {
|
|||
|
||||
isc_refcount_decrement0(&xfr->connects);
|
||||
|
||||
if (xfr->tlsctx != NULL) {
|
||||
isc_tlsctx_free(&xfr->tlsctx);
|
||||
}
|
||||
|
||||
if (atomic_load(&xfr->shuttingdown)) {
|
||||
result = ISC_R_SHUTTINGDOWN;
|
||||
}
|
||||
|
|
@ -1670,6 +1723,10 @@ xfrin_destroy(dns_xfrin_ctx_t *xfr) {
|
|||
isc_mem_free(xfr->mctx, xfr->firstsoa_data);
|
||||
}
|
||||
|
||||
if (xfr->tlsctx_cache != NULL) {
|
||||
isc_tlsctx_cache_detach(&xfr->tlsctx_cache);
|
||||
}
|
||||
|
||||
isc_mem_putanddetach(&xfr->mctx, xfr, sizeof(*xfr));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
#include <isc/taskpool.h>
|
||||
#include <isc/thread.h>
|
||||
#include <isc/timer.h>
|
||||
#include <isc/tls.h>
|
||||
#include <isc/util.h>
|
||||
|
||||
#include <dns/acl.h>
|
||||
|
|
@ -629,6 +630,8 @@ struct dns_zonemgr {
|
|||
struct dns_unreachable unreachable[UNREACH_CACHE_SIZE];
|
||||
|
||||
dns_keymgmt_t *keymgmt;
|
||||
|
||||
isc_tlsctx_cache_t *tlsctx_cache;
|
||||
};
|
||||
|
||||
/*%
|
||||
|
|
@ -18133,7 +18136,8 @@ got_transfer_quota(isc_task_t *task, isc_event_t *event) {
|
|||
}
|
||||
|
||||
CHECK(dns_xfrin_create(zone, xfrtype, &primaryaddr, &sourceaddr, dscp,
|
||||
zone->tsigkey, zone->transport, zone->mctx,
|
||||
zone->tsigkey, zone->transport,
|
||||
zone->zmgr->tlsctx_cache, zone->mctx,
|
||||
zone->zmgr->netmgr, zone_xfrdone, &zone->xfr));
|
||||
LOCK_ZONE(zone);
|
||||
if (xfrtype == dns_rdatatype_axfr) {
|
||||
|
|
@ -18831,6 +18835,8 @@ dns_zonemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
|
|||
|
||||
isc_mutex_init(&zmgr->iolock);
|
||||
|
||||
zmgr->tlsctx_cache = NULL;
|
||||
|
||||
zmgr->magic = ZONEMGR_MAGIC;
|
||||
|
||||
*zmgrp = zmgr;
|
||||
|
|
@ -19188,6 +19194,9 @@ zonemgr_free(dns_zonemgr_t *zmgr) {
|
|||
zonemgr_keymgmt_destroy(zmgr);
|
||||
|
||||
mctx = zmgr->mctx;
|
||||
if (zmgr->tlsctx_cache != NULL) {
|
||||
isc_tlsctx_cache_detach(&zmgr->tlsctx_cache);
|
||||
}
|
||||
isc_mem_put(zmgr->mctx, zmgr, sizeof(*zmgr));
|
||||
isc_mem_detach(&mctx);
|
||||
}
|
||||
|
|
@ -23627,3 +23636,20 @@ zone_nsecttl(dns_zone_t *zone) {
|
|||
|
||||
return (ISC_MIN(zone->minimum, zone->soattl));
|
||||
}
|
||||
|
||||
void
|
||||
dns_zonemgr_set_tlsctx_cache(dns_zonemgr_t *zmgr,
|
||||
isc_tlsctx_cache_t *tlsctx_cache) {
|
||||
REQUIRE(DNS_ZONEMGR_VALID(zmgr));
|
||||
REQUIRE(tlsctx_cache != NULL);
|
||||
|
||||
RWLOCK(&zmgr->rwlock, isc_rwlocktype_write);
|
||||
|
||||
if (zmgr->tlsctx_cache != NULL) {
|
||||
isc_tlsctx_cache_detach(&zmgr->tlsctx_cache);
|
||||
}
|
||||
|
||||
isc_tlsctx_cache_attach(tlsctx_cache, &zmgr->tlsctx_cache);
|
||||
|
||||
RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_write);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -158,7 +158,6 @@ isc_tlsctx_enable_http2client_alpn(isc_tlsctx_t *ctx);
|
|||
void
|
||||
isc_tlsctx_enable_http2server_alpn(isc_tlsctx_t *ctx);
|
||||
/*%<
|
||||
*
|
||||
* Enable HTTP/2 Application Layer Protocol Negotation for 'ctx'.
|
||||
*
|
||||
* Requires:
|
||||
|
|
@ -178,9 +177,118 @@ isc_tlsctx_enable_dot_client_alpn(isc_tlsctx_t *ctx);
|
|||
void
|
||||
isc_tlsctx_enable_dot_server_alpn(isc_tlsctx_t *ctx);
|
||||
/*%<
|
||||
*
|
||||
* Enable DoT Application Layer Protocol Negotation for 'ctx'.
|
||||
*
|
||||
* Requires:
|
||||
*\li 'ctx' is not NULL.
|
||||
*/
|
||||
|
||||
typedef struct isc_tlsctx_cache isc_tlsctx_cache_t;
|
||||
/*%<
|
||||
* The TLS context cache is an object which allows retrieving a
|
||||
* previously created TLS context based on the following tuple:
|
||||
*
|
||||
* 1. The name of a TLS entry, as defined in the configuration file;
|
||||
* 2. A transport type. Currently, only TLS (DoT) and HTTPS (DoH) are
|
||||
* supported;
|
||||
* 3. An IP address family (AF_INET or AF_INET6).
|
||||
*
|
||||
* There are multiple uses for this object:
|
||||
*
|
||||
* First, it allows reuse of client-side contexts during zone transfers.
|
||||
* That, in turn, allows use of session caches associated with these
|
||||
* contexts, which enables TLS session resumption, making establishment
|
||||
* of XoT connections faster and computationally cheaper.
|
||||
*
|
||||
* Second, it can be extended to be used as storage for TLS context related
|
||||
* data, as defined in 'tls' statements in the configuration file (for
|
||||
* example, CA-bundle intermediate certificate storage, client-side contexts
|
||||
* with pre-loaded certificates in a case of Mutual TLS, etc). This will
|
||||
* be used to implement Strict/Mutual TLS.
|
||||
*
|
||||
* Third, it avoids creating an excessive number of server-side TLS
|
||||
* contexts, which might help to reduce the number of contexts
|
||||
* created during server initialisation and reconfiguration.
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
isc_tlsctx_cache_none = 0,
|
||||
isc_tlsctx_cache_tls,
|
||||
isc_tlsctx_cache_https,
|
||||
isc_tlsctx_cache_count
|
||||
} isc_tlsctx_cache_transport_t;
|
||||
/*%< TLS context cache transport type values. */
|
||||
|
||||
isc_tlsctx_cache_t *
|
||||
isc_tlsctx_cache_new(isc_mem_t *mctx);
|
||||
/*%<
|
||||
* Create a new TLS context cache object.
|
||||
*
|
||||
* Requires:
|
||||
*\li 'mctx' is a valid memory context.
|
||||
*/
|
||||
|
||||
void
|
||||
isc_tlsctx_cache_attach(isc_tlsctx_cache_t *source,
|
||||
isc_tlsctx_cache_t **targetp);
|
||||
/*%<
|
||||
* Create a reference to the TLS context cache object.
|
||||
*
|
||||
* Requires:
|
||||
*\li 'source' is a valid TLS context cache object;
|
||||
*\li 'targetp' is a valid pointer to a pointer which must equal NULL.
|
||||
*/
|
||||
|
||||
void
|
||||
isc_tlsctx_cache_detach(isc_tlsctx_cache_t **pcache);
|
||||
/*%<
|
||||
* Remove a reference to the TLS context cache object.
|
||||
*
|
||||
* Requires:
|
||||
*\li 'pcache' is a valid pointer to a pointer which must point to a
|
||||
* valid TLS context cache object.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
isc_tlsctx_cache_add(isc_tlsctx_cache_t *cache, const char *name,
|
||||
const isc_tlsctx_cache_transport_t transport,
|
||||
const uint16_t family, isc_tlsctx_t *ctx,
|
||||
isc_tlsctx_t **pfound);
|
||||
/*%<
|
||||
*
|
||||
* Add a new TLS context to the TLS context cache. 'pfound' is an
|
||||
* optional pointer, which can be used to retrieve an already
|
||||
* existing TLS context object in a case it exists.
|
||||
*
|
||||
* Requires:
|
||||
*\li 'cache' is a valid pointer to a TLS context cache object;
|
||||
*\li 'name' is a valid pointer to a non-empty string;
|
||||
*\li 'transport' is a valid transport identifier (currently only
|
||||
* TLS/DoT and HTTPS/DoH are supported);
|
||||
*\li 'family' - either 'AF_INET' or 'AF_INET6';
|
||||
*\li 'ctx' - a valid pointer to a valid TLS context object.
|
||||
*
|
||||
* Returns:
|
||||
*\li #ISC_R_EXISTS - node of the same key already exists;
|
||||
*\li #ISC_R_SUCCESS - the new entry has been added successfully.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
isc_tlsctx_cache_find(isc_tlsctx_cache_t *cache, const char *name,
|
||||
const isc_tlsctx_cache_transport_t transport,
|
||||
const uint16_t family, isc_tlsctx_t **pctx);
|
||||
/*%<
|
||||
* Look up a TLS context in the TLS context cache.
|
||||
*
|
||||
* Requires:
|
||||
*\li 'cache' is a valid pointer to a TLS context cache object;
|
||||
*\li 'name' is a valid pointer to a non empty string;
|
||||
*\li 'transport' - a valid transport identifier (currently only
|
||||
* TLS/DoT and HTTPS/DoH are supported;
|
||||
*\li 'family' - either 'AF_INET' or 'AF_INET6';
|
||||
*\li 'pctx' - a valid pointer to a non-NULL pointer.
|
||||
*
|
||||
* Returns:
|
||||
*\li #ISC_R_SUCCESS - the context has been found;
|
||||
*\li #ISC_R_NOTFOUND - the context has not been found.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -2454,7 +2454,6 @@ isc_nm_listenhttp(isc_nm_t *mgr, isc_sockaddr_t *iface, int backlog,
|
|||
isc_nm_http_endpoints_attach(eps, &sock->h2.listener_endpoints);
|
||||
|
||||
if (ctx != NULL) {
|
||||
isc_tlsctx_enable_http2server_alpn(ctx);
|
||||
result = isc_nm_listentls(mgr, iface, httplisten_acceptcb, sock,
|
||||
sizeof(isc_nm_http_session_t),
|
||||
backlog, quota, ctx, &sock->outer);
|
||||
|
|
|
|||
|
|
@ -494,8 +494,6 @@ isc_nm_listentlsdns(isc_nm_t *mgr, isc_sockaddr_t *iface,
|
|||
sock->tid = 0;
|
||||
sock->fd = -1;
|
||||
|
||||
isc_tlsctx_enable_dot_server_alpn(sslctx);
|
||||
|
||||
#if !HAVE_SO_REUSEPORT_LB
|
||||
fd = isc__nm_tlsdns_lb_socket(iface->type.sa.sa_family);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -332,6 +332,7 @@ nm_setup(void **state) {
|
|||
|
||||
server_tlsctx = NULL;
|
||||
isc_tlsctx_createserver(NULL, NULL, &server_tlsctx);
|
||||
isc_tlsctx_enable_http2server_alpn(server_tlsctx);
|
||||
client_tlsctx = NULL;
|
||||
isc_tlsctx_createclient(&client_tlsctx);
|
||||
isc_tlsctx_enable_http2client_alpn(client_tlsctx);
|
||||
|
|
|
|||
202
lib/isc/tls.c
202
lib/isc/tls.c
|
|
@ -12,6 +12,7 @@
|
|||
#include <inttypes.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#if HAVE_LIBNGHTTP2
|
||||
#include <nghttp2/nghttp2.h>
|
||||
#endif /* HAVE_LIBNGHTTP2 */
|
||||
|
|
@ -27,10 +28,14 @@
|
|||
#include <openssl/rsa.h>
|
||||
|
||||
#include <isc/atomic.h>
|
||||
#include <isc/ht.h>
|
||||
#include <isc/log.h>
|
||||
#include <isc/magic.h>
|
||||
#include <isc/mutex.h>
|
||||
#include <isc/mutexblock.h>
|
||||
#include <isc/once.h>
|
||||
#include <isc/refcount.h>
|
||||
#include <isc/rwlock.h>
|
||||
#include <isc/thread.h>
|
||||
#include <isc/tls.h>
|
||||
#include <isc/util.h>
|
||||
|
|
@ -885,3 +890,200 @@ isc_tlsctx_enable_dot_server_alpn(isc_tlsctx_t *tls) {
|
|||
SSL_CTX_set_alpn_select_cb(tls, dot_alpn_select_proto_cb, NULL);
|
||||
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
|
||||
}
|
||||
|
||||
#define TLSCTX_CACHE_MAGIC ISC_MAGIC('T', 'l', 'S', 'c')
|
||||
#define VALID_TLSCTX_CACHE(t) ISC_MAGIC_VALID(t, TLSCTX_CACHE_MAGIC)
|
||||
|
||||
typedef struct isc_tlsctx_cache_entry {
|
||||
/*
|
||||
* We need a TLS context entry for each transport on both IPv4 and
|
||||
* IPv6 in order to avoid cluttering a context-specific
|
||||
* session-resumption cache.
|
||||
*/
|
||||
isc_tlsctx_t *ctx[isc_tlsctx_cache_count - 1][2];
|
||||
/*
|
||||
* TODO: add a certificate store for an intermediate certificates
|
||||
* from a CA-bundle file. One is enough for all the contexts defined
|
||||
* above. We will need that for validation.
|
||||
*
|
||||
* X509_STORE *ca_bundle_store; // TODO: define the utilities to
|
||||
* operate on these ones
|
||||
*/
|
||||
} isc_tlsctx_cache_entry_t;
|
||||
|
||||
struct isc_tlsctx_cache {
|
||||
uint32_t magic;
|
||||
isc_refcount_t references;
|
||||
isc_mem_t *mctx;
|
||||
|
||||
isc_rwlock_t rwlock;
|
||||
isc_ht_t *data;
|
||||
};
|
||||
|
||||
isc_tlsctx_cache_t *
|
||||
isc_tlsctx_cache_new(isc_mem_t *mctx) {
|
||||
isc_tlsctx_cache_t *nc;
|
||||
|
||||
nc = isc_mem_get(mctx, sizeof(*nc));
|
||||
|
||||
*nc = (isc_tlsctx_cache_t){ .magic = TLSCTX_CACHE_MAGIC };
|
||||
isc_refcount_init(&nc->references, 1);
|
||||
isc_mem_attach(mctx, &nc->mctx);
|
||||
|
||||
RUNTIME_CHECK(isc_ht_init(&nc->data, mctx, 5) == ISC_R_SUCCESS);
|
||||
isc_rwlock_init(&nc->rwlock, 0, 0);
|
||||
|
||||
return (nc);
|
||||
}
|
||||
|
||||
void
|
||||
isc_tlsctx_cache_attach(isc_tlsctx_cache_t *source,
|
||||
isc_tlsctx_cache_t **targetp) {
|
||||
REQUIRE(VALID_TLSCTX_CACHE(source));
|
||||
REQUIRE(targetp != NULL && *targetp == NULL);
|
||||
|
||||
isc_refcount_increment(&source->references);
|
||||
|
||||
*targetp = source;
|
||||
}
|
||||
|
||||
static void
|
||||
tlsctx_cache_entry_destroy(isc_mem_t *mctx, isc_tlsctx_cache_entry_t *entry) {
|
||||
size_t i, k;
|
||||
|
||||
for (i = 0; i < (isc_tlsctx_cache_count - 1); i++) {
|
||||
for (k = 0; k < 2; k++) {
|
||||
if (entry->ctx[i][k] != NULL) {
|
||||
isc_tlsctx_free(&entry->ctx[i][k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
isc_mem_put(mctx, entry, sizeof(*entry));
|
||||
}
|
||||
|
||||
void
|
||||
isc_tlsctx_cache_detach(isc_tlsctx_cache_t **pcache) {
|
||||
isc_tlsctx_cache_t *cache;
|
||||
isc_ht_iter_t *it = NULL;
|
||||
isc_result_t result;
|
||||
REQUIRE(pcache != NULL);
|
||||
cache = *pcache;
|
||||
REQUIRE(VALID_TLSCTX_CACHE(cache));
|
||||
|
||||
if (isc_refcount_decrement(&cache->references) > 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
RUNTIME_CHECK(isc_ht_iter_create(cache->data, &it) == ISC_R_SUCCESS);
|
||||
for (result = isc_ht_iter_first(it); result == ISC_R_SUCCESS;
|
||||
result = isc_ht_iter_delcurrent_next(it))
|
||||
{
|
||||
isc_tlsctx_cache_entry_t *entry = NULL;
|
||||
isc_ht_iter_current(it, (void **)&entry);
|
||||
tlsctx_cache_entry_destroy(cache->mctx, entry);
|
||||
}
|
||||
isc_ht_iter_destroy(&it);
|
||||
isc_ht_destroy(&cache->data);
|
||||
|
||||
isc_rwlock_destroy(&cache->rwlock);
|
||||
cache->magic = 0;
|
||||
isc_mem_putanddetach(&cache->mctx, cache, sizeof(*cache));
|
||||
*pcache = NULL;
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
isc_tlsctx_cache_add(isc_tlsctx_cache_t *cache, const char *name,
|
||||
const isc_tlsctx_cache_transport_t transport,
|
||||
const uint16_t family, isc_tlsctx_t *ctx,
|
||||
isc_tlsctx_t **pfound) {
|
||||
isc_result_t result = ISC_R_FAILURE;
|
||||
size_t name_len, tr_offset;
|
||||
isc_tlsctx_cache_entry_t *entry = NULL;
|
||||
bool ipv6;
|
||||
|
||||
REQUIRE(VALID_TLSCTX_CACHE(cache));
|
||||
REQUIRE(name != NULL && *name != '\0');
|
||||
REQUIRE(transport > isc_tlsctx_cache_none &&
|
||||
transport < isc_tlsctx_cache_count);
|
||||
REQUIRE(family == AF_INET || family == AF_INET6);
|
||||
REQUIRE(ctx != NULL);
|
||||
|
||||
tr_offset = (transport - 1);
|
||||
ipv6 = (family == AF_INET6);
|
||||
|
||||
RWLOCK(&cache->rwlock, isc_rwlocktype_write);
|
||||
|
||||
name_len = strlen(name);
|
||||
result = isc_ht_find(cache->data, (const uint8_t *)name, name_len,
|
||||
(void **)&entry);
|
||||
if (result == ISC_R_SUCCESS && entry->ctx[tr_offset][ipv6] != NULL) {
|
||||
/* The entry exists. */
|
||||
if (pfound != NULL) {
|
||||
INSIST(*pfound == NULL);
|
||||
*pfound = entry->ctx[tr_offset][ipv6];
|
||||
}
|
||||
result = ISC_R_EXISTS;
|
||||
} else if (result == ISC_R_SUCCESS &&
|
||||
entry->ctx[tr_offset][ipv6] == NULL) {
|
||||
/*
|
||||
* The hast table entry exists, but is not filled for this
|
||||
* particular transport/IP type combination.
|
||||
*/
|
||||
entry->ctx[tr_offset][ipv6] = ctx;
|
||||
result = ISC_R_SUCCESS;
|
||||
} else {
|
||||
/*
|
||||
* The hash table entry does not exist, let's create one.
|
||||
*/
|
||||
INSIST(result != ISC_R_SUCCESS);
|
||||
entry = isc_mem_get(cache->mctx, sizeof(*entry));
|
||||
/* Oracle/Red Hat Linux, GCC bug #53119 */
|
||||
memset(entry, 0, sizeof(*entry));
|
||||
entry->ctx[tr_offset][ipv6] = ctx;
|
||||
RUNTIME_CHECK(isc_ht_add(cache->data, (const uint8_t *)name,
|
||||
name_len,
|
||||
(void *)entry) == ISC_R_SUCCESS);
|
||||
result = ISC_R_SUCCESS;
|
||||
}
|
||||
|
||||
RWUNLOCK(&cache->rwlock, isc_rwlocktype_write);
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
isc_tlsctx_cache_find(isc_tlsctx_cache_t *cache, const char *name,
|
||||
const isc_tlsctx_cache_transport_t transport,
|
||||
const uint16_t family, isc_tlsctx_t **pctx) {
|
||||
isc_result_t result = ISC_R_FAILURE;
|
||||
size_t tr_offset;
|
||||
isc_tlsctx_cache_entry_t *entry = NULL;
|
||||
bool ipv6;
|
||||
|
||||
REQUIRE(VALID_TLSCTX_CACHE(cache));
|
||||
REQUIRE(name != NULL && *name != '\0');
|
||||
REQUIRE(transport > isc_tlsctx_cache_none &&
|
||||
transport < isc_tlsctx_cache_count);
|
||||
REQUIRE(family == AF_INET || family == AF_INET6);
|
||||
REQUIRE(pctx != NULL && *pctx == NULL);
|
||||
|
||||
tr_offset = (transport - 1);
|
||||
ipv6 = (family == AF_INET6);
|
||||
|
||||
RWLOCK(&cache->rwlock, isc_rwlocktype_read);
|
||||
|
||||
result = isc_ht_find(cache->data, (const uint8_t *)name, strlen(name),
|
||||
(void **)&entry);
|
||||
if (result == ISC_R_SUCCESS && entry->ctx[tr_offset][ipv6] != NULL) {
|
||||
*pctx = entry->ctx[tr_offset][ipv6];
|
||||
} else if (result == ISC_R_SUCCESS &&
|
||||
entry->ctx[tr_offset][ipv6] == NULL) {
|
||||
result = ISC_R_NOTFOUND;
|
||||
} else {
|
||||
INSIST(result != ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
RWUNLOCK(&cache->rwlock, isc_rwlocktype_read);
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,15 +40,16 @@ typedef struct ns_listenlist ns_listenlist_t;
|
|||
|
||||
struct ns_listenelt {
|
||||
isc_mem_t *mctx;
|
||||
in_port_t port;
|
||||
bool is_http;
|
||||
isc_dscp_t dscp; /* -1 = not set, 0..63 */
|
||||
in_port_t port;
|
||||
bool is_http;
|
||||
isc_dscp_t dscp; /* -1 = not set, 0..63 */
|
||||
dns_acl_t *acl;
|
||||
isc_tlsctx_t *sslctx;
|
||||
char **http_endpoints;
|
||||
size_t http_endpoints_number;
|
||||
isc_quota_t *http_quota;
|
||||
uint32_t max_concurrent_streams;
|
||||
isc_tlsctx_t *sslctx;
|
||||
isc_tlsctx_cache_t *sslctx_cache;
|
||||
char **http_endpoints;
|
||||
size_t http_endpoints_number;
|
||||
isc_quota_t *http_quota;
|
||||
uint32_t max_concurrent_streams;
|
||||
ISC_LINK(ns_listenelt_t) link;
|
||||
};
|
||||
|
||||
|
|
@ -59,6 +60,7 @@ struct ns_listenlist {
|
|||
};
|
||||
|
||||
typedef struct ns_listen_tls_params {
|
||||
const char *name;
|
||||
const char *key;
|
||||
const char *cert;
|
||||
uint32_t protocols;
|
||||
|
|
@ -76,24 +78,25 @@ typedef struct ns_listen_tls_params {
|
|||
|
||||
isc_result_t
|
||||
ns_listenelt_create(isc_mem_t *mctx, in_port_t port, isc_dscp_t dscp,
|
||||
dns_acl_t *acl, bool tls,
|
||||
dns_acl_t *acl, const uint16_t family, bool tls,
|
||||
const ns_listen_tls_params_t *tls_params,
|
||||
ns_listenelt_t **target);
|
||||
isc_tlsctx_cache_t *tlsctx_cache, ns_listenelt_t **target);
|
||||
/*%<
|
||||
* Create a listen-on list element.
|
||||
*
|
||||
* Requires:
|
||||
* \li 'targetp' is a valid pointer to a pointer containing 'NULL';
|
||||
* \li 'tls_params' is a valid, non-'NULL' pointer if 'tls' equals 'true'.
|
||||
* \li 'tlsctx_cache' is a valid, non-'NULL' pointer if 'tls' equals 'true'.
|
||||
*/
|
||||
|
||||
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,
|
||||
dns_acl_t *acl, const uint16_t family, 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);
|
||||
isc_tlsctx_cache_t *tlsctx_cache, char **endpoints,
|
||||
size_t nendpoints, isc_quota_t *quota,
|
||||
const uint32_t max_streams, ns_listenelt_t **target);
|
||||
/*%<
|
||||
* Create a listen-on list element for HTTP(S).
|
||||
*/
|
||||
|
|
@ -124,7 +127,8 @@ ns_listenlist_detach(ns_listenlist_t **listp);
|
|||
|
||||
isc_result_t
|
||||
ns_listenlist_default(isc_mem_t *mctx, in_port_t port, isc_dscp_t dscp,
|
||||
bool enabled, ns_listenlist_t **target);
|
||||
bool enabled, const uint16_t family,
|
||||
ns_listenlist_t **target);
|
||||
/*%<
|
||||
* Create a listen-on list with default contents, matching
|
||||
* all addresses with port 'port' (if 'enabled' is true),
|
||||
|
|
|
|||
|
|
@ -24,50 +24,92 @@
|
|||
static void
|
||||
destroy(ns_listenlist_t *list);
|
||||
|
||||
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) {
|
||||
static isc_result_t
|
||||
listenelt_create(isc_mem_t *mctx, in_port_t port, isc_dscp_t dscp,
|
||||
dns_acl_t *acl, const uint16_t family, const bool is_http,
|
||||
bool tls, const ns_listen_tls_params_t *tls_params,
|
||||
isc_tlsctx_cache_t *tlsctx_cache, ns_listenelt_t **target) {
|
||||
ns_listenelt_t *elt = NULL;
|
||||
isc_result_t result = ISC_R_SUCCESS;
|
||||
isc_tlsctx_t *sslctx = NULL;
|
||||
|
||||
REQUIRE(target != NULL && *target == NULL);
|
||||
REQUIRE(!tls || tls_params != NULL);
|
||||
REQUIRE(!tls || (tls_params != NULL && tlsctx_cache != NULL));
|
||||
|
||||
if (tls) {
|
||||
result = isc_tlsctx_createserver(tls_params->key,
|
||||
tls_params->cert, &sslctx);
|
||||
const isc_tlsctx_cache_transport_t transport =
|
||||
is_http ? isc_tlsctx_cache_https : isc_tlsctx_cache_tls;
|
||||
|
||||
/*
|
||||
* Let's try to reuse the existing context from the cache in
|
||||
* order to avoid excessive TLS contexts creation.
|
||||
*/
|
||||
result = isc_tlsctx_cache_find(tlsctx_cache, tls_params->name,
|
||||
transport, family, &sslctx);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
return (result);
|
||||
}
|
||||
/*
|
||||
* The lookup failed, let's try to create a new context
|
||||
* and store it within the cache.
|
||||
*/
|
||||
INSIST(tls_params->name != NULL &&
|
||||
*tls_params->name != '\0');
|
||||
|
||||
if (tls_params->protocols != 0) {
|
||||
isc_tlsctx_set_protocols(sslctx, tls_params->protocols);
|
||||
}
|
||||
|
||||
if (tls_params->dhparam_file != NULL) {
|
||||
if (!isc_tlsctx_load_dhparams(sslctx,
|
||||
tls_params->dhparam_file))
|
||||
{
|
||||
isc_tlsctx_free(&sslctx);
|
||||
return (ISC_R_FAILURE);
|
||||
result = isc_tlsctx_createserver(
|
||||
tls_params->key, tls_params->cert, &sslctx);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
return (result);
|
||||
}
|
||||
}
|
||||
|
||||
if (tls_params->ciphers != NULL) {
|
||||
isc_tlsctx_set_cipherlist(sslctx, tls_params->ciphers);
|
||||
}
|
||||
if (tls_params->protocols != 0) {
|
||||
isc_tlsctx_set_protocols(sslctx,
|
||||
tls_params->protocols);
|
||||
}
|
||||
|
||||
if (tls_params->prefer_server_ciphers_set) {
|
||||
isc_tlsctx_prefer_server_ciphers(
|
||||
sslctx, tls_params->prefer_server_ciphers);
|
||||
}
|
||||
if (tls_params->dhparam_file != NULL) {
|
||||
if (!isc_tlsctx_load_dhparams(
|
||||
sslctx, tls_params->dhparam_file)) {
|
||||
isc_tlsctx_free(&sslctx);
|
||||
return (ISC_R_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
if (tls_params->session_tickets_set) {
|
||||
isc_tlsctx_session_tickets(sslctx,
|
||||
tls_params->session_tickets);
|
||||
if (tls_params->ciphers != NULL) {
|
||||
isc_tlsctx_set_cipherlist(sslctx,
|
||||
tls_params->ciphers);
|
||||
}
|
||||
|
||||
if (tls_params->prefer_server_ciphers_set) {
|
||||
isc_tlsctx_prefer_server_ciphers(
|
||||
sslctx,
|
||||
tls_params->prefer_server_ciphers);
|
||||
}
|
||||
|
||||
if (tls_params->session_tickets_set) {
|
||||
isc_tlsctx_session_tickets(
|
||||
sslctx, tls_params->session_tickets);
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBNGHTTP2
|
||||
if (is_http) {
|
||||
isc_tlsctx_enable_http2server_alpn(sslctx);
|
||||
}
|
||||
#endif /* HAVE_LIBNGHTTP2 */
|
||||
|
||||
if (!is_http) {
|
||||
isc_tlsctx_enable_dot_server_alpn(sslctx);
|
||||
}
|
||||
|
||||
/*
|
||||
* The storing in the cache should not fail because the
|
||||
* (re)initialisation happens from within a single
|
||||
* thread.
|
||||
*/
|
||||
RUNTIME_CHECK(isc_tlsctx_cache_add(
|
||||
tlsctx_cache, tls_params->name,
|
||||
transport, family, sslctx,
|
||||
NULL) == ISC_R_SUCCESS);
|
||||
} else {
|
||||
INSIST(sslctx != NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -79,6 +121,10 @@ ns_listenelt_create(isc_mem_t *mctx, in_port_t port, isc_dscp_t dscp,
|
|||
elt->dscp = dscp;
|
||||
elt->acl = acl;
|
||||
elt->sslctx = sslctx;
|
||||
elt->sslctx_cache = NULL;
|
||||
if (sslctx != NULL && tlsctx_cache != NULL) {
|
||||
isc_tlsctx_cache_attach(tlsctx_cache, &elt->sslctx_cache);
|
||||
}
|
||||
elt->http_endpoints = NULL;
|
||||
elt->http_endpoints_number = 0;
|
||||
elt->http_quota = NULL;
|
||||
|
|
@ -87,21 +133,30 @@ ns_listenelt_create(isc_mem_t *mctx, in_port_t port, isc_dscp_t dscp,
|
|||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
ns_listenelt_create(isc_mem_t *mctx, in_port_t port, isc_dscp_t dscp,
|
||||
dns_acl_t *acl, const uint16_t family, bool tls,
|
||||
const ns_listen_tls_params_t *tls_params,
|
||||
isc_tlsctx_cache_t *tlsctx_cache, ns_listenelt_t **target) {
|
||||
return listenelt_create(mctx, port, dscp, acl, family, false, tls,
|
||||
tls_params, tlsctx_cache, target);
|
||||
}
|
||||
|
||||
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,
|
||||
dns_acl_t *acl, const uint16_t family, 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) {
|
||||
isc_tlsctx_cache_t *tlsctx_cache, char **endpoints,
|
||||
size_t nendpoints, isc_quota_t *quota,
|
||||
const uint32_t max_streams, ns_listenelt_t **target) {
|
||||
isc_result_t result;
|
||||
|
||||
REQUIRE(target != NULL && *target == NULL);
|
||||
REQUIRE(endpoints != NULL && *endpoints != NULL);
|
||||
REQUIRE(nendpoints > 0);
|
||||
|
||||
result = ns_listenelt_create(mctx, http_port, dscp, acl, tls,
|
||||
tls_params, target);
|
||||
result = listenelt_create(mctx, http_port, dscp, acl, family, true, tls,
|
||||
tls_params, tlsctx_cache, target);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
(*target)->is_http = true;
|
||||
(*target)->http_endpoints = endpoints;
|
||||
|
|
@ -123,8 +178,11 @@ ns_listenelt_destroy(ns_listenelt_t *elt) {
|
|||
if (elt->acl != NULL) {
|
||||
dns_acl_detach(&elt->acl);
|
||||
}
|
||||
if (elt->sslctx != NULL) {
|
||||
isc_tlsctx_free(&elt->sslctx);
|
||||
|
||||
elt->sslctx = NULL; /* this one is going to be destroyed alongside the
|
||||
sslctx_cache */
|
||||
if (elt->sslctx_cache != NULL) {
|
||||
isc_tlsctx_cache_detach(&elt->sslctx_cache);
|
||||
}
|
||||
if (elt->http_endpoints != NULL) {
|
||||
size_t i;
|
||||
|
|
@ -179,7 +237,8 @@ ns_listenlist_detach(ns_listenlist_t **listp) {
|
|||
|
||||
isc_result_t
|
||||
ns_listenlist_default(isc_mem_t *mctx, in_port_t port, isc_dscp_t dscp,
|
||||
bool enabled, ns_listenlist_t **target) {
|
||||
bool enabled, const uint16_t family,
|
||||
ns_listenlist_t **target) {
|
||||
isc_result_t result;
|
||||
dns_acl_t *acl = NULL;
|
||||
ns_listenelt_t *elt = NULL;
|
||||
|
|
@ -195,7 +254,8 @@ ns_listenlist_default(isc_mem_t *mctx, in_port_t port, isc_dscp_t dscp,
|
|||
goto cleanup;
|
||||
}
|
||||
|
||||
result = ns_listenelt_create(mctx, port, dscp, acl, false, NULL, &elt);
|
||||
result = ns_listenelt_create(mctx, port, dscp, acl, family, false, NULL,
|
||||
NULL, &elt);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
goto cleanup_acl;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ ns_listenlist_default_test(void **state) {
|
|||
|
||||
UNUSED(state);
|
||||
|
||||
result = ns_listenlist_default(mctx, port, -1, false, &list);
|
||||
result = ns_listenlist_default(mctx, port, -1, false, AF_INET, &list);
|
||||
assert_int_equal(result, ISC_R_SUCCESS);
|
||||
assert_non_null(list);
|
||||
|
||||
|
|
@ -98,7 +98,7 @@ ns_listenlist_default_test(void **state) {
|
|||
|
||||
ns_listenlist_detach(&list);
|
||||
|
||||
result = ns_listenlist_default(mctx, port, -1, true, &list);
|
||||
result = ns_listenlist_default(mctx, port, -1, true, AF_INET, &list);
|
||||
assert_int_equal(result, ISC_R_SUCCESS);
|
||||
|
||||
assert_false(ISC_LIST_EMPTY(list->elts));
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@
|
|||
|
||||
/*! \file */
|
||||
|
||||
#include "nstest.h"
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
|
@ -50,6 +49,8 @@
|
|||
#include <ns/interfacemgr.h>
|
||||
#include <ns/server.h>
|
||||
|
||||
#include "nstest.h"
|
||||
|
||||
isc_mem_t *mctx = NULL;
|
||||
isc_log_t *lctx = NULL;
|
||||
isc_nm_t *netmgr = NULL;
|
||||
|
|
@ -236,7 +237,7 @@ create_managers(void) {
|
|||
dispatchmgr, maintask, NULL, ncpus, false,
|
||||
&interfacemgr));
|
||||
|
||||
CHECK(ns_listenlist_default(mctx, port, -1, true, &listenon));
|
||||
CHECK(ns_listenlist_default(mctx, port, -1, true, AF_INET, &listenon));
|
||||
ns_interfacemgr_setlistenon4(interfacemgr, listenon);
|
||||
ns_listenlist_detach(&listenon);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue