]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
[mod_commands, mod_verto] Add new reloadcert API and let mod_verto reload certificate...
authorAndrey Volk <andywolk@gmail.com>
Mon, 25 May 2026 21:25:56 +0000 (00:25 +0300)
committerGitHub <noreply@github.com>
Mon, 25 May 2026 21:25:56 +0000 (00:25 +0300)
src/include/switch_types.h
src/mod/applications/mod_commands/mod_commands.c
src/mod/endpoints/mod_verto/mod_verto.c
src/switch_event.c

index 294c64ee3f1772db90b5229301e8221808f5631a..a68d5bbf7093259389aa23a5246aebc2c506a44f 100644 (file)
@@ -2075,6 +2075,7 @@ typedef uint32_t switch_io_flag_t;
     SWITCH_EVENT_CALL_DETAIL
     SWITCH_EVENT_DEVICE_STATE
     SWITCH_EVENT_SHUTDOWN_REQUESTED            - Shutdown of the system has been requested
+    SWITCH_EVENT_CERT_RELOAD                   - SSL/TLS certificates reload has been requested
     SWITCH_EVENT_ALL                           - All events at once
 </pre>
 
@@ -2172,6 +2173,7 @@ typedef enum {
        SWITCH_EVENT_DEVICE_STATE,
        SWITCH_EVENT_TEXT,
        SWITCH_EVENT_SHUTDOWN_REQUESTED,
+       SWITCH_EVENT_CERT_RELOAD,
        SWITCH_EVENT_ALL
 } switch_event_types_t;
 
index 22e25ea8a67531c19578ef9fa459a708ed60d60b..b44035044aa27c74fd4785df69074d271610af57 100644 (file)
@@ -2860,6 +2860,22 @@ SWITCH_STANDARD_API(reload_xml_function)
        return SWITCH_STATUS_SUCCESS;
 }
 
+SWITCH_STANDARD_API(reload_cert_function)
+{
+       switch_event_t *event;
+
+       if (switch_event_create(&event, SWITCH_EVENT_CERT_RELOAD) == SWITCH_STATUS_SUCCESS) {
+               switch_event_fire(&event);
+               stream->write_function(stream, "+OK cert reload event sent\n");
+
+               return SWITCH_STATUS_SUCCESS;
+       }
+
+       stream->write_function(stream, "-ERR failed to create event\n");
+
+       return SWITCH_STATUS_FALSE;
+}
+
 #define KILL_SYNTAX "<uuid> [cause]"
 SWITCH_STANDARD_API(kill_function)
 {
@@ -7656,6 +7672,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load)
        SWITCH_ADD_API(commands_api_interface, "reloadacl", "Reload ACL", reload_acl_function, "");
        SWITCH_ADD_API(commands_api_interface, "reload", "Reload module", reload_function, UNLOAD_SYNTAX);
        SWITCH_ADD_API(commands_api_interface, "reloadxml", "Reload XML", reload_xml_function, "");
+       SWITCH_ADD_API(commands_api_interface, "reloadcert", "Reload SSL/TLS certificates", reload_cert_function, "");
        SWITCH_ADD_API(commands_api_interface, "replace", "Replace a string", replace_function, "<data>|<string1>|<string2>");
        SWITCH_ADD_API(commands_api_interface, "say_string", "", say_string_function, SAY_STRING_SYNTAX);
        SWITCH_ADD_API(commands_api_interface, "sched_api", "Schedule an api command", sched_api_function, SCHED_SYNTAX);
@@ -7831,6 +7848,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load)
        switch_console_set_complete("add nat_map status");
        switch_console_set_complete("add reload ::console::list_loaded_modules");
        switch_console_set_complete("add reloadacl reloadxml");
+       switch_console_set_complete("add reloadcert");
        switch_console_set_complete("add show aliases");
        switch_console_set_complete("add show api");
        switch_console_set_complete("add show application");
index 1363416139ff8315b06f6f1c64056de0d7121a88..113a21c57916872c14f6df4e30d73a5a0aa6bb26 100644 (file)
@@ -150,108 +150,162 @@ static void verto_deinit_ssl(verto_profile_t *profile)
        }
 }
 
-static void close_file(ks_socket_t *sock)
+static SSL_CTX *verto_create_ssl_ctx(verto_profile_t *profile, const char **errp)
 {
-       if (*sock != KS_SOCK_INVALID) {
-#ifndef WIN32
-               close(*sock);
-#else
-               closesocket(*sock);
-#endif
-               *sock = KS_SOCK_INVALID;
-       }
-}
+       SSL_CTX *ctx = SSL_CTX_new(profile->ssl_method);
 
