From 25bcbc3cfcdef70921dee3f52d66b2927bcb991b Mon Sep 17 00:00:00 2001 From: Michal Hajek Date: Wed, 10 Dec 2025 14:51:40 +0100 Subject: [PATCH] res_pjsip_config_wizard: Force reload on Named ACL change events Currently, endpoints created via the PJSIP Config Wizard do not update their ACL rules if the underlying Named ACL (in acl.conf) changes. This occurs because the wizard relies on file timestamp and content caching of pjsip_wizard.conf, which remains unchanged during an external ACL update. As a result, endpoints retain stale ACL rules even after a reload. This patch updates res_pjsip_config_wizard to subscribe to the ast_named_acl_change_type Stasis event. A local generation counter is incremented whenever an ACL change event is received. During a reload, the wizard compares the current local generation against the generation stored in the wizard object. If a change is detected: 1. The file cache optimization (CONFIG_FLAG_FILEUNCHANGED) is bypassed. 2. Wizard objects utilizing 'acl' or 'contact_acl' are forced to update, ensuring they pick up the new IP rules. Signed-off-by: Michal Hajek michal.hajek@daktela.com Fixes: #1641 --- res/res_pjsip_config_wizard.c | 37 ++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/res/res_pjsip_config_wizard.c b/res/res_pjsip_config_wizard.c index 4ddd875bb5..1789e34f8d 100644 --- a/res/res_pjsip_config_wizard.c +++ b/res/res_pjsip_config_wizard.c @@ -49,6 +49,9 @@ #include "asterisk/pbx.h" #include "asterisk/sorcery.h" #include "asterisk/vector.h" +#include "asterisk/stasis.h" +#include "asterisk/acl.h" +#include "asterisk/security_events.h" /*** DOCUMENTATION @@ -297,6 +300,22 @@ static AST_VECTOR_RW(object_type_wizards, struct object_type_wizard *) object_ty const static char *object_types[] = {"phoneprov", "registration", "identify", "endpoint", "aor", "auth", NULL}; +static int acl_change_detected = 0; +static struct stasis_subscription *acl_change_sub; + +/*! \brief Callback for Named ACL changed */ +static void acl_change_stasis_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message) +{ + if (stasis_message_type(message) != ast_named_acl_change_type()) { + return; + } + + ast_debug(3, "PJSIP Wizard: Named ACL change detected via Stasis. Triggering reload.\n"); + acl_change_detected = 1; + ast_sorcery_reload(ast_sip_get_sorcery()); + acl_change_detected = 0; +} + static int is_one_of(const char *needle, const char *haystack[]) { int i; @@ -1064,7 +1083,9 @@ static void object_type_loaded_observer(const char *name, return; } - if (reloaded && otw->last_config) { + /* Only use the FILEUNCHANGED optimization if the ACLs haven't changed. + * If ACLs changed, we force a reload of the config file to re-evaluate rules. */ + if (reloaded && otw->last_config && !acl_change_detected) { flags.flags = CONFIG_FLAG_FILEUNCHANGED; } @@ -1089,6 +1110,14 @@ static void object_type_loaded_observer(const char *name, if (otw->last_config) { last_cat = ast_category_get(otw->last_config, id, "type=^wizard$"); changes = !ast_variable_lists_match(ast_category_first(category), ast_category_first(last_cat), 1); + + /* If the ACL has changed, we assume EVERYTHING might have changed. + * We force an update for all wizard objects. */ + if (!changes && reloaded && acl_change_detected) { + ast_debug(3, "Forcing update of wizard '%s' due to global ACL change.\n", id); + changes = 1; + } + if (last_cat) { ast_category_delete(otw->last_config, last_cat); } @@ -1314,6 +1343,8 @@ static int load_module(void) ast_sorcery_global_observer_add(&global_observer); ast_cli_register_multiple(config_wizard_cli, ARRAY_LEN(config_wizard_cli)); + acl_change_sub = stasis_subscribe(ast_security_topic(), acl_change_stasis_cb, NULL); + /* If the PJSIP sorcery instance exists it means that we have been explicitly * loaded and things are potentially already set up. Since we won't receive any * observer callbacks informing us of this we add ourselves to the instance @@ -1347,6 +1378,10 @@ static int load_module(void) static int unload_module(void) { + if (acl_change_sub) { + acl_change_sub = stasis_unsubscribe_and_join(acl_change_sub); + } + ast_cli_unregister_multiple(config_wizard_cli, ARRAY_LEN(config_wizard_cli)); ast_sorcery_global_observer_remove(&global_observer); AST_VECTOR_REMOVE_ALL_CMP_UNORDERED(&object_type_wizards, NULL, NOT_EQUALS, OTW_DELETE_CB);