]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Add isc_nmsocket_set_tlsctx()
authorArtem Boldariev <artem@boldariev.com>
Thu, 31 Mar 2022 10:47:48 +0000 (13:47 +0300)
committerArtem Boldariev <artem@boldariev.com>
Wed, 6 Apr 2022 15:45:57 +0000 (18:45 +0300)
This commit adds isc_nmsocket_set_tlsctx() - an asynchronous function
that replaces the TLS context within a given TLS-enabled listener
socket object. It is based on the newly added reference counting
functionality.

The intention of adding this function is to add functionality to
replace a TLS context without recreating the whole socket object,
including the underlying TCP listener socket, as a BIND process might
not have enough permissions to re-create it fully on reconfiguration.

lib/isc/include/isc/netmgr.h
lib/isc/netmgr/http.c
lib/isc/netmgr/netmgr-int.h
lib/isc/netmgr/netmgr.c
lib/isc/netmgr/tlsdns.c
lib/isc/netmgr/tlsstream.c

index 0ae582a0b5b032114f88fe26efdaa4f2a72325d2..4651bbf4cf864b7d17e52f6ef50a1a859ea76692 100644 (file)
@@ -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__)
index 6684373a686c9bc4d831ed5eaf9826fd70b60ba6..1d59ee3c309c5af6ee4794c38ae2ad99f5e7c11e 100644 (file)
@@ -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,
index a8a7e93ad4a2080bfce4c0af3c08f4adb42de56a..9adb7e0084db35f36167ead365180b7b475162b3 100644 (file)
@@ -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
index 66b77939c54eb053cc007f5cfa62190a073d471a..a73223942cdee513d9dd4d67837fb80a02517a1f 100644 (file)
@@ -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
index 021647f5b1ba89d22816c0bb767d372f6f54b946..96612c1a854d3c6803e0241fbeac3fcdec528a9f 100644 (file)
@@ -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
+}
index 0a46214a0380bb8cb61f9ebdd6be717d3b2de830..9ec072897e4cdefabe2cd61b8a8c4bcf28edee4a 100644 (file)
@@ -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]);
+}