-static void close_socket(ks_socket_t *sock)
-{
-       if (*sock != KS_SOCK_INVALID) {
-               shutdown(*sock, 2);
-               close_file(sock);
-       }
-}
-
-void verto_broadcast(const char *event_channel, cJSON *json, const char *key, switch_event_channel_id_t id, void *user_data);
+       if (!ctx) {
+               *errp = "Failed to create SSL context";
 
-static int verto_init_ssl(verto_profile_t *profile)
-{
-       const char *err;
-       int i = 0;
-
-       profile->ssl_method = SSLv23_server_method();   /* create server instance */
-       profile->ssl_ctx = SSL_CTX_new(profile->ssl_method);         /* create context */
-       profile->ssl_ready = 1;
-       assert(profile->ssl_ctx);
+               return NULL;
+       }
 
        /* Disable SSLv2 */
-       SSL_CTX_set_options(profile->ssl_ctx, SSL_OP_NO_SSLv2);
+       SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2);
        /* Disable SSLv3 */
-       SSL_CTX_set_options(profile->ssl_ctx, SSL_OP_NO_SSLv3);
+       SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3);
        /* Disable TLSv1 */
-       SSL_CTX_set_options(profile->ssl_ctx, SSL_OP_NO_TLSv1);
+       SSL_CTX_set_options(ctx, SSL_OP_NO_TLSv1);
        /* Disable Compression CRIME (Compression Ratio Info-leak Made Easy) */
-       SSL_CTX_set_options(profile->ssl_ctx, SSL_OP_NO_COMPRESSION);
+       SSL_CTX_set_options(ctx, SSL_OP_NO_COMPRESSION);
 
