struct metric* check_metric_conf (struct config_file *cfg, struct metric *c);
gboolean parse_normalizer (struct config_file *cfg, struct statfile *st, const gchar *line);
gboolean read_xml_config (struct config_file *cfg, const gchar *filename);
+gboolean check_modules_config (struct config_file *cfg);
#endif /* ifdef CFG_FILE_H */
/*
gboolean
read_xml_config (struct config_file *cfg, const gchar *filename)
{
- struct stat st;
+ struct stat st;
gint fd;
- gchar *data;
- gboolean res;
- GMarkupParseContext *ctx;
- GError *err = NULL;
+ gchar *data;
+ gboolean res;
+ GMarkupParseContext *ctx;
+ GError *err = NULL;
struct rspamd_xml_userdata ud;
return res;
}
+static void
+modules_config_callback (gpointer key, gpointer value, gpointer ud)
+{
+ extern GHashTable *module_options;
+ GHashTable *cur_module;
+ GList *cur;
+ struct module_opt *opt;
+ const gchar *mname = key;
+ gboolean *res = ud;
+
+ if ((cur_module = g_hash_table_lookup (module_options, mname)) == NULL) {
+ msg_warn ("module %s has not registered any options but is presented in configuration", mname);
+ *res = FALSE;
+ return;
+ }
+
+ cur = value;
+ while (cur) {
+ opt = cur->data;
+
+ if (!opt->is_lua && !check_module_option (mname, opt->param, opt->value)) {
+ *res = FALSE;
+ return;
+ }
+
+ cur = g_list_next (cur);
+ }
+}
+
+gboolean
+check_modules_config (struct config_file *cfg)
+{
+ gboolean res = TRUE;
+
+ g_hash_table_foreach (cfg->modules_opts, modules_config_callback, &res);
+ return res;
+}
+
/*
* vi:ts=4
*/
},
};
-static GHashTable *module_options = NULL,
- *worker_options = NULL,
- *classifier_options = NULL;
+GHashTable *module_options = NULL,
+ *worker_options = NULL,
+ *classifier_options = NULL;
GQuark
xml_error_quark (void)
(classifier_config = g_hash_table_lookup (classifier_options, ccf->classifier->name)) == NULL ||
(cparam = g_hash_table_lookup (classifier_config, name)) == NULL) {
msg_warn ("unregistered classifier attribute '%s' for classifier %s", name, ccf->classifier->name);
- g_hash_table_insert (ccf->opts, (char *)name, memory_pool_strdup (cfg->cfg_pool, data));
+ return FALSE;
}
else {
- return cparam->handler (cfg, ctx, attrs, data, NULL, cparam->user_data, cparam->offset);
+ g_hash_table_insert (ccf->opts, (char *)name, memory_pool_strdup (cfg->cfg_pool, data));
}
return TRUE;
/* Register handlers for specific parts of config */
/* Checker for module options */
-static gboolean
-check_module_option (struct config_file *cfg, const gchar *mname, const gchar *optname, const gchar *data)
+struct option_callback_data {
+ const gchar *optname;
+ gboolean res;
+ struct xml_config_param *param;
+};
+
+static void
+module_option_callback (gpointer key, gpointer value, gpointer ud)
+{
+ const gchar *optname = key;
+ static gchar rebuf[512];
+ struct option_callback_data *cd = ud;
+ GRegex *re;
+ GError *err = NULL;
+ gsize relen;
+
+ if (*optname == '/') {
+ relen = strcspn (optname + 1, "/");
+ if (relen > sizeof (rebuf)) {
+ relen = sizeof (rebuf);
+ }
+ rspamd_strlcpy (rebuf, optname + 1, relen);
+ /* This is a regexp so compile and check it */
+ re = g_regex_new (rebuf, G_REGEX_CASELESS, 0, &err);
+ if (err != NULL) {
+ msg_err ("failed to compile regexp for option '%s', error was: %s, regexp was: %s", cd->optname, err->message, rebuf);
+ return;
+ }
+ if (g_regex_match (re, cd->optname, 0, NULL)) {
+ cd->res = TRUE;
+ cd->param = value;
+ }
+ }
+
+ return;
+}
+
+gboolean
+check_module_option (const gchar *mname, const gchar *optname, const gchar *data)
{
struct xml_config_param *param;
enum module_opt_type type;
GHashTable *module;
gchar *err_str;
+ struct option_callback_data cd;
if (module_options == NULL) {
msg_warn ("no module options registered while checking option %s for module %s", mname, optname);
}
if ((param = g_hash_table_lookup (module, optname)) == NULL) {
- msg_warn ("module %s has not registered option %s", mname, optname);
- return FALSE;
+ /* Try to handle regexp options */
+ cd.optname = optname;
+ cd.res = FALSE;
+ g_hash_table_foreach (module, module_option_callback, &cd);
+ if (!cd.res) {
+ msg_warn ("module %s has not registered option %s", mname, optname);
+ return FALSE;
+ }
+ param = cd.param;
}
type = param->offset;
return FALSE;
}
break;
+ case MODULE_OPT_TYPE_DOUBLE:
+ (void)strtod (data, &err_str);
+ if (*err_str != '\0') {
+ msg_warn ("non-numeric data for option: '%s' for module: '%s' at position: '%s'", optname, mname, err_str);
+ return FALSE;
+ }
+ break;
case MODULE_OPT_TYPE_TIME:
(void)parse_time (data, TIME_SECONDS);
if (errno != 0) {
/* Register new classifier option */
void
-register_classifier_opt (const gchar *ctype, const gchar *optname, element_handler_func func, gpointer dest_struct, gint offset)
+register_classifier_opt (const gchar *ctype, const gchar *optname)
{
struct xml_config_param *param;
GHashTable *classifier;
if ((param = g_hash_table_lookup (classifier, optname)) == NULL) {
/* Register new param */
param = g_malloc (sizeof (struct xml_config_param));
- param->handler = func;
- param->user_data = dest_struct;
- param->offset = offset;
+ param->handler = NULL;
+ param->user_data = NULL;
+ param->offset = 0;
param->name = optname;
g_hash_table_insert (classifier, (char *)optname, param);
}
msg_warn ("replace old handler for param '%s'", optname);
g_free (param);
param = g_malloc (sizeof (struct xml_config_param));
- param->handler = func;
- param->user_data = dest_struct;
- param->offset = offset;
+ param->handler = NULL;
+ param->user_data = NULL;
+ param->offset = 0;
param->name = optname;
g_hash_table_insert (classifier, (char *)optname, param);
}
MODULE_OPT_TYPE_STRING = 0,
MODULE_OPT_TYPE_INT,
MODULE_OPT_TYPE_UINT,
+ MODULE_OPT_TYPE_DOUBLE,
MODULE_OPT_TYPE_TIME,
MODULE_OPT_TYPE_MAP,
MODULE_OPT_TYPE_SIZE,
void register_worker_opt (gint wtype, const gchar *optname, element_handler_func func, gpointer dest_struct, gint offset);
/* Register new classifier option */
-void register_classifier_opt (const gchar *ctype, const gchar *optname, element_handler_func func, gpointer dest_struct, gint offset);
+void register_classifier_opt (const gchar *ctype, const gchar *optname);
+
+/* Check validity of module option */
+gboolean check_module_option (const gchar *mname, const gchar *optname, const gchar *data);
/* Dumper functions */
gboolean xml_dump_config (struct config_file *cfg, const gchar *filename);
ctx->pool = pool;
ctx->cfg = cfg;
+
return ctx;
}
/* Init contextes */
init_workers_ctx (rspamd);
+ /* Init classifiers options */
+ register_classifier_opt ("bayes", "min_tokens");
+ register_classifier_opt ("winnow", "min_tokens");
+ register_classifier_opt ("winnow", "learn_threshold");
+
if (! load_rspamd_config (rspamd->cfg, TRUE)) {
exit (EXIT_FAILURE);
}
/* Init events to test modules */
event_init ();
res = TRUE;
+ if (!check_modules_config (rspamd->cfg)) {
+ res = FALSE;
+ }
/* Perform modules configuring */
l = g_list_first (rspamd->cfg->filters);
msg_info ("rspamd " RVERSION " is starting, build id: " RID);
rspamd->cfg->cfg_name = memory_pool_strdup (rspamd->cfg->cfg_pool, rspamd->cfg->cfg_name);
+ (void)check_modules_config (rspamd->cfg);
if (!rspamd->cfg->no_fork && daemon (0, 0) == -1) {
fprintf (stderr, "Cannot daemonize\n");
#include "../cfg_file.h"
#include "../expressions.h"
#include "../view.h"
+#include "../cfg_xml.h"
#define DEFAULT_SYMBOL "R_CHARSET_MIXED"
#define DEFAULT_THRESHOLD 0.1
chartable_module_ctx->chartable_pool = memory_pool_new (memory_pool_get_size ());
*ctx = (struct module_ctx *)chartable_module_ctx;
+ register_module_opt ("chartable", "symbol", MODULE_OPT_TYPE_STRING);
+ register_module_opt ("chartable", "threshold", MODULE_OPT_TYPE_STRING);
return 0;
}
#include "../map.h"
#include "../images.h"
#include "../fuzzy_storage.h"
+#include "../cfg_xml.h"
#define DEFAULT_SYMBOL "R_FUZZY_HASH"
#define DEFAULT_UPSTREAM_ERROR_TIME 10
fuzzy_module_ctx->mappings = g_hash_table_new (g_direct_hash, g_direct_equal);
*ctx = (struct module_ctx *)fuzzy_module_ctx;
+ /* Register module options */
+ register_module_opt ("fuzzy_check", "symbol", MODULE_OPT_TYPE_STRING);
+ register_module_opt ("fuzzy_check", "max_score", MODULE_OPT_TYPE_DOUBLE);
+ register_module_opt ("fuzzy_check", "servers", MODULE_OPT_TYPE_STRING);
+ register_module_opt ("fuzzy_check", "fuzzy_map", MODULE_OPT_TYPE_STRING);
+ register_module_opt ("fuzzy_check", "whitelist", MODULE_OPT_TYPE_STRING);
+ register_module_opt ("fuzzy_check", "mime_types", MODULE_OPT_TYPE_STRING);
+ register_module_opt ("fuzzy_check", "min_bytes", MODULE_OPT_TYPE_UINT);
+ register_module_opt ("fuzzy_check", "min_height", MODULE_OPT_TYPE_UINT);
+ register_module_opt ("fuzzy_check", "min_width", MODULE_OPT_TYPE_UINT);
+ register_module_opt ("fuzzy_check", "min_symbols", MODULE_OPT_TYPE_UINT);
return 0;
}
#include "../view.h"
#include "../lua/lua_common.h"
#include "../json/jansson.h"
+#include "../cfg_xml.h"
#define DEFAULT_STATFILE_PREFIX "./"
register_expression_function ("check_smtp_data", rspamd_check_smtp_data, NULL);
(void)luaopen_regexp (cfg->lua_state);
+ register_module_opt ("regexp", "dynamic_rules", MODULE_OPT_TYPE_STRING);
+ register_module_opt ("regexp", "/^\\S+$/", MODULE_OPT_TYPE_STRING);
return 0;
}
#include "../view.h"
#include "../map.h"
#include "../spf.h"
+#include "../cfg_xml.h"
#define DEFAULT_SYMBOL_FAIL "R_SPF_FAIL"
#define DEFAULT_SYMBOL_SOFTFAIL "R_SPF_SOFTFAIL"
spf_module_ctx->spf_pool = memory_pool_new (memory_pool_get_size ());
*ctx = (struct module_ctx *)spf_module_ctx;
+ register_module_opt ("spf", "symbol_fail", MODULE_OPT_TYPE_STRING);
+ register_module_opt ("spf", "symbol_softfail", MODULE_OPT_TYPE_STRING);
+ register_module_opt ("spf", "symbol_allow", MODULE_OPT_TYPE_STRING);
+ register_module_opt ("spf", "whitelist", MODULE_OPT_TYPE_MAP);
return 0;
}
#include "../view.h"
#include "../map.h"
#include "../dns.h"
+#include "../cfg_xml.h"
#include "surbl.h"
register_protocol_command ("urls", urls_command_handler);
/* Register module options */
+ register_module_opt ("surbl", "redirector", MODULE_OPT_TYPE_STRING);
+ register_module_opt ("surbl", "url_expire", MODULE_OPT_TYPE_TIME);
+ register_module_opt ("surbl", "redirector_connect_timeout", MODULE_OPT_TYPE_TIME);
+ register_module_opt ("surbl", "redirector_read_timeout", MODULE_OPT_TYPE_TIME);
+ register_module_opt ("surbl", "max_urls", MODULE_OPT_TYPE_UINT);
+ register_module_opt ("surbl", "redirector_hosts_map", MODULE_OPT_TYPE_STRING);
+ register_module_opt ("surbl", "exceptions", MODULE_OPT_TYPE_STRING);
+ register_module_opt ("surbl", "whitelist", MODULE_OPT_TYPE_STRING);
+ register_module_opt ("surbl", "/^suffix_.*$/", MODULE_OPT_TYPE_STRING);
+ register_module_opt ("surbl", "/^bit_.*$/", MODULE_OPT_TYPE_STRING);
return 0;
}
surbl_module_ctx->weight = DEFAULT_SURBL_WEIGHT;
}
if ((value = get_module_opt (cfg, "surbl", "url_expire")) != NULL) {
- surbl_module_ctx->url_expire = atoi (value);
+ surbl_module_ctx->url_expire = parse_time (value, TIME_SECONDS) / 1000;
}
else {
surbl_module_ctx->url_expire = DEFAULT_SURBL_URL_EXPIRE;
red_domain = g_ptr_array_index (surbl_module_ctx->redirector_ptrs, idx);
/* Try to find corresponding regexp */
re = g_hash_table_lookup (surbl_module_ctx->redirector_hosts, red_domain);
- if (re == NO_REGEXP || g_regex_match (re, url->string, 0, NULL)) {
+ if (re != NULL && (re == NO_REGEXP || g_regex_match (re, url->string, 0, NULL))) {
/* If no regexp found or founded regexp matches url string register redirector's call */
register_redirector_call (url, param->task, param->tree, param->suffix);
param->task->save.saved++;
}
}
}
+ elsif ($http_response->code != 200) {
+ _log (LOG_INFO, "HTTP response was %d, for request to %s", $http_response->code, $http_request->uri);
+ my $new_response = HTTP::Response->new($http_response->code);
+
+ # Avoid sending the response if the client has gone away.
+ $heap->{client}->put($new_response) if defined $heap->{client};
+
+ # Shut down the client's connection when the response is sent.
+ $kernel->yield("shutdown");
+ return;
+ }
my $response_type = $http_response->content_type();
if ( $response_type =~ /^text/i ) {
my $content = $http_response->decoded_content();