Commit 7210a1b4c2 for asterisk.org
commit 7210a1b4c2e5d362317b8fb5c5c3b2263ec4a8a0
Author: Michal Hajek <michal.hajek@daktela.com>
Date: Wed Dec 10 14:51:40 2025 +0100
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
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
<configInfo name="res_pjsip_config_wizard" language="en_US">
@@ -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);