-       /* set the local certificate from CertFile */
        if (!zstr(profile->chain)) {
                if (switch_file_exists(profile->chain, NULL) != SWITCH_STATUS_SUCCESS) {
-                       err = "SUPPLIED CHAIN FILE NOT FOUND\n";
+                       *errp = "SUPPLIED CHAIN FILE NOT FOUND";
                        goto fail;
                }
 
-               if (!SSL_CTX_use_certificate_chain_file(profile->ssl_ctx, profile->chain)) {
-                       err = "CERT CHAIN FILE ERROR";
+               if (!SSL_CTX_use_certificate_chain_file(ctx, profile->chain)) {
+                       *errp = "CERT CHAIN FILE ERROR";
                        goto fail;
                }
        }
 
        if (switch_file_exists(profile->cert, NULL) != SWITCH_STATUS_SUCCESS) {
-               err = "SUPPLIED CERT FILE NOT FOUND\n";
+               *errp = "SUPPLIED CERT FILE NOT FOUND";
                goto fail;
        }
 
-       if (!SSL_CTX_use_certificate_file(profile->ssl_ctx, profile->cert, SSL_FILETYPE_PEM)) {
-               err = "CERT FILE ERROR";
+       if (!SSL_CTX_use_certificate_file(ctx, profile->cert, SSL_FILETYPE_PEM)) {
+               *errp = "CERT FILE ERROR";
                goto fail;
        }
 
-       /* set the private key from KeyFile */
-
        if (switch_file_exists(profile->key, NULL) != SWITCH_STATUS_SUCCESS) {
-               err = "SUPPLIED KEY FILE NOT FOUND\n";
+               *errp = "SUPPLIED KEY FILE NOT FOUND";
                goto fail;
        }
 
-       if (!SSL_CTX_use_PrivateKey_file(profile->ssl_ctx, profile->key, SSL_FILETYPE_PEM)) {
-               err = "PRIVATE KEY FILE ERROR";
+       if (!SSL_CTX_use_PrivateKey_file(ctx, profile->key, SSL_FILETYPE_PEM)) {
+               *errp = "PRIVATE KEY FILE ERROR";
                goto fail;
        }
 
-       /* verify private key */
-       if ( !SSL_CTX_check_private_key(profile->ssl_ctx) ) {
-               err = "PRIVATE KEY FILE ERROR";
+       if (!SSL_CTX_check_private_key(ctx)) {
+               *errp = "PRIVATE KEY FILE ERROR";
                goto fail;
        }
 
-       SSL_CTX_set_cipher_list(profile->ssl_ctx, "HIGH:!DSS:!aNULL@STRENGTH");
+       SSL_CTX_set_cipher_list(ctx, "HIGH:!DSS:!aNULL@STRENGTH");
 
-       return 1;
+       return ctx;
 
  fail:
-       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SSL ERR: %s\n", err);
+       SSL_CTX_free(ctx);
 
-       profile->ssl_ready = 0;
-       verto_deinit_ssl(profile);
+       return NULL;
+}
 
-       for (i = 0; i < profile->i; i++) {
-               if (profile->ip[i].secure) {
-                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SSL NOT ENABLED FOR LISTENER %s:%d. REVERTING TO WS\n",
-                                                         profile->ip[i].local_ip, profile->ip[i].local_port);
-                       profile->ip[i].secure = 0;
+static int verto_reload_ssl(verto_profile_t *profile)
+{
+       const char *err = NULL;
+       SSL_CTX *new_ctx = verto_create_ssl_ctx(profile, &err);
+
+       if (!new_ctx) {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SSL reload failed for profile %s: %s\n", profile->name, err);
+
+               return 0;
+       }
+
+       SSL_CTX_free(profile->ssl_ctx);
+
+       profile->ssl_ctx = new_ctx;
+       profile->ssl_ready = 1;
+
+       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "SSL certificates reloaded for profile %s\n", profile->name);
+
+       return 1;
+}
+
+static void cert_reload_handler(switch_event_t *event)
+{
+       verto_profile_t *p;
+
+       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Certificate reload event received, processing\n");
+
+       switch_mutex_lock(verto_globals.mutex);
+
+       for (p = verto_globals.profile_head; p; p = p->next) {
+               if (p->running) {
+                       switch_thread_rwlock_wrlock(p->rwlock);
+                       verto_reload_ssl(p);
+                       switch_thread_rwlock_unlock(p->rwlock);
                }
        }
 
-       return 0;
+       switch_mutex_unlock(verto_globals.mutex);
+
+       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Certificate reload event processed\n");
+}
+
+static void close_file(ks_socket_t *sock)
+{
+       if (*sock != KS_SOCK_INVALID) {
+#ifndef WIN32
+               close(*sock);
+#else
+               closesocket(*sock);
+#endif
+               *sock = KS_SOCK_INVALID;
+       }
+}
+
+static void close_socket(ks_socket_t *sock)
+{
+       if (*sock != KS_SOCK_INVALID) {
+               shutdown(*sock, 2);
+               close_file(sock);
+       }
+}
+
+void verto_broadcast(const char *event_channel, cJSON *json, const char *key, switch_event_channel_id_t id, void *user_data);
+
+static int verto_init_ssl(verto_profile_t *profile)
+{
+       const char *err = NULL;
+       int i = 0;
+
+       profile->ssl_method = SSLv23_server_method();
+       profile->ssl_ctx = verto_create_ssl_ctx(profile, &err);
+
+       if (!profile->ssl_ctx) {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SSL ERR: %s\n", err);
+
+               profile->ssl_ready = 0;
+
+               for (i = 0; i < profile->i; i++) {
+                       if (profile->ip[i].secure) {
+                               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "SSL NOT READY FOR LISTENER %s:%d. USE reloadcert AFTER FIXING CERTIFICATES\n",
+                                                                 profile->ip[i].local_ip, profile->ip[i].local_port);
+                       }
+               }
+
+               return 0;
+       }
+
+       profile->ssl_ready = 1;
 
+       return 1;
 }
 
 
@@ -1972,6 +2026,7 @@ static void client_run(jsock_t *jsock)
 
        ks_pool_open(&jsock->kpool);
 
+       switch_thread_rwlock_rdlock(jsock->profile->rwlock);
 #if defined(KS_VERSION_NUM) && KS_VERSION_NUM >= 20000
        params = ks_json_create_object();
        ks_json_add_number_to_object(params, "payload_size_max", 1000000);
@@ -1979,8 +2034,10 @@ static void client_run(jsock_t *jsock)
 #else
        if (kws_init(&jsock->ws, jsock->client_socket, (jsock->ptype & PTYPE_CLIENT_SSL) ? jsock->profile->ssl_ctx : NULL, 0, flags, jsock->kpool) != KS_STATUS_SUCCESS) {
 #endif
+               switch_thread_rwlock_unlock(jsock->profile->rwlock);
                log_and_exit(SWITCH_LOG_NOTICE, "%s WS SETUP FAILED\n", jsock->name);
        }
+       switch_thread_rwlock_unlock(jsock->profile->rwlock);
 
        if (kws_test_flag(jsock->ws, KWS_HTTP)) {
                http_run(jsock);
@@ -4690,7 +4747,7 @@ static int start_jsock(verto_profile_t *profile, ks_socket_t sock, int family)
 
        for (i = 0; i < profile->i; i++) {
                if ( profile->server_socket[i] == sock ) {
-                       if (profile->ip[i].secure) {
+                       if (profile->ip[i].secure && profile->ssl_ready) {
                                ptype = PTYPE_CLIENT_SSL;
                        }
                        break;
@@ -6887,6 +6944,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_verto_load)
 
        switch_core_register_secondary_recover_callback(modname, verto_recover_callback);
 
+       switch_event_bind(modname, SWITCH_EVENT_CERT_RELOAD, SWITCH_EVENT_SUBCLASS_ANY, cert_reload_handler, NULL);
+
        if (verto_globals.enable_presence) {
                switch_event_bind(modname, SWITCH_EVENT_CHANNEL_CALLSTATE, SWITCH_EVENT_SUBCLASS_ANY, presence_event_handler, NULL);
        }
@@ -6922,6 +6981,7 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_verto_shutdown)
        switch_core_hash_destroy(&json_GLOBALS.store_hash);
 
        switch_event_channel_unbind(NULL, verto_broadcast, NULL);
+       switch_event_unbind_callback(cert_reload_handler);
        switch_event_unbind_callback(presence_event_handler);
        switch_event_unbind_callback(event_handler);
 
index 8a8c8d6c3579595475c27ebf69978b4c71aa7540..25bf961512f9a81f3c0a176e45d355b5998e0cf1 100644 (file)
@@ -227,6 +227,7 @@ static char *EVENT_NAMES[] = {
        "DEVICE_STATE",
        "TEXT",
        "SHUTDOWN_REQUESTED",
+       "CERT_RELOAD",
        "ALL"
 };