mosquitto-auth-plugin: add SIGHUP support for dynamic ACL reload

Enable dynamic reloading of subnet ACL configuration via SIGHUP signal
  without disconnecting clients. Register MOSQ_EVT_RELOAD callback to
  reload ACL rules when mosquitto receives SIGHUP.
This commit is contained in:
Sukru Senli 2025-11-26 10:47:27 +01:00
parent d526ee41cd
commit 3655ae9d79
2 changed files with 55 additions and 1 deletions

View file

@ -14,7 +14,7 @@
include $(TOPDIR)/rules.mk include $(TOPDIR)/rules.mk
PKG_NAME:=mosquitto-auth-plugin PKG_NAME:=mosquitto-auth-plugin
PKG_VERSION:=1.2.0 PKG_VERSION:=1.2.1
PKG_MAINTAINER:=Erik Karlsson <erik.karlsson@genexis.eu> PKG_MAINTAINER:=Erik Karlsson <erik.karlsson@genexis.eu>
PKG_LICENSE:=EPL-2.0 PKG_LICENSE:=EPL-2.0

View file

@ -53,6 +53,7 @@ typedef struct {
user_acl_t users[MAX_USERS]; user_acl_t users[MAX_USERS];
int user_count; int user_count;
mosquitto_plugin_id_t *identifier; mosquitto_plugin_id_t *identifier;
char *config_file;
} plugin_data_t; } plugin_data_t;
/* Parse CIDR notation for IPv4 or IPv6 (e.g., "192.168.1.0/24" or "2001:db8::/32") */ /* Parse CIDR notation for IPv4 or IPv6 (e.g., "192.168.1.0/24" or "2001:db8::/32") */
@ -548,6 +549,30 @@ static int basic_auth_callback(int event, void *event_data, void *userdata)
return check_subnet_on_auth(pdata, ed); return check_subnet_on_auth(pdata, ed);
} }
static int reload_callback(int event, void *event_data, void *userdata)
{
plugin_data_t *pdata = userdata;
if (pdata == NULL)
return MOSQ_ERR_SUCCESS;
mosquitto_log_printf(MOSQ_LOG_NOTICE,
"subnet_acl: Reloading subnet ACL configuration from '%s'",
pdata->config_file ? pdata->config_file : "(none)");
/* Reload subnet ACL configuration */
if (load_subnet_acl_config(pdata, pdata->config_file) != 0) {
mosquitto_log_printf(MOSQ_LOG_ERR,
"subnet_acl: Failed to reload subnet ACL configuration, keeping old config");
return MOSQ_ERR_UNKNOWN;
}
mosquitto_log_printf(MOSQ_LOG_NOTICE,
"subnet_acl: Reload complete, now tracking %d user(s)", pdata->user_count);
return MOSQ_ERR_SUCCESS;
}
int mosquitto_plugin_version(int supported_version_count, int mosquitto_plugin_version(int supported_version_count,
const int *supported_versions) const int *supported_versions)
{ {
@ -576,8 +601,20 @@ int mosquitto_plugin_init(mosquitto_plugin_id_t *identifier,
pdata->identifier = identifier; pdata->identifier = identifier;
/* Store config file path for reload */
if (config_file != NULL) {
pdata->config_file = strdup(config_file);
if (pdata->config_file == NULL) {
free(pdata);
return MOSQ_ERR_NOMEM;
}
} else {
pdata->config_file = NULL;
}
/* Load subnet ACL configuration */ /* Load subnet ACL configuration */
if (load_subnet_acl_config(pdata, config_file) != 0) { if (load_subnet_acl_config(pdata, config_file) != 0) {
free(pdata->config_file);
free(pdata); free(pdata);
return MOSQ_ERR_UNKNOWN; return MOSQ_ERR_UNKNOWN;
} }
@ -588,6 +625,20 @@ int mosquitto_plugin_init(mosquitto_plugin_id_t *identifier,
if (rc != MOSQ_ERR_SUCCESS) { if (rc != MOSQ_ERR_SUCCESS) {
mosquitto_log_printf(MOSQ_LOG_ERR, mosquitto_log_printf(MOSQ_LOG_ERR,
"subnet_acl: Failed to register authentication callback"); "subnet_acl: Failed to register authentication callback");
free(pdata->config_file);
free(pdata);
return rc;
}
/* Register reload callback to handle SIGHUP */
rc = mosquitto_callback_register(identifier, MOSQ_EVT_RELOAD,
reload_callback, NULL, pdata);
if (rc != MOSQ_ERR_SUCCESS) {
mosquitto_log_printf(MOSQ_LOG_ERR,
"subnet_acl: Failed to register reload callback");
mosquitto_callback_unregister(identifier, MOSQ_EVT_BASIC_AUTH,
basic_auth_callback, NULL);
free(pdata->config_file);
free(pdata); free(pdata);
return rc; return rc;
} }
@ -609,6 +660,9 @@ int mosquitto_plugin_cleanup(void *user_data,
if (pdata) { if (pdata) {
mosquitto_callback_unregister(pdata->identifier, MOSQ_EVT_BASIC_AUTH, mosquitto_callback_unregister(pdata->identifier, MOSQ_EVT_BASIC_AUTH,
basic_auth_callback, NULL); basic_auth_callback, NULL);
mosquitto_callback_unregister(pdata->identifier, MOSQ_EVT_RELOAD,
reload_callback, NULL);
free(pdata->config_file);
free(pdata); free(pdata);
} }