diff options
author | Vsevolod Stakhov <vsevolod@rambler-co.ru> | 2012-10-01 22:08:36 +0400 |
---|---|---|
committer | Vsevolod Stakhov <vsevolod@rambler-co.ru> | 2012-10-01 22:08:36 +0400 |
commit | 6205f36ee17d54e9e43d495ba929ed7708c98027 (patch) | |
tree | 6af53ce62a1e0e749cef789a77cfe3e6f0652722 /src | |
parent | cdb0282eb749fc0cb274575b01c9ca988a5f5db1 (diff) | |
download | rspamd-6205f36ee17d54e9e43d495ba929ed7708c98027.tar.gz rspamd-6205f36ee17d54e9e43d495ba929ed7708c98027.zip |
* Add dynamic configuration dumping.
* Add labels support to the statfiles (would be used for meta-classification)
* Rewrite exim spam.c patch to work with both rspamd and SA by using 'variant=rspamd' option
in spam_server line.
Diffstat (limited to 'src')
-rw-r--r-- | src/cfg_file.h | 3 | ||||
-rw-r--r-- | src/cfg_utils.c | 4 | ||||
-rw-r--r-- | src/cfg_xml.c | 14 | ||||
-rw-r--r-- | src/dynamic_cfg.c | 152 | ||||
-rw-r--r-- | src/dynamic_cfg.h | 7 | ||||
-rw-r--r-- | src/lua/lua_classifier.c | 43 |
6 files changed, 222 insertions, 1 deletions
diff --git a/src/cfg_file.h b/src/cfg_file.h index e2c1c7678..eaad2ff22 100644 --- a/src/cfg_file.h +++ b/src/cfg_file.h @@ -182,6 +182,7 @@ typedef double (*statfile_normalize_func)(struct config_file *cfg, long double s struct statfile { gchar *symbol; /**< symbol of statfile */ gchar *path; /**< filesystem pattern (with %r or %f) */ + gchar *label; /**< label of this statfile */ gsize size; /**< size of statfile */ GList *sections; /**< list of sections in statfile */ struct statfile_autolearn_params *autolearn; /**< autolearn params */ @@ -198,6 +199,7 @@ struct statfile { */ struct classifier_config { GList *statfiles; /**< statfiles list */ + GHashTable *labels; /**< statfiles with labels */ gchar *metric; /**< metric of this classifier */ struct classifier *classifier; /**< classifier interface */ struct tokenizer *tokenizer; /**< tokenizer used for classifier */ @@ -315,6 +317,7 @@ struct config_file { GList *pre_filters; /**< list of pre-processing lua filters */ GList *post_filters; /**< list of post-processing lua filters */ gchar *dynamic_conf; /**< path to dynamic configuration */ + GList *current_dynamic_conf; /**< currently loaded dynamic configuration */ GHashTable* domain_settings; /**< settings per-domains */ GHashTable* user_settings; /**< settings per-user */ gchar* domain_settings_str; /**< string representation of settings */ diff --git a/src/cfg_utils.c b/src/cfg_utils.c index d554ae7fb..440fb65e6 100644 --- a/src/cfg_utils.c +++ b/src/cfg_utils.c @@ -826,6 +826,10 @@ check_classifier_conf (struct config_file *cfg, struct classifier_config *c) c->opts = g_hash_table_new (g_str_hash, g_str_equal); memory_pool_add_destructor (cfg->cfg_pool, (pool_destruct_func) g_hash_table_destroy, c->opts); } + if (c->labels == NULL) { + c->labels = g_hash_table_new (g_str_hash, g_str_equal); + memory_pool_add_destructor (cfg->cfg_pool, (pool_destruct_func) g_hash_table_destroy, c->labels); + } return c; } diff --git a/src/cfg_xml.c b/src/cfg_xml.c index e47ead1c8..bcec06c1d 100644 --- a/src/cfg_xml.c +++ b/src/cfg_xml.c @@ -484,6 +484,12 @@ static struct xml_parser_rule grammar[] = { NULL }, { + "label", + xml_handle_string, + G_STRUCT_OFFSET (struct statfile, label), + NULL + }, + { "size", xml_handle_size, G_STRUCT_OFFSET (struct statfile, size), @@ -1955,6 +1961,14 @@ rspamd_xml_end_element (GMarkupParseContext *context, const gchar *element_name, ccf->statfiles = g_list_prepend (ccf->statfiles, st); ud->cfg->statfiles = g_list_prepend (ud->cfg->statfiles, st); g_hash_table_insert (ud->cfg->classifiers_symbols, st->symbol, ccf); + if (st->label) { + if (g_hash_table_lookup (ccf->labels, st->label)) { + msg_warn ("duplicate statfile label %s with symbol %s, ignoring", st->label, st->symbol); + } + else { + g_hash_table_insert (ccf->labels, st->label, st); + } + } ud->section_pointer = ccf; ud->parent_pointer = NULL; ud->state = XML_READ_CLASSIFIER; diff --git a/src/dynamic_cfg.c b/src/dynamic_cfg.c index 4f4167887..17d634721 100644 --- a/src/dynamic_cfg.c +++ b/src/dynamic_cfg.c @@ -233,6 +233,7 @@ json_config_fin_cb (memory_pool_t * pool, struct map_cb_data *data) return; } + jb->cfg->current_dynamic_conf = NULL; dynamic_cfg_free (jb->config_metrics); jb->config_metrics = NULL; @@ -301,6 +302,8 @@ json_config_fin_cb (memory_pool_t * pool, struct map_cb_data *data) */ apply_dynamic_conf (jb->config_metrics, jb->cfg); + jb->cfg->current_dynamic_conf = jb->config_metrics; + json_decref (js); } @@ -339,3 +342,152 @@ init_dynamic_config (struct config_file *cfg) } } +static gboolean +dump_dynamic_list (gint fd, GList *rules) +{ + GList *cur, *cur_elt; + struct dynamic_cfg_metric *metric; + struct dynamic_cfg_symbol *sym; + struct dynamic_cfg_action *act; + FILE *f; + + /* Open buffered stream for the descriptor */ + if ((f = fdopen (fd, "a+")) == NULL) { + msg_err ("fdopen failed: %s", strerror (errno)); + return FALSE; + } + + + if (rules) { + fprintf (f, "[\n"); + cur = rules; + while (cur) { + metric = cur->data; + fprintf (f, "{\n\"metric\": \"%s\"\n", metric->name); + if (metric->symbols) { + fprintf (f, " \"symbols\": [\n"); + cur_elt = metric->symbols; + while (cur_elt) { + sym = cur_elt->data; + cur_elt = g_list_next (cur_elt); + if (cur_elt) { + fprintf (f, " {\"name\": \"%s\",\n\"value\": %.2f},\n", sym->name, sym->value); + } + else { + fprintf (f, " {\"name\": \"%s\",\n\"value\": %.2f}\n", sym->name, sym->value); + } + } + if (metric->actions) { + fprintf (f, " ],\n"); + } + else { + fprintf (f, " ]\n"); + } + } + + if (metric->actions) { + cur_elt = metric->actions; + fprintf (f, " \"actions\": [\n"); + while (cur_elt) { + act = cur_elt->data; + cur_elt = g_list_next (cur_elt); + if (cur_elt) { + fprintf (f, " {\"name\": \"%s\",\n\"value\": %.2f},\n", str_action_metric (act->action), act->value); + } + else { + fprintf (f, " {\"name\": \"%s\",\n\"value\": %.2f}\n", str_action_metric (act->action), act->value); + } + } + fprintf (f, " ]\n"); + } + cur = g_list_next (cur); + if (cur) { + fprintf (f, "},\n"); + } + else { + fprintf (f, "}\n]\n"); + } + } + } + fclose (f); + + return TRUE; +} + +/** + * Dump dynamic configuration to the disk + * @param cfg + * @return + */ +gboolean +dump_dynamic_config (struct config_file *cfg) +{ + struct stat st; + gchar *dir, pathbuf[PATH_MAX]; + gint fd; + + if (cfg->dynamic_conf == NULL || cfg->current_dynamic_conf == NULL) { + /* No dynamic conf has been specified, so do not try to dump it */ + return FALSE; + } + + if (stat (cfg->dynamic_conf, &st) == -1) { + msg_warn ("%s is unavailable: %s", cfg->dynamic_conf, strerror (errno)); + return FALSE; + } + if (access (cfg->dynamic_conf, W_OK | R_OK) == -1) { + msg_warn ("%s is inaccessible: %s", cfg->dynamic_conf, strerror (errno)); + return FALSE; + } + + dir = g_path_get_dirname (cfg->dynamic_conf); + if (dir == NULL) { + /* Inaccessible path */ + if (dir != NULL) { + g_free (dir); + } + msg_err ("invalid file: %s", cfg->dynamic_conf); + return FALSE; + } + + rspamd_snprintf (pathbuf, sizeof (pathbuf), "%s%crconf-XXXXXX", dir, G_DIR_SEPARATOR); +#ifdef HAVE_MKSTEMP + /* Umask is set before */ + fd = mkstemp (pathbuf); +#else + fd = g_mkstemp_full (pathbuf, O_RDWR, S_IWUSR | S_IRUSR); +#endif + if (fd == -1) { + msg_err ("mkstemp error: %s", strerror (errno)); + + return FALSE; + } + + if (!dump_dynamic_list (fd, cfg->current_dynamic_conf)) { + close (fd); + unlink (pathbuf); + return FALSE; + } + + if (unlink (cfg->dynamic_conf) == -1) { + msg_err ("unlink error: %s", strerror (errno)); + close (fd); + unlink (pathbuf); + return FALSE; + } + + /* Rename old config */ + if (rename (pathbuf, cfg->dynamic_conf) == -1) { + msg_err ("unlink error: %s", strerror (errno)); + close (fd); + unlink (pathbuf); + return FALSE; + } + /* Set permissions */ + if (chmod (cfg->dynamic_conf, st.st_mode) == -1) { + msg_warn ("chmod failed: %s", strerror (errno)); + } + + close (fd); + return TRUE; +} diff --git a/src/dynamic_cfg.h b/src/dynamic_cfg.h index edf026e53..494a48835 100644 --- a/src/dynamic_cfg.h +++ b/src/dynamic_cfg.h @@ -34,5 +34,12 @@ */ void init_dynamic_config (struct config_file *cfg); +/** + * Dump dynamic configuration to the disk + * @param cfg + * @return + */ +gboolean dump_dynamic_config (struct config_file *cfg); + #endif /* DYNAMIC_CFG_H_ */ diff --git a/src/lua/lua_classifier.c b/src/lua/lua_classifier.c index d4a8edb87..c6eb2cf18 100644 --- a/src/lua/lua_classifier.c +++ b/src/lua/lua_classifier.c @@ -31,17 +31,20 @@ LUA_FUNCTION_DEF (classifier, register_pre_callback); LUA_FUNCTION_DEF (classifier, register_post_callback); LUA_FUNCTION_DEF (classifier, get_statfiles); +LUA_FUNCTION_DEF (classifier, get_statfile_by_label); static const struct luaL_reg classifierlib_m[] = { LUA_INTERFACE_DEF (classifier, register_pre_callback), LUA_INTERFACE_DEF (classifier, register_post_callback), LUA_INTERFACE_DEF (classifier, get_statfiles), + LUA_INTERFACE_DEF (classifier, get_statfile_by_label), {"__tostring", lua_class_tostring}, {NULL, NULL} }; LUA_FUNCTION_DEF (statfile, get_symbol); +LUA_FUNCTION_DEF (statfile, get_label); LUA_FUNCTION_DEF (statfile, get_path); LUA_FUNCTION_DEF (statfile, get_size); LUA_FUNCTION_DEF (statfile, is_spam); @@ -49,6 +52,7 @@ LUA_FUNCTION_DEF (statfile, get_param); static const struct luaL_reg statfilelib_m[] = { LUA_INTERFACE_DEF (statfile, get_symbol), + LUA_INTERFACE_DEF (statfile, get_label), LUA_INTERFACE_DEF (statfile, get_path), LUA_INTERFACE_DEF (statfile, get_size), LUA_INTERFACE_DEF (statfile, is_spam), @@ -236,7 +240,7 @@ lua_classifier_register_post_callback (lua_State *L) return 0; } -/* Return table of statfiles indexed by theirs name */ +/* Return table of statfiles indexed by name */ static gint lua_classifier_get_statfiles (lua_State *L) { @@ -267,6 +271,28 @@ lua_classifier_get_statfiles (lua_State *L) return 1; } +/* Get statfile with specified label */ +static gint +lua_classifier_get_statfile_by_label (lua_State *L) +{ + struct classifier_config *ccf = lua_check_classifier (L); + struct statfile *st, **pst; + const gchar *label; + + label = luaL_checkstring (L, 2); + if (ccf && label) { + st = g_hash_table_lookup (ccf->labels, label); + if (st) { + pst = lua_newuserdata (L, sizeof (struct statfile *)); + lua_setclass (L, "rspamd{statfile}", -1); + *pst = st; + return 1; + } + } + lua_pushnil (L); + return 1; +} + /* Statfile functions */ static gint lua_statfile_get_symbol (lua_State *L) @@ -284,6 +310,21 @@ lua_statfile_get_symbol (lua_State *L) } static gint +lua_statfile_get_label (lua_State *L) +{ + struct statfile *st = lua_check_statfile (L); + + if (st != NULL && st->label != NULL) { + lua_pushstring (L, st->label); + } + else { + lua_pushnil (L); + } + + return 1; +} + +static gint lua_statfile_get_path (lua_State *L) { struct statfile *st = lua_check_statfile (L); |