@@ -302,6 +302,15 @@ struct rspamd_config_post_load_script { | |||
struct rspamd_lang_detector; | |||
struct rspamd_config_settings_elt { | |||
guint32 id; | |||
const gchar *name; | |||
ucl_object_t *symbols_enabled; | |||
ucl_object_t *symbols_disabled; | |||
struct rspamd_config_settings_elt *prev, *next; | |||
ref_entry_t ref; | |||
}; | |||
/** | |||
* Structure that stores all config data | |||
*/ | |||
@@ -458,6 +467,7 @@ struct rspamd_config { | |||
gchar *zstd_output_dictionary; /**< path to zstd output dictionary */ | |||
ucl_object_t *neighbours; /**< other servers in the cluster */ | |||
struct rspamd_config_settings_elt *setting_ids; /**< preprocessed settings ids */ | |||
struct rspamd_lang_detector *lang_det; /**< language detector */ | |||
ref_entry_t ref; /**< reference counter */ | |||
@@ -715,6 +725,38 @@ gboolean rspamd_config_radix_from_ucl (struct rspamd_config *cfg, | |||
struct rspamd_radix_map_helper **target, | |||
GError **err); | |||
/** | |||
* Adds new settings id to be preprocessed | |||
* @param cfg | |||
* @param name | |||
* @param symbols_enabled | |||
* @param symbols_disabled | |||
*/ | |||
void rspamd_config_register_settings_id (struct rspamd_config *cfg, | |||
const gchar *name, | |||
ucl_object_t *symbols_enabled, | |||
ucl_object_t *symbols_disabled); | |||
/** | |||
* Finds settings id element and obtain reference count (must be unrefed by callee) | |||
* @param cfg | |||
* @param id | |||
* @return | |||
*/ | |||
struct rspamd_config_settings_elt *rspamd_config_find_settings_id_ref ( | |||
struct rspamd_config *cfg, | |||
guint32 id); | |||
/** | |||
* Finds settings id element and obtain reference count (must be unrefed by callee) | |||
* @param cfg | |||
* @param id | |||
* @return | |||
*/ | |||
struct rspamd_config_settings_elt *rspamd_config_find_settings_name_ref ( | |||
struct rspamd_config *cfg, | |||
const gchar *name, gsize namelen); | |||
/** | |||
* Returns action object by name | |||
* @param cfg |
@@ -2334,3 +2334,115 @@ rspamd_actions_sort (struct rspamd_config *cfg) | |||
{ | |||
HASH_SORT (cfg->actions, rspamd_actions_cmp); | |||
} | |||
static void | |||
rspamd_config_settings_elt_dtor (struct rspamd_config_settings_elt *e) | |||
{ | |||
if (e->symbols_enabled) { | |||
ucl_object_unref (e->symbols_enabled); | |||
} | |||
if (e->symbols_disabled) { | |||
ucl_object_unref (e->symbols_disabled); | |||
} | |||
} | |||
static inline guint32 | |||
rspamd_config_name_to_id (const gchar *name, gsize namelen) | |||
{ | |||
guint64 h; | |||
h = rspamd_cryptobox_fast_hash_specific (RSPAMD_CRYPTOBOX_XXHASH64, | |||
name, strlen (name), 0x0); | |||
/* Take the lower part of hash as LE number */ | |||
return ((guint32)GUINT64_TO_LE (h)); | |||
} | |||
struct rspamd_config_settings_elt * | |||
rspamd_config_find_settings_id_ref (struct rspamd_config *cfg, | |||
guint32 id) | |||
{ | |||
struct rspamd_config_settings_elt *cur; | |||
DL_FOREACH (cfg->setting_ids, cur) { | |||
if (cur->id == id) { | |||
REF_RETAIN (cur); | |||
return cur; | |||
} | |||
} | |||
return NULL; | |||
} | |||
struct rspamd_config_settings_elt *rspamd_config_find_settings_name_ref ( | |||
struct rspamd_config *cfg, | |||
const gchar *name, gsize namelen) | |||
{ | |||
guint32 id; | |||
id = rspamd_config_name_to_id (name, namelen); | |||
return rspamd_config_find_settings_id_ref (cfg, id); | |||
} | |||
void | |||
rspamd_config_register_settings_id (struct rspamd_config *cfg, | |||
const gchar *name, | |||
ucl_object_t *symbols_enabled, | |||
ucl_object_t *symbols_disabled) | |||
{ | |||
struct rspamd_config_settings_elt *elt; | |||
guint32 id; | |||
id = rspamd_config_name_to_id (name, strlen (name)); | |||
elt = rspamd_config_find_settings_id_ref (cfg, id); | |||
if (elt) { | |||
/* Need to replace */ | |||
struct rspamd_config_settings_elt *nelt; | |||
DL_DELETE (cfg->setting_ids, elt); | |||
nelt = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (*nelt)); | |||
nelt->id = id; | |||
nelt->name = rspamd_mempool_strdup (cfg->cfg_pool, name); | |||
if (symbols_enabled) { | |||
nelt->symbols_enabled = ucl_object_ref (symbols_enabled); | |||
} | |||
if (symbols_disabled) { | |||
nelt->symbols_disabled = ucl_object_ref (symbols_disabled); | |||
} | |||
REF_INIT_RETAIN (nelt, rspamd_config_settings_elt_dtor); | |||
msg_info_config ("replace settings id %d (%s)", id, name); | |||
DL_APPEND (cfg->setting_ids, nelt); | |||
/* | |||
* Need to unref old element twice as there are two reference holders: | |||
* 1. Config structure as we call REF_INIT_RETAIN | |||
* 2. rspamd_config_find_settings_id_ref also increases refcount | |||
*/ | |||
REF_RELEASE (elt); | |||
REF_RELEASE (elt); | |||
} | |||
else { | |||
elt = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (*elt)); | |||
elt->id = id; | |||
elt->name = rspamd_mempool_strdup (cfg->cfg_pool, name); | |||
if (symbols_enabled) { | |||
elt->symbols_enabled = ucl_object_ref (symbols_enabled); | |||
} | |||
if (symbols_disabled) { | |||
elt->symbols_disabled = ucl_object_ref (symbols_disabled); | |||
} | |||
msg_info_config ("register new settings id %d (%s)", id, name); | |||
REF_INIT_RETAIN (elt, rspamd_config_settings_elt_dtor); | |||
DL_APPEND (cfg->setting_ids, elt); | |||
} | |||
} |
@@ -483,13 +483,14 @@ rspamd_protocol_handle_headers (struct rspamd_task *task, | |||
task->subject = rspamd_mempool_ftokdup (task->task_pool, hv_tok); | |||
} | |||
IF_HEADER (SETTINGS_ID_HEADER) { | |||
guint64 h; | |||
msg_debug_protocol ("read settings-id header, value: %V", hv); | |||
h = rspamd_cryptobox_fast_hash_specific (RSPAMD_CRYPTOBOX_XXHASH64, | |||
hv_tok->begin, hv_tok->len, 0x0); | |||
/* Take the lower part of hash as LE number */ | |||
task->settings_id = (guint32)GUINT64_TO_LE (h); | |||
task->settings_elt = rspamd_config_find_settings_name_ref ( | |||
task->cfg, hv_tok->begin, hv_tok->len); | |||
if (task->settings_elt == NULL) { | |||
msg_warn_protocol ("unknown settings id: %V", | |||
hv); | |||
} | |||
} | |||
break; | |||
case 'u': | |||
@@ -1702,10 +1703,9 @@ rspamd_protocol_write_log_pipe (struct rspamd_task *task) | |||
ls = g_malloc0 (sz); | |||
/* Handle settings id */ | |||
sid = task->settings_id; | |||
if (sid) { | |||
ls->settings_id = sid; | |||
if (task->settings_elt) { | |||
ls->settings_id = task->settings_elt->id; | |||
} | |||
else { | |||
ls->settings_id = 0; |
@@ -1425,24 +1425,26 @@ static gboolean | |||
rspamd_symcache_is_item_allowed (struct rspamd_task *task, | |||
struct rspamd_symcache_item *item) | |||
{ | |||
if (task->settings_id != 0) { | |||
if (task->settings_elt != 0) { | |||
guint32 id = task->settings_elt->id; | |||
if (item->forbidden_ids.st[0] != 0 && | |||
rspamd_symcache_check_id_list (&item->forbidden_ids, | |||
task->settings_id)) { | |||
id)) { | |||
msg_debug_cache_task ("deny execution of %s as it is forbidden for " | |||
"settings id %d", | |||
item->symbol, | |||
task->settings_id); | |||
id); | |||
return FALSE; | |||
} | |||
if (item->allowed_ids.st[0] != 0 && | |||
!rspamd_symcache_check_id_list (&item->allowed_ids, | |||
task->settings_id)) { | |||
id)) { | |||
msg_debug_cache_task ("deny execution of %s as it is not listed as allowed for " | |||
"settings id %d", | |||
item->symbol, | |||
task->settings_id); | |||
id); | |||
return FALSE; | |||
} | |||
} |
@@ -313,6 +313,10 @@ rspamd_task_free (struct rspamd_task *task) | |||
ucl_object_unref (task->settings); | |||
} | |||
if (task->settings_elt != NULL) { | |||
REF_RELEASE (task->settings_elt); | |||
} | |||
if (task->client_addr) { | |||
rspamd_inet_address_free (task->client_addr); | |||
} |
@@ -206,7 +206,7 @@ struct rspamd_task { | |||
gpointer checkpoint; /**< Opaque checkpoint data */ | |||
ucl_object_t *settings; /**< Settings applied to task */ | |||
guint32 processed_stages; /**< bits of stages that are processed */ | |||
guint32 settings_id; /**< hashed settings id */ | |||
struct rspamd_config_settings_elt *settings_elt; /**< preprocessed settings id elt */ | |||
const gchar *classifier; /**< Classifier to learn (if needed) */ | |||
struct rspamd_lang_detector *lang_det; /**< Languages detector */ |
@@ -4872,8 +4872,8 @@ lua_task_get_settings_id (lua_State *L) | |||
if (task != NULL) { | |||
if (task->settings_id) { | |||
lua_pushnumber (L, task->settings_id); | |||
if (task->settings_elt) { | |||
lua_pushnumber (L, task->settings_elt->id); | |||
} | |||
else { | |||
lua_pushnil (L); |