diff --git a/lib/isc/include/isc/netmgr.h b/lib/isc/include/isc/netmgr.h index 0ae582a0b5..4651bbf4cf 100644 --- a/lib/isc/include/isc/netmgr.h +++ b/lib/isc/include/isc/netmgr.h @@ -109,6 +109,18 @@ isc_nmsocket_close(isc_nmsocket_t **sockp); * sockets with active handles, the socket will be closed. */ +void +isc_nmsocket_set_tlsctx(isc_nmsocket_t *listener, isc_tlsctx_t *tlsctx); +/*%< + * Asynchronously replace the TLS context within the listener socket object. + * The function is intended to be used during reconfiguration. + * + * Requires: + * \li 'listener' is a pointer to a valid network manager listener socket + object with TLS support; + * \li 'tlsctx' is a valid pointer to a TLS context object. + */ + #ifdef NETMGR_TRACE #define isc_nmhandle_attach(handle, dest) \ isc__nmhandle_attach(handle, dest, __FILE__, __LINE__, __func__) diff --git a/lib/isc/netmgr/http.c b/lib/isc/netmgr/http.c index 6684373a68..1d59ee3c30 100644 --- a/lib/isc/netmgr/http.c +++ b/lib/isc/netmgr/http.c @@ -2936,6 +2936,14 @@ isc__nm_http_verify_tls_peer_result_string(const isc_nmhandle_t *handle) { return (isc_nm_verify_tls_peer_result_string(session->handle)); } +void +isc__nm_http_set_tlsctx(isc_nmsocket_t *listener, isc_tlsctx_t *tlsctx) { + REQUIRE(VALID_NMSOCK(listener)); + REQUIRE(listener->type == isc_nm_httplistener); + + isc_nmsocket_set_tlsctx(listener->outer, tlsctx); +} + static const bool base64url_validation_table[256] = { false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, diff --git a/lib/isc/netmgr/netmgr-int.h b/lib/isc/netmgr/netmgr-int.h index a8a7e93ad4..9adb7e0084 100644 --- a/lib/isc/netmgr/netmgr-int.h +++ b/lib/isc/netmgr/netmgr-int.h @@ -328,6 +328,8 @@ typedef enum isc__netievent_type { netievent_task, + netievent_settlsctx, + /* * event type values higher than this will be treated * as high-priority events, which can be processed @@ -665,6 +667,38 @@ typedef struct isc__netievent { isc__nm_put_netievent(nm, ievent); \ } +typedef struct isc__netievent__tlsctx { + NETIEVENT__SOCKET; + isc_tlsctx_t *tlsctx; +} isc__netievent__tlsctx_t; + +#define NETIEVENT_SOCKET_TLSCTX_TYPE(type) \ + typedef isc__netievent__tlsctx_t isc__netievent_##type##_t; + +#define NETIEVENT_SOCKET_TLSCTX_DECL(type) \ + isc__netievent_##type##_t *isc__nm_get_netievent_##type( \ + isc_nm_t *nm, isc_nmsocket_t *sock, isc_tlsctx_t *tlsctx); \ + void isc__nm_put_netievent_##type(isc_nm_t *nm, \ + isc__netievent_##type##_t *ievent); + +#define NETIEVENT_SOCKET_TLSCTX_DEF(type) \ + isc__netievent_##type##_t *isc__nm_get_netievent_##type( \ + isc_nm_t *nm, isc_nmsocket_t *sock, isc_tlsctx_t *tlsctx) { \ + isc__netievent_##type##_t *ievent = \ + isc__nm_get_netievent(nm, netievent_##type); \ + isc__nmsocket_attach(sock, &ievent->sock); \ + isc_tlsctx_attach(tlsctx, &ievent->tlsctx); \ + \ + return (ievent); \ + } \ + \ + void isc__nm_put_netievent_##type(isc_nm_t *nm, \ + isc__netievent_##type##_t *ievent) { \ + isc_tlsctx_free(&ievent->tlsctx); \ + isc__nmsocket_detach(&ievent->sock); \ + isc__nm_put_netievent(nm, ievent); \ + } + typedef union { isc__netievent_t ni; isc__netievent__socket_t nis; @@ -672,6 +706,7 @@ typedef union { isc__netievent_udpsend_t nius; isc__netievent__socket_quota_t nisq; isc__netievent_tlsconnect_t nitc; + isc__netievent__tlsctx_t nitls; } isc__netievent_storage_t; /* @@ -930,6 +965,7 @@ struct isc_nmsocket { isc_tlsctx_t *ctx; isc_tlsctx_t **listener_tls_ctx; /*%< A context reference per worker */ + size_t n_listener_tls_ctx; isc_nmsocket_t *tlslistener; atomic_bool result_updated; enum { @@ -1608,6 +1644,9 @@ void isc__nm_async_tlsdnsshutdown(isc__networker_t *worker, isc__netievent_t *ev0); void isc__nm_async_tlsdnsread(isc__networker_t *worker, isc__netievent_t *ev0); +void +isc__nm_async_tlsdns_set_tlsctx(isc_nmsocket_t *listener, isc_tlsctx_t *tlsctx, + const int tid); /*%< * Callback handlers for asynchronous TLSDNS events. */ @@ -1684,6 +1723,10 @@ isc__nmhandle_tls_keepalive(isc_nmhandle_t *handle, bool value); * Set the keepalive value on the underlying TCP handle. */ +void +isc__nm_async_tls_set_tlsctx(isc_nmsocket_t *listener, isc_tlsctx_t *tlsctx, + const int tid); + void isc__nm_http_stoplistening(isc_nmsocket_t *sock); @@ -1769,8 +1812,14 @@ isc__nm_httpsession_attach(isc_nm_http_session_t *source, void isc__nm_httpsession_detach(isc_nm_http_session_t **sessionp); +void +isc__nm_http_set_tlsctx(isc_nmsocket_t *sock, isc_tlsctx_t *tlsctx); + #endif +void +isc__nm_async_settlsctx(isc__networker_t *worker, isc__netievent_t *ev0); + #define isc__nm_uverr2result(x) \ isc___nm_uverr2result(x, true, __FILE__, __LINE__, __func__) isc_result_t @@ -1963,6 +2012,8 @@ NETIEVENT_TYPE(stop); NETIEVENT_TASK_TYPE(task); +NETIEVENT_SOCKET_TLSCTX_TYPE(settlsctx); + /* Now declared the helper functions */ NETIEVENT_SOCKET_DECL(close); @@ -2030,6 +2081,8 @@ NETIEVENT_DECL(stop); NETIEVENT_TASK_DECL(task); +NETIEVENT_SOCKET_TLSCTX_DECL(settlsctx); + void isc__nm_udp_failed_read_cb(isc_nmsocket_t *sock, isc_result_t result); void diff --git a/lib/isc/netmgr/netmgr.c b/lib/isc/netmgr/netmgr.c index 66b77939c5..a73223942c 100644 --- a/lib/isc/netmgr/netmgr.c +++ b/lib/isc/netmgr/netmgr.c @@ -903,6 +903,7 @@ process_netievent(isc__networker_t *worker, isc__netievent_t *ievent) { NETIEVENT_CASE(httpsend); NETIEVENT_CASE(httpclose); #endif + NETIEVENT_CASE(settlsctx); NETIEVENT_CASE(connectcb); NETIEVENT_CASE(readcb); @@ -1041,6 +1042,8 @@ NETIEVENT_DEF(stop); NETIEVENT_TASK_DEF(task); +NETIEVENT_SOCKET_TLSCTX_DEF(settlsctx); + void isc__nm_maybe_enqueue_ievent(isc__networker_t *worker, isc__netievent_t *event) { @@ -3554,6 +3557,71 @@ isc_nm_verify_tls_peer_result_string(const isc_nmhandle_t *handle) { return (NULL); } +void +isc__nm_async_settlsctx(isc__networker_t *worker, isc__netievent_t *ev0) { + isc__netievent__tlsctx_t *ev_tlsctx = (isc__netievent__tlsctx_t *)ev0; + const int tid = isc_nm_tid(); + isc_nmsocket_t *listener = ev_tlsctx->sock; + isc_tlsctx_t *tlsctx = ev_tlsctx->tlsctx; + + UNUSED(worker); + + switch (listener->type) { + case isc_nm_tlsdnslistener: + isc__nm_async_tlsdns_set_tlsctx(listener, tlsctx, tid); + break; +#if HAVE_LIBNGHTTP2 + case isc_nm_tlslistener: + isc__nm_async_tls_set_tlsctx(listener, tlsctx, tid); + break; +#endif /* HAVE_LIBNGHTTP2 */ + default: + UNREACHABLE(); + break; + }; +} + +static void +set_tlsctx_workers(isc_nmsocket_t *listener, isc_tlsctx_t *tlsctx) { + /* Update the TLS context reference for every worker thread. */ + for (size_t i = 0; i < isc_nm_getnworkers(listener->mgr); i++) { + isc__netievent__tlsctx_t *ievent = + isc__nm_get_netievent_settlsctx(listener->mgr, listener, + tlsctx); + isc__nm_enqueue_ievent(&listener->mgr->workers[i], + (isc__netievent_t *)ievent); + } +} + +void +isc_nmsocket_set_tlsctx(isc_nmsocket_t *listener, isc_tlsctx_t *tlsctx) { + REQUIRE(VALID_NMSOCK(listener)); + REQUIRE(tlsctx != NULL); + + switch (listener->type) { +#if HAVE_LIBNGHTTP2 + case isc_nm_httplistener: + /* + * We handle HTTP listener sockets differently, as they rely + * on underlying TLS sockets for networking. The TLS context + * will get passed to these underlying sockets via the call to + * isc__nm_http_set_tlsctx(). + */ + isc__nm_http_set_tlsctx(listener, tlsctx); + break; + case isc_nm_tlslistener: + set_tlsctx_workers(listener, tlsctx); + break; +#endif /* HAVE_LIBNGHTTP2 */ + case isc_nm_tlsdnslistener: + set_tlsctx_workers(listener, tlsctx); + break; + default: + UNREACHABLE(); + break; + }; +} + #ifdef NETMGR_TRACE /* * Dump all active sockets in netmgr. We output to stderr diff --git a/lib/isc/netmgr/tlsdns.c b/lib/isc/netmgr/tlsdns.c index 021647f5b1..96612c1a85 100644 --- a/lib/isc/netmgr/tlsdns.c +++ b/lib/isc/netmgr/tlsdns.c @@ -2115,6 +2115,14 @@ isc__nm_tlsdns_verify_tls_peer_result_string(const isc_nmhandle_t *handle) { return (isc_tls_verify_peer_result_string(sock->tls.tls)); } +void +isc__nm_async_tlsdns_set_tlsctx(isc_nmsocket_t *listener, isc_tlsctx_t *tlsctx, + const int tid) { + REQUIRE(tid >= 0); + + isc_tlsctx_free(&listener->children[tid].tls.ctx); + isc_tlsctx_attach(tlsctx, &listener->children[tid].tls.ctx); +} void isc__nm_tlsdns_cleanup_data(isc_nmsocket_t *sock) { @@ -2124,4 +2132,4 @@ isc__nm_tlsdns_cleanup_data(isc_nmsocket_t *sock) { { isc_tlsctx_free(&sock->tls.ctx); } -} \ No newline at end of file +} diff --git a/lib/isc/netmgr/tlsstream.c b/lib/isc/netmgr/tlsstream.c index 0a46214a03..9ec072897e 100644 --- a/lib/isc/netmgr/tlsstream.c +++ b/lib/isc/netmgr/tlsstream.c @@ -1101,17 +1101,17 @@ isc__nm_tls_verify_tls_peer_result_string(const isc_nmhandle_t *handle) { static void tls_init_listener_tlsctx(isc_nmsocket_t *listener, isc_tlsctx_t *ctx) { - uint32_t nworkers; + size_t nworkers; REQUIRE(VALID_NM(listener->mgr)); - - nworkers = isc_nm_getnworkers(listener->mgr); - - REQUIRE(nworkers > 0); REQUIRE(ctx != NULL); + nworkers = (size_t)isc_nm_getnworkers(listener->mgr); + INSIST(nworkers > 0); + listener->tlsstream.listener_tls_ctx = isc_mem_get( listener->mgr->mctx, sizeof(isc_tlsctx_t *) * nworkers); + listener->tlsstream.n_listener_tls_ctx = nworkers; for (size_t i = 0; i < nworkers; i++) { listener->tlsstream.listener_tls_ctx[i] = NULL; isc_tlsctx_attach(ctx, @@ -1121,22 +1121,19 @@ tls_init_listener_tlsctx(isc_nmsocket_t *listener, isc_tlsctx_t *ctx) { static void tls_cleanup_listener_tlsctx(isc_nmsocket_t *listener) { - uint32_t nworkers; - REQUIRE(VALID_NM(listener->mgr)); - nworkers = isc_nm_getnworkers(listener->mgr); - - REQUIRE(nworkers > 0); if (listener->tlsstream.listener_tls_ctx == NULL) { return; } - for (size_t i = 0; i < nworkers; i++) { + for (size_t i = 0; i < listener->tlsstream.n_listener_tls_ctx; i++) { isc_tlsctx_free(&listener->tlsstream.listener_tls_ctx[i]); } isc_mem_put(listener->mgr->mctx, listener->tlsstream.listener_tls_ctx, - sizeof(isc_tlsctx_t *) * nworkers); + sizeof(isc_tlsctx_t *) * + listener->tlsstream.n_listener_tls_ctx); + listener->tlsstream.n_listener_tls_ctx = 0; } static isc_tlsctx_t * @@ -1150,3 +1147,12 @@ tls_get_listener_tlsctx(isc_nmsocket_t *listener, const int tid) { return (listener->tlsstream.listener_tls_ctx[tid]); } + +void +isc__nm_async_tls_set_tlsctx(isc_nmsocket_t *listener, isc_tlsctx_t *tlsctx, + const int tid) { + REQUIRE(tid >= 0); + + isc_tlsctx_free(&listener->tlsstream.listener_tls_ctx[tid]); + isc_tlsctx_attach(tlsctx, &listener->tlsstream.listener_tls_ctx[tid]); +}