- now symbols inside metrics definition must be inside rules as well - symbols may be virtual (e.g. when module can insert several symbols inside callback) - symbols may be pure callbacks (when symbol's name is unknown and depends on conditions) * Module 'emails' is removed as it is not used in the current rspamd MANY fixes to sample config filestags/0.3.7
@@ -573,7 +573,6 @@ SET(CLASSIFIERSSRC src/classifiers/classifiers.c | |||
SET(PLUGINSSRC src/plugins/surbl.c | |||
src/plugins/regexp.c | |||
src/plugins/chartable.c | |||
src/plugins/emails.c | |||
src/plugins/fuzzy_check.c | |||
src/plugins/spf.c) | |||
@@ -147,7 +147,6 @@ reconf['MIME_HEADER_CTYPE_ONLY'] = string.format('!(%s) & !(%s) & (%s) & !(%s) & | |||
local msgid_dollars_ok = 'Message-Id=/[0-9a-f]{4,}\\$[0-9a-f]{4,}\\$[0-9a-f]{4,}\\@\\S+/Hr' | |||
local mimeole_ms = 'X-MimeOLE=/^Produced By Microsoft MimeOLE/H' | |||
local rcvd_with_exchange = 'Received=/with Microsoft Exchange Server/H' | |||
reconf['R_MUA_EXCHANGE'] = 'X-MimeOLE=/Microsoft Exchange/H' | |||
reconf['RATWARE_MS_HASH'] = string.format('(%s) & !(%s) & !(%s)', msgid_dollars_ok, mimeole_ms, rcvd_with_exchange) | |||
-- Reply-type in content-type |
@@ -33,12 +33,8 @@ | |||
<action>reject</action> | |||
<action>greylist:5</action> | |||
<action>add_header:5</action> | |||
<symbol weight="8.00">R_SPAM_FROM_MTU</symbol> | |||
<symbol weight="10.00">R_WWW_EKONF_COM</symbol> | |||
<symbol weight="2.00">R_TINYURL</symbol> | |||
<symbol weight="2.00">MISSING_SUBJECT</symbol> | |||
<symbol weight="2.10">FORGED_OUTLOOK_TAGS</symbol> | |||
<symbol weight="8.00">R_FAKE_THEBAT</symbol> | |||
<symbol weight="5.00">FORGED_SENDER</symbol> | |||
<symbol weight="2.00">DRUGS_MANYKINDS</symbol> | |||
<symbol weight="3.30">ADVANCE_FEE_2</symbol> | |||
@@ -54,27 +50,27 @@ | |||
<symbol weight="2.00">RCVD_DOUBLE_IP_SPAM</symbol> | |||
<symbol weight="5.50">OB_SURBL_MULTI</symbol> | |||
<symbol weight="5.00">FORGED_OUTLOOK_HTML</symbol> | |||
<symbol weight="2.00">HTML_MIME_NO_HTML_TAG</symbol> | |||
<symbol weight="10.50">R_BAD_EMAIL</symbol> | |||
<symbol weight="10.00">R_SPAM_FROM_LIBERO</symbol> | |||
<symbol weight="-2.00">WHITELIST_IP</symbol> | |||
<symbol weight="5.00">R_UNDISC_RCPT</symbol> | |||
<symbol weight="2.00">DRUGS_ANXIETY</symbol> | |||
<symbol weight="2.00">DRUGS_MUSCLE</symbol> | |||
<symbol weight="2.00">DRUGS_ANXIETY_EREC</symbol> | |||
<symbol weight="5.50">PH_SURBL_MULTI</symbol> | |||
<symbol weight="9.00">R_WHITE_ON_WHITE</symbol> | |||
<symbol weight="1.00">FAKE_HTML</symbol> | |||
<symbol weight="10.00">R_SPAM_FROM_VERSATEL</symbol> | |||
<symbol weight="3.00">HTML_SHORT_LINK_IMG_2</symbol> | |||
<symbol weight="3.00">FORGED_MUA_OUTLOOK</symbol> | |||
<symbol weight="4.00">R_FREE_HOSTING</symbol> | |||
<symbol weight="2.00">DRUGS_ERECTILE</symbol> | |||
<symbol weight="3.00">R_FREE_HOSTING_NAROD</symbol> | |||
<symbol weight="10.00">R_SPAM_FROM_ONO</symbol> | |||
<symbol weight="2.00">FM_FAKE_HELO_VERIZON</symbol> | |||
<symbol weight="2.00">REPTO_QUOTE_YAHOO</symbol> | |||
<symbol weight="5.00">MISSING_MIMEOLE</symbol> | |||
<symbol weight="0.50">RAMBLER_URIBL</symbol> | |||
<symbol weight="9.50">RAMBLER_URIBL</symbol> | |||
<symbol weight="2.00">MISSING_TO</symbol> | |||
<symbol weight="0.33">FROM_EXCESS_BASE64</symbol> | |||
<symbol weight="-5.00">FROM_WORLDBANK</symbol> | |||
<symbol weight="-5.00">FROM_CBR</symbol> | |||
<symbol weight="-5.00">FROM_CSHOP</symbol> | |||
<symbol weight="-5.00">FROM_MIRHOSTING</symbol> | |||
<symbol weight="-5.00">FROM_PASSIFLORA</symbol> | |||
<symbol weight="10.00">R_SPAM_FROM_VALUEHOST</symbol> | |||
<symbol weight="5.00">R_MIXED_CHARSET</symbol> | |||
<symbol weight="3.50">SORTED_RECIPS</symbol> | |||
@@ -83,25 +79,41 @@ | |||
<symbol weight="3.00">R_TO_SEEMS_AUTO</symbol> | |||
<symbol weight="1.00">SUBJECT_NEEDS_ENCODING</symbol> | |||
<symbol weight="3.84">TRACKER_ID</symbol> | |||
<symbol weight="7.00">KAM_LOTTO1</symbol> | |||
<symbol weight="8.00">R_LOTTO</symbol> | |||
<symbol weight="3.00">R_NO_SPACE_IN_FROM</symbol> | |||
<symbol weight="8.00">R_SAJDING</symbol> | |||
<symbol weight="6.00">R_BAD_CTE_7BIT</symbol> | |||
<symbol weight="5.50">WS_SURBL_MULTI</symbol> | |||
<symbol weight="10.00">R_POCHTA_RU</symbol> | |||
<symbol weight="10.00">R_FLASH_REDIR_IMGSHACK</symbol> | |||
<symbol weight="5.00">INVALID_MSGID</symbol> | |||
<symbol weight="8.00">R_FORGED_MPOP_WEBMAIL</symbol> | |||
<symbol weight="3.00">MISSING_MID</symbol> | |||
<symbol weight="2.00">DRUGS_DIET</symbol> | |||
<symbol weight="3.00">FORGED_RECIPIENTS</symbol> | |||
<symbol weight="2.00">RATWARE_MS_HASH</symbol> | |||
<symbol weight="5.00">HTML_TAG_BALANCE_HEAD</symbol> | |||
<symbol weight="1.00">STOX_REPLY_TYPE</symbol> | |||
<symbol weight="3.00">BAYES_SPAM</symbol> | |||
<symbol weight="-3.00">BAYES_HAM</symbol> | |||
<symbol weight="1.00">R_FUZZY</symbol> | |||
<symbol weight="1.00">R_FUZZY1</symbol> | |||
<symbol weight="1.00">R_FUZZY2</symbol> | |||
<symbol weight="1.00">R_FUZZY3</symbol> | |||
<symbol weight="3.00">R_SPF_FAIL</symbol> | |||
<symbol weight="1.00">R_SPF_SOFTFAIL</symbol> | |||
<symbol weight="-3.00">R_SPF_ALLOW</symbol> | |||
<symbol weight="-2.00">MAILLIST</symbol> | |||
<symbol weight="3.00">R_IP_PBL</symbol> | |||
<symbol weight="1.00">ONCE_RECEIVED</symbol> | |||
<symbol weight="4.00">ONCE_RECEIVED_STRICT</symbol> | |||
<symbol weight="1.00">RECEIVED_RBL</symbol> | |||
<symbol weight="3.00">R_PARTS_DIFFER</symbol> | |||
<symbol weight="2.00">MIME_HEADER_CTYPE_ONLY</symbol> | |||
<symbol weight="8.00">R_FAKE_OUTLOOK</symbol> | |||
</metric> | |||
<!-- End of factors section --> | |||
@@ -116,8 +128,8 @@ | |||
<maxfiles>2048</maxfiles> | |||
<maxcore>0</maxcore> | |||
<!-- Other params --> | |||
<param name="hashfile">/tmp/fuzzy.db</param> | |||
<param name="use_judy">yes</param> | |||
<hashfile>/tmp/fuzzy.db</hashfile> | |||
<use_judy>yes</use_judy> | |||
</worker> | |||
<worker> | |||
<type>controller</type> | |||
@@ -126,7 +138,7 @@ | |||
<maxfiles>2048</maxfiles> | |||
<maxcore>0</maxcore> | |||
<!-- Other params --> | |||
<param name="password">q1</param> | |||
<password>q1</password> | |||
</worker> | |||
<worker> | |||
<type>normal</type> | |||
@@ -141,82 +153,79 @@ | |||
<!-- Modules section --> | |||
<!-- fuzzy_check --> | |||
<module name="fuzzy_check"> | |||
<option name="servers">localhost:11335</option> | |||
<option name="symbol">R_FUZZY</option> | |||
<option name="min_length">300</option> | |||
<option name="max_score">10</option> | |||
<option name="mime_types">application/pdf</option> | |||
<option name="metric">default</option> | |||
<option name="fuzzy_map">1:R_FUZZY1:10,2:R_FUZZY2:5,3:R_FUZZY3:-2.1</option> | |||
<servers>localhost:11335</servers> | |||
<symbol>R_FUZZY</symbol> | |||
<min_bytes>300</min_bytes> | |||
<max_score>10</max_score> | |||
<mime_types>application/pdf</mime_types> | |||
<fuzzy_map>1:R_FUZZY1:10,2:R_FUZZY2:5,3:R_FUZZY3:-2.1</fuzzy_map> | |||
</module> | |||
<!-- forged_recipients --> | |||
<module name="forged_recipients"> | |||
<option name="symbol_sender">FORGED_SENDER</option> | |||
<option name="symbol_rcpt">FORGED_RECIPIENTS</option> | |||
<symbol_sender>FORGED_SENDER</symbol_sender> | |||
<symbol_rcpt>FORGED_RECIPIENTS</symbol_rcpt> | |||
</module> | |||
<!-- maillist --> | |||
<module name="maillist"> | |||
<option name="symbol">MAILLIST</option> | |||
<symbol>MAILLIST</symbol> | |||
</module> | |||
<!-- surbl --> | |||
<module name="surbl"> | |||
<option name="whitelist">file://@ETC_PREFIX@/rspamd/surbl-whitelist.inc</option> | |||
<option name="2tld">file://@ETC_PREFIX@/rspamd/2tld.inc</option> | |||
<option name="metric">default</option> | |||
<option name="bit_64">JP</option> | |||
<option name="bit_32">AB</option> | |||
<option name="bit_16">OB</option> | |||
<option name="bit_8">PH</option> | |||
<option name="bit_4">WS</option> | |||
<option name="bit_2">SC</option> | |||
<option name="suffix_RAMBLER_URIBL">uribl.rambler.ru</option> | |||
<whitelist>file://@ETC_PREFIX@/rspamd/surbl-whitelist.inc</whitelist> | |||
<exceptions>file://@ETC_PREFIX@/rspamd/2tld.inc</exceptions> | |||
<bit_64>JP</bit_64> | |||
<bit_32>AB</bit_32> | |||
<bit_16>OB</bit_16> | |||
<bit_8>PH</bit_8> | |||
<bit_4>WS</bit_4> | |||
<bit_2>SC</bit_2> | |||
<suffix_RAMBLER_URIBL>uribl.rambler.ru</suffix_RAMBLER_URIBL> | |||
<option name="suffix_%b_SURBL_MULTI">multi.surbl.org</option> | |||
<option name="redirector_read_timeout">10s</option> | |||
<option name="redirector_connect_timeout">1s</option> | |||
<option name="redirector">localhost:8080</option> | |||
<redirector_read_timeout>10s</redirector_read_timeout> | |||
<redirector_connect_timeout>1s</redirector_connect_timeout> | |||
<redirector>localhost:8080</redirector> | |||
</module> | |||
<!-- received_rbl --> | |||
<module name="received_rbl"> | |||
<option name="symbol">RECEIVED_RBL</option> | |||
<option name="rbl">pbl.spamhaus.org</option> | |||
<option name="rbl">xbl.spamhaus.org</option> | |||
<option name="rbl">insecure-bl.rambler.ru</option> | |||
<symbol>RECEIVED_RBL</symbol> | |||
<rbl>pbl.spamhaus.org</rbl> | |||
<rbl>xbl.spamhaus.org</rbl> | |||
<rbl>insecure-bl.rambler.ru</rbl> | |||
</module> | |||
<!-- whitelist --> | |||
<module name="whitelist"> | |||
<option name="ip_whitelist">http://cebka.pp.ru/stuff/grey_whitelist.conf</option> | |||
<option name="symbol_ip">WHITELIST_IP</option> | |||
<ip_whitelist>http://cebka.pp.ru/stuff/grey_whitelist.conf</ip_whitelist> | |||
<symbol_ip>WHITELIST_IP</symbol_ip> | |||
</module> | |||
<!-- chartable --> | |||
<module name="chartable"> | |||
<option name="threshold">0.1</option> | |||
<option name="symbol">R_MIXED_CHARSET</option> | |||
<option name="metric">default</option> | |||
<threshold>0.1</threshold> | |||
<symbol>R_MIXED_CHARSET</symbol> | |||
</module> | |||
<!-- once_received --> | |||
<module name="once_received"> | |||
<option name="good_host">mail</option> | |||
<option name="bad_host">static</option> | |||
<option name="bad_host">dynamic</option> | |||
<option name="symbol_strict">ONCE_RECEIVED_STRICT</option> | |||
<option name="symbol">ONCE_RECEIVED</option> | |||
<good_host>mail</good_host> | |||
<bad_host>static</bad_host> | |||
<bad_host>dynamic</bad_host> | |||
<symbol_strict>ONCE_RECEIVED_STRICT</symbol_strict> | |||
<symbol>ONCE_RECEIVED</symbol> | |||
</module> | |||
<!-- multimap --> | |||
<module name="multimap"> | |||
<!-- | |||
<option name="rule">type = header, header = To, pattern = @(.+)>?$, map = file://@ETC_PREFIX@/rspamd/rcpt_test, symbol = R_RCPT_WHITELIST</option> | |||
<option name="rule">type = ip, map = file://@ETC_PREFIX@/rspamd/ip_test, symbol = R_IP_WHITELIST</option> | |||
<rule>type = header, header = To, pattern = @(.+)>?$, map = file://@ETC_PREFIX@/rspamd/rcpt_test, symbol = R_RCPT_WHITELIST</rule> | |||
<rule>type = ip, map = file://@ETC_PREFIX@/rspamd/ip_test, symbol = R_IP_WHITELIST</rule> | |||
--> | |||
<option name="rule">type = dnsbl, map = pbl.spamhaus.org, symbol = R_IP_PBL</option> | |||
<rule>type = dnsbl, map = pbl.spamhaus.org, symbol = R_IP_PBL</rule> | |||
</module> | |||
@@ -227,7 +236,7 @@ | |||
<classifier type="winnow"> | |||
<tokenizer>osb-text</tokenizer> | |||
<metric>default</metric> | |||
<option name="min_tokens">20</option> | |||
<min_tokens>20</min_tokens> | |||
<statfile> | |||
<symbol>WINNOW_HAM</symbol> | |||
<size>100M</size> | |||
@@ -244,8 +253,8 @@ | |||
<classifier type="bayes"> | |||
<tokenizer>osb-text</tokenizer> | |||
<metric>default</metric> | |||
<option name="min_tokens">10</option> | |||
<option name="learn_threshold">0.2</option> | |||
<min_tokens>10</min_tokens> | |||
<learn_threshold>0.2</learn_threshold> | |||
<statfile> | |||
<symbol>BAYES_HAM</symbol> | |||
<size>10M</size> | |||
@@ -266,8 +275,7 @@ | |||
<classifier type="bayes"> | |||
<tokenizer>osb-text</tokenizer> | |||
<metric>default</metric> | |||
<option name="min_tokens">10</option> | |||
<option name="learn_threshold">0.2</option> | |||
<min_tokens>10</min_tokens> | |||
<statfile> | |||
<symbol>BAYES_HAM</symbol> | |||
<size>10M</size> |
@@ -417,6 +417,7 @@ 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); | |||
void insert_classifier_symbols (struct config_file *cfg); | |||
#endif /* ifdef CFG_FILE_H */ | |||
/* |
@@ -983,6 +983,20 @@ check_modules_config (struct config_file *cfg) | |||
return res; | |||
} | |||
static void | |||
symbols_classifiers_callback (gpointer key, gpointer value, gpointer ud) | |||
{ | |||
struct config_file *cfg = ud; | |||
register_virtual_symbol (&cfg->cache, key, 1.0); | |||
} | |||
void | |||
insert_classifier_symbols (struct config_file *cfg) | |||
{ | |||
g_hash_table_foreach (cfg->classifiers_symbols, symbols_classifiers_callback, cfg); | |||
} | |||
/* | |||
* vi:ts=4 | |||
*/ |
@@ -586,7 +586,7 @@ handle_log_type (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHash | |||
gchar *val; | |||
if (g_ascii_strcasecmp (data, "file") == 0) { | |||
/* Find filename attribute */ | |||
if ((val = g_hash_table_lookup (attrs, "filename")) == NULL) { | |||
if (attrs == NULL || (val = g_hash_table_lookup (attrs, "filename")) == NULL) { | |||
msg_err ("cannot log to file that is not specified"); | |||
return FALSE; | |||
} | |||
@@ -597,7 +597,7 @@ handle_log_type (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHash | |||
cfg->log_type = RSPAMD_LOG_CONSOLE; | |||
} | |||
else if (g_ascii_strcasecmp (data, "syslog") == 0) { | |||
if ((val = g_hash_table_lookup (attrs, "facility")) == NULL) { | |||
if (attrs == NULL || (val = g_hash_table_lookup (attrs, "facility")) == NULL) { | |||
msg_err ("cannot log to syslog when facility is not specified"); | |||
return FALSE; | |||
} | |||
@@ -688,13 +688,13 @@ worker_handle_param (struct config_file *cfg, struct rspamd_xml_userdata *ctx, c | |||
GHashTable *worker_config; | |||
if (g_ascii_strcasecmp (tag, "option") == 0 || g_ascii_strcasecmp (tag, "param") == 0) { | |||
if ((name = g_hash_table_lookup (attrs, "name")) == NULL) { | |||
if (attrs == NULL || (name = g_hash_table_lookup (attrs, "name")) == NULL) { | |||
msg_err ("worker param tag must have \"name\" attribute"); | |||
return FALSE; | |||
} | |||
} | |||
else { | |||
name = tag; | |||
name = memory_pool_strdup (cfg->cfg_pool, tag); | |||
} | |||
if (!worker_options || | |||
@@ -805,7 +805,7 @@ handle_metric_symbol (struct config_file *cfg, struct rspamd_xml_userdata *ctx, | |||
struct metric *metric = ctx->section_pointer; | |||
value = memory_pool_alloc (cfg->cfg_pool, sizeof (double)); | |||
if ((strval = g_hash_table_lookup (attrs, "weight")) == NULL) { | |||
if (attrs == NULL || (strval = g_hash_table_lookup (attrs, "weight")) == NULL) { | |||
msg_info ("symbol tag should have \"weight\" attribute, assume weight 1.0"); | |||
*value = 1.0; | |||
} | |||
@@ -849,11 +849,11 @@ handle_module_opt (struct config_file *cfg, struct rspamd_xml_userdata *ctx, con | |||
} | |||
} | |||
else { | |||
name = tag; | |||
name = memory_pool_strdup (cfg->cfg_pool, tag); | |||
} | |||
/* Check for lua */ | |||
if ((val = g_hash_table_lookup (attrs, "lua")) != NULL) { | |||
if (attrs != NULL && (val = g_hash_table_lookup (attrs, "lua")) != NULL) { | |||
if (g_ascii_strcasecmp (val, "yes") == 0) { | |||
is_lua = TRUE; | |||
} | |||
@@ -890,7 +890,7 @@ handle_lua (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable | |||
/* Now config table can be used for configuring rspamd */ | |||
} | |||
/* First check "src" attribute */ | |||
if ((val = g_hash_table_lookup (attrs, "src")) != NULL) { | |||
if (attrs != NULL && (val = g_hash_table_lookup (attrs, "src")) != NULL) { | |||
/* Chdir */ | |||
tmp1 = g_strdup (val); | |||
tmp2 = g_strdup (val); | |||
@@ -998,7 +998,7 @@ handle_variable (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHash | |||
{ | |||
gchar *val; | |||
if ((val = g_hash_table_lookup (attrs, "name")) == NULL) { | |||
if (attrs == NULL || (val = g_hash_table_lookup (attrs, "name")) == NULL) { | |||
msg_err ("'name' attribute is required for tag 'variable'"); | |||
return FALSE; | |||
} | |||
@@ -1013,7 +1013,7 @@ handle_composite (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHas | |||
gchar *val; | |||
struct expression *expr; | |||
if ((val = g_hash_table_lookup (attrs, "name")) == NULL) { | |||
if (attrs == NULL || (val = g_hash_table_lookup (attrs, "name")) == NULL) { | |||
msg_err ("'name' attribute is required for tag 'composite'"); | |||
return FALSE; | |||
} | |||
@@ -1136,13 +1136,13 @@ handle_classifier_opt (struct config_file *cfg, struct rspamd_xml_userdata *ctx, | |||
GHashTable *classifier_config; | |||
if (g_ascii_strcasecmp (tag, "option") == 0 || g_ascii_strcasecmp (tag, "param") == 0) { | |||
if ((name = g_hash_table_lookup (attrs, "name")) == NULL) { | |||
if (attrs == NULL || (name = g_hash_table_lookup (attrs, "name")) == NULL) { | |||
msg_err ("worker param tag must have \"name\" attribute"); | |||
return FALSE; | |||
} | |||
} | |||
else { | |||
name = tag; | |||
name = memory_pool_strdup (cfg->cfg_pool, tag); | |||
} | |||
if (!classifier_options || | |||
@@ -1376,7 +1376,7 @@ rspamd_xml_start_element (GMarkupParseContext *context, const gchar *element_nam | |||
g_queue_push_head (ud->if_stack, GSIZE_TO_POINTER ((gsize)ud->state)); | |||
/* Now get attributes */ | |||
ud->cur_attrs = process_attrs (ud->cfg, attribute_names, attribute_values); | |||
if ((condition = g_hash_table_lookup (ud->cur_attrs, "condition")) == NULL) { | |||
if (ud->cur_attrs == NULL || (condition = g_hash_table_lookup (ud->cur_attrs, "condition")) == NULL) { | |||
msg_err ("unknown condition attribute for if tag"); | |||
*error = g_error_new (xml_error_quark (), XML_PARAM_MISSING, "param 'condition' is required for tag 'if'"); | |||
ud->state = XML_ERROR; |
@@ -40,6 +40,8 @@ LUA_FUNCTION_DEF (config, add_radix_map); | |||
LUA_FUNCTION_DEF (config, add_hash_map); | |||
LUA_FUNCTION_DEF (config, get_classifier); | |||
LUA_FUNCTION_DEF (config, register_symbol); | |||
LUA_FUNCTION_DEF (config, register_virtual_symbol); | |||
LUA_FUNCTION_DEF (config, register_callback_symbol); | |||
LUA_FUNCTION_DEF (config, register_post_filter); | |||
LUA_FUNCTION_DEF (config, register_module_option); | |||
@@ -51,6 +53,8 @@ static const struct luaL_reg configlib_m[] = { | |||
LUA_INTERFACE_DEF (config, add_hash_map), | |||
LUA_INTERFACE_DEF (config, get_classifier), | |||
LUA_INTERFACE_DEF (config, register_symbol), | |||
LUA_INTERFACE_DEF (config, register_virtual_symbol), | |||
LUA_INTERFACE_DEF (config, register_callback_symbol), | |||
LUA_INTERFACE_DEF (config, register_module_option), | |||
LUA_INTERFACE_DEF (config, register_post_filter), | |||
{"__tostring", lua_class_tostring}, | |||
@@ -504,7 +508,7 @@ lua_config_register_symbol (lua_State * L) | |||
struct lua_callback_data *cd; | |||
if (cfg) { | |||
name = g_strdup (luaL_checkstring (L, 2)); | |||
name = memory_pool_strdup (cfg->cfg_pool, luaL_checkstring (L, 2)); | |||
weight = luaL_checknumber (L, 3); | |||
callback = luaL_checkstring (L, 4); | |||
if (name) { | |||
@@ -517,6 +521,45 @@ lua_config_register_symbol (lua_State * L) | |||
return 1; | |||
} | |||
static gint | |||
lua_config_register_virtual_symbol (lua_State * L) | |||
{ | |||
struct config_file *cfg = lua_check_config (L); | |||
const gchar *name; | |||
double weight; | |||
if (cfg) { | |||
name = memory_pool_strdup (cfg->cfg_pool, luaL_checkstring (L, 2)); | |||
weight = luaL_checknumber (L, 3); | |||
if (name) { | |||
register_virtual_symbol (&cfg->cache, name, weight); | |||
} | |||
} | |||
return 1; | |||
} | |||
static gint | |||
lua_config_register_callback_symbol (lua_State * L) | |||
{ | |||
struct config_file *cfg = lua_check_config (L); | |||
const gchar *name, *callback; | |||
double weight; | |||
struct lua_callback_data *cd; | |||
if (cfg) { | |||
name = memory_pool_strdup (cfg->cfg_pool, luaL_checkstring (L, 2)); | |||
weight = luaL_checknumber (L, 3); | |||
callback = luaL_checkstring (L, 4); | |||
if (name) { | |||
cd = g_malloc (sizeof (struct lua_callback_data)); | |||
cd->name = g_strdup (callback); | |||
cd->L = L; | |||
register_callback_symbol (&cfg->cache, name, weight, lua_metric_symbol_callback, cd); | |||
} | |||
} | |||
return 1; | |||
} | |||
/* Radix and hash table functions */ | |||
static gint | |||
lua_radix_get_key (lua_State * L) |
@@ -31,6 +31,7 @@ | |||
#include "map.h" | |||
#include "fuzzy_storage.h" | |||
#include "cfg_xml.h" | |||
#include "symbols_cache.h" | |||
#ifndef WITHOUT_PERL | |||
@@ -715,16 +716,20 @@ print_symbols_cache (struct config_file *cfg) | |||
cur = cfg->cache->negative_items; | |||
while (cur) { | |||
item = cur->data; | |||
printf ("-----------------------------------------------------------------\n"); | |||
printf ("| %3d | %22s | %6.1f | %9d | %9.3f |\n", i, item->s->symbol, item->s->weight, item->s->frequency, item->s->avg_time); | |||
if (!item->is_callback) { | |||
printf ("-----------------------------------------------------------------\n"); | |||
printf ("| %3d | %22s | %6.1f | %9d | %9.3f |\n", i, item->s->symbol, item->s->weight, item->s->frequency, item->s->avg_time); | |||
} | |||
cur = g_list_next (cur); | |||
i ++; | |||
} | |||
cur = cfg->cache->static_items; | |||
while (cur) { | |||
item = cur->data; | |||
printf ("-----------------------------------------------------------------\n"); | |||
printf ("| %3d | %22s | %6.1f | %9d | %9.3f |\n", i, item->s->symbol, item->s->weight, item->s->frequency, item->s->avg_time); | |||
if (!item->is_callback) { | |||
printf ("-----------------------------------------------------------------\n"); | |||
printf ("| %3d | %22s | %6.1f | %9d | %9.3f |\n", i, item->s->symbol, item->s->weight, item->s->frequency, item->s->avg_time); | |||
} | |||
cur = g_list_next (cur); | |||
i ++; | |||
} | |||
@@ -859,6 +864,12 @@ main (gint argc, gchar **argv, gchar **env) | |||
} | |||
l = g_list_next (l); | |||
} | |||
/* Insert classifiers symbols */ | |||
(void)insert_classifier_symbols (rspamd->cfg); | |||
if (! validate_cache (rspamd->cfg->cache, rspamd->cfg, TRUE)) { | |||
res = FALSE; | |||
} | |||
if (dump_vars) { | |||
dump_cfg_vars (rspamd->cfg); | |||
} | |||
@@ -917,6 +928,9 @@ main (gint argc, gchar **argv, gchar **env) | |||
/* Check configuration for modules */ | |||
(void)check_modules_config (rspamd->cfg); | |||
/* Insert classifiers symbols */ | |||
(void)insert_classifier_symbols (rspamd->cfg); | |||
/* Perform modules configuring */ | |||
l = g_list_first (rspamd->cfg->filters); | |||
@@ -933,6 +947,9 @@ main (gint argc, gchar **argv, gchar **env) | |||
/* Init config cache */ | |||
init_cfg_cache (rspamd->cfg); | |||
/* Validate cache */ | |||
(void)validate_cache (rspamd->cfg->cache, rspamd->cfg, FALSE); | |||
/* Flush log */ | |||
flush_log_buf (); | |||
@@ -1,231 +0,0 @@ | |||
/* | |||
* Copyright (c) 2009, Rambler media | |||
* All rights reserved. | |||
* | |||
* Redistribution and use in source and binary forms, with or without | |||
* modification, are permitted provided that the following conditions are met: | |||
* * Redistributions of source code must retain the above copyright | |||
* notice, this list of conditions and the following disclaimer. | |||
* * Redistributions in binary form must reproduce the above copyright | |||
* notice, this list of conditions and the following disclaimer in the | |||
* documentation and/or other materials provided with the distribution. | |||
* | |||
* THIS SOFTWARE IS PROVIDED BY Rambler media ''AS IS'' AND ANY | |||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||
* DISCLAIMED. IN NO EVENT SHALL Rambler BE LIABLE FOR ANY | |||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
*/ | |||
/***MODULE:email | |||
* rspamd module that extracts emails from messages and check them via blacklist | |||
* | |||
* Allowed options: | |||
* - symbol (string): symbol to insert (default: 'R_BAD_EMAIL') | |||
* - blacklist (map string): map that contains list of bad emails | |||
*/ | |||
#include "../config.h" | |||
#include "../main.h" | |||
#include "../message.h" | |||
#include "../modules.h" | |||
#include "../cfg_file.h" | |||
#include "../expressions.h" | |||
#include "../util.h" | |||
#include "../view.h" | |||
#include "../map.h" | |||
#define DEFAULT_SYMBOL "R_BAD_EMAIL" | |||
static const gchar *email_re_text = | |||
"[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+(?:[A-Z]{2}|com|org|net|gov|mil|biz|info|mobi|name|aero|jobs|museum)\\b"; | |||
struct email_ctx { | |||
gint (*filter) (struct worker_task * task); | |||
gchar *symbol; | |||
GRegex *email_re; | |||
GHashTable *blacklist; | |||
gchar *blacklist_file; | |||
memory_pool_t *email_pool; | |||
}; | |||
static struct email_ctx *email_module_ctx = NULL; | |||
static gint emails_mime_filter (struct worker_task *task); | |||
static void emails_symbol_callback (struct worker_task *task, void *unused); | |||
static gint emails_command_handler (struct worker_task *task); | |||
gint | |||
emails_module_init (struct config_file *cfg, struct module_ctx **ctx) | |||
{ | |||
GError *err = NULL; | |||
email_module_ctx = g_malloc (sizeof (struct email_ctx)); | |||
email_module_ctx->filter = emails_mime_filter; | |||
email_module_ctx->email_pool = memory_pool_new (memory_pool_get_size ()); | |||
email_module_ctx->email_re = g_regex_new (email_re_text, G_REGEX_RAW | G_REGEX_OPTIMIZE | G_REGEX_CASELESS, 0, &err); | |||
email_module_ctx->blacklist = g_hash_table_new (rspamd_strcase_hash, rspamd_strcase_equal); | |||
*ctx = (struct module_ctx *)email_module_ctx; | |||
register_protocol_command ("emails", emails_command_handler); | |||
return 0; | |||
} | |||
gint | |||
emails_module_config (struct config_file *cfg) | |||
{ | |||
gchar *value; | |||
gint res = TRUE; | |||
if ((value = get_module_opt (cfg, "emails", "symbol")) != NULL) { | |||
email_module_ctx->symbol = memory_pool_strdup (email_module_ctx->email_pool, value); | |||
} | |||
else { | |||
email_module_ctx->symbol = DEFAULT_SYMBOL; | |||
} | |||
if ((value = get_module_opt (cfg, "emails", "blacklist")) != NULL) { | |||
if (add_map (value, read_host_list, fin_host_list, (void **)&email_module_ctx->blacklist)) { | |||
email_module_ctx->blacklist_file = memory_pool_strdup (email_module_ctx->email_pool, value + sizeof ("file://") - 1); | |||
} | |||
} | |||
register_symbol (&cfg->cache, email_module_ctx->symbol, 1, emails_symbol_callback, NULL); | |||
return res; | |||
} | |||
gint | |||
emails_module_reconfig (struct config_file *cfg) | |||
{ | |||
memory_pool_delete (email_module_ctx->email_pool); | |||
email_module_ctx->email_pool = memory_pool_new (memory_pool_get_size ()); | |||
return emails_module_config (cfg); | |||
} | |||
static GList * | |||
extract_emails (struct worker_task *task) | |||
{ | |||
GList *res = NULL, *cur; | |||
GMatchInfo *info; | |||
GError *err = NULL; | |||
struct mime_text_part *part; | |||
gchar *email_str; | |||
gint rc; | |||
cur = g_list_first (task->text_parts); | |||
while (cur) { | |||
part = cur->data; | |||
if (part->is_empty) { | |||
cur = g_list_next (cur); | |||
continue; | |||
} | |||
rc = g_regex_match_full (email_module_ctx->email_re, (const gchar *)part->orig->data, part->orig->len, 0, 0, &info, &err); | |||
if (rc) { | |||
while (g_match_info_matches (info)) { | |||
email_str = g_match_info_fetch (info, 0); | |||
if (email_str != NULL) { | |||
res = g_list_prepend (res, email_str); | |||
memory_pool_add_destructor (task->task_pool, (pool_destruct_func) g_free, email_str); | |||
} | |||
/* Get next match */ | |||
g_match_info_next (info, &err); | |||
} | |||
} | |||
else if (err != NULL) { | |||
debug_task ("error matching regexp: %s", err->message); | |||
} | |||
else { | |||
debug_task ("cannot find url pattern in given string"); | |||
} | |||
g_match_info_free (info); | |||
cur = g_list_next (cur); | |||
} | |||
if (res != NULL) { | |||
memory_pool_add_destructor (task->task_pool, (pool_destruct_func) g_list_free, res); | |||
} | |||
return res; | |||
} | |||
static gint | |||
emails_command_handler (struct worker_task *task) | |||
{ | |||
GList *emails, *cur; | |||
gchar outbuf[BUFSIZ]; | |||
gint r, num = 0; | |||
emails = extract_emails (task); | |||
r = snprintf (outbuf, sizeof (outbuf), "%s 0 %s" CRLF, (task->proto == SPAMC_PROTO) ? SPAMD_REPLY_BANNER : RSPAMD_REPLY_BANNER, "OK"); | |||
r += snprintf (outbuf + r, sizeof (outbuf) - r - 2, "Emails: "); | |||
cur = g_list_first (emails); | |||
while (cur) { | |||
num++; | |||
if (g_list_next (cur) != NULL) { | |||
r += snprintf (outbuf + r, sizeof (outbuf) - r - 2, "%s, ", (gchar *)cur->data); | |||
} | |||
else { | |||
r += snprintf (outbuf + r, sizeof (outbuf) - r - 2, "%s", (gchar *)cur->data); | |||
} | |||
cur = g_list_next (cur); | |||
} | |||
outbuf[r++] = '\r'; | |||
outbuf[r++] = '\n'; | |||
if (! rspamd_dispatcher_write (task->dispatcher, outbuf, r, FALSE, FALSE)) { | |||
return -1; | |||
} | |||
msg_info ("msg ok, id: <%s>, %d emails extracted", task->message_id, num); | |||
return 0; | |||
} | |||
static void | |||
emails_symbol_callback (struct worker_task *task, void *unused) | |||
{ | |||
GList *emails, *cur; | |||
if (check_view (task->cfg->views, email_module_ctx->symbol, task)) { | |||
emails = extract_emails (task); | |||
if (email_module_ctx->blacklist && emails) { | |||
cur = g_list_first (emails); | |||
while (cur) { | |||
if (g_hash_table_lookup (email_module_ctx->blacklist, cur->data) != NULL) { | |||
insert_result (task, email_module_ctx->symbol, 1, g_list_prepend (NULL, memory_pool_strdup (task->task_pool, (gchar *)cur->data))); | |||
} | |||
cur = g_list_next (cur); | |||
} | |||
} | |||
} | |||
} | |||
static gint | |||
emails_mime_filter (struct worker_task *task) | |||
{ | |||
/* XXX: remove this */ | |||
return 0; | |||
} |
@@ -128,7 +128,7 @@ static void fuzzy_delete_handler (gchar **args, struct contr | |||
/* Flags string is in format <numeric_flag>:<SYMBOL>:weight[, <numeric_flag>:<SYMBOL>:weight...] */ | |||
static void | |||
parse_flags_string (gchar *str) | |||
parse_flags_string (struct config_file *cfg, gchar *str) | |||
{ | |||
gchar **strvec, *item, *err_str, **map_str; | |||
gint num, i, t; | |||
@@ -152,6 +152,7 @@ parse_flags_string (gchar *str) | |||
map->fuzzy_flag = strtol (map_str[0], &err_str, 10); | |||
if (errno != 0 || (err_str && *err_str != '\0')) { | |||
msg_info ("cannot parse flag %s: %s", map_str[0], strerror (errno)); | |||
continue; | |||
} | |||
else if (t == 2) { | |||
/* Weight is skipped in definition */ | |||
@@ -159,9 +160,11 @@ parse_flags_string (gchar *str) | |||
} | |||
else { | |||
map->weight = strtol (map_str[2], &err_str, 10); | |||
/* Add flag to hash table */ | |||
g_hash_table_insert (fuzzy_module_ctx->mappings, GINT_TO_POINTER(map->fuzzy_flag), map); | |||
} | |||
/* Add flag to hash table */ | |||
g_hash_table_insert (fuzzy_module_ctx->mappings, GINT_TO_POINTER(map->fuzzy_flag), map); | |||
register_virtual_symbol (&cfg->cache, map->symbol, map->weight); | |||
} | |||
g_strfreev (map_str); | |||
} | |||
@@ -407,7 +410,7 @@ fuzzy_check_module_config (struct config_file *cfg) | |||
parse_servers_string (value); | |||
} | |||
if ((value = get_module_opt (cfg, "fuzzy_check", "fuzzy_map")) != NULL) { | |||
parse_flags_string (value); | |||
parse_flags_string (cfg, value); | |||
} | |||
register_symbol (&cfg->cache, fuzzy_module_ctx->symbol, fuzzy_module_ctx->max_score, fuzzy_symbol_callback, NULL); |
@@ -73,10 +73,13 @@ if opts then | |||
if opts['symbol_rcpt'] or opts['symbol_sender'] then | |||
if opts['symbol_rcpt'] then | |||
symbol_rcpt = opts['symbol_rcpt'] | |||
rspamd_config:register_virtual_symbol(symbol_rcpt, 1.0, 'check_forged_headers') | |||
end | |||
if opts['symbol_sender'] then | |||
symbol_sender = opts['symbol_sender'] | |||
rspamd_config:register_virtual_symbol(symbol_sender, 1.0) | |||
end | |||
rspamd_config:register_symbol(symbol_rcpt, 1.0, 'check_forged_headers') | |||
rspamd_config:register_callback_symbol('FORGED_RECIPIENTS', 1.0, 'check_forged_headers') | |||
end | |||
end |
@@ -89,7 +89,7 @@ function add_rule(params) | |||
local _,_,name,value = string.find(param, '(%w+)%s*=%s*(.+)') | |||
if not name or not value then | |||
rspamd_logger:err('invalid rule: '..param) | |||
return 0 | |||
return nil | |||
end | |||
if name == 'type' then | |||
if value == 'ip' then | |||
@@ -100,7 +100,7 @@ function add_rule(params) | |||
newrule['type'] = 'header' | |||
else | |||
rspamd_logger:err('invalid rule type: '.. value) | |||
return 0 | |||
return nil | |||
end | |||
elseif name == 'header' then | |||
newrule['header'] = value | |||
@@ -112,13 +112,13 @@ function add_rule(params) | |||
newrule['symbol'] = value | |||
else | |||
rspamd_logger:err('invalid rule option: '.. name) | |||
return 0 | |||
return nil | |||
end | |||
end | |||
if not newrule['symbol'] or not newrule['map'] or not newrule['symbol'] then | |||
rspamd_logger:err('incomplete rule') | |||
return 0 | |||
return nil | |||
end | |||
if newrule['type'] == 'ip' then | |||
newrule['ips'] = rspamd_config:add_radix_map (newrule['map']) | |||
@@ -126,7 +126,7 @@ function add_rule(params) | |||
newrule['hash'] = rspamd_config:add_hash_map (newrule['map']) | |||
end | |||
table.insert(rules, newrule) | |||
return 1 | |||
return newrule | |||
end | |||
-- Registration | |||
@@ -139,14 +139,20 @@ if opts then | |||
if type(strrules) == 'table' then | |||
for _,value in ipairs(strrules) do | |||
local params = split(value, ',') | |||
if not add_rule (params) then | |||
local rule = add_rule (params) | |||
if not rule then | |||
rspamd_logger:err('cannot add rule: "'..value..'"') | |||
else | |||
rspamd_config:register_virtual_symbol(rule['symbol'], 1.0) | |||
end | |||
end | |||
elseif type(strrules) == 'string' then | |||
local params = split(strrules, ',') | |||
if not add_rule (params) then | |||
local rule = add_rule (params) | |||
if not rule then | |||
rspamd_logger:err('cannot add rule: "'..strrules..'"') | |||
else | |||
rspamd_config:register_virtual_symbol(rule['symbol'], 1.0) | |||
end | |||
end | |||
end | |||
@@ -154,5 +160,5 @@ end | |||
if table.maxn(rules) > 0 then | |||
-- add fake symbol to check all maps inside a single callback | |||
rspamd_config:register_symbol('MULTIMAP', 1.0, 'check_multimap') | |||
rspamd_config:register_callback_symbol('MULTIMAP', 1.0, 'check_multimap') | |||
end |
@@ -59,6 +59,7 @@ if opts then | |||
for n,v in pairs(opts) do | |||
if n == 'symbol_strict' then | |||
symbol_strict = v | |||
rspamd_config:register_virtual_symbol(symbol_strict, 1.0) | |||
elseif n == 'bad_host' then | |||
bad_hosts = v | |||
elseif n == 'good_host' then |
@@ -112,6 +112,8 @@ spf_module_config (struct config_file *cfg) | |||
} | |||
register_symbol (&cfg->cache, spf_module_ctx->symbol_fail, 1, spf_symbol_callback, NULL); | |||
register_virtual_symbol (&cfg->cache, spf_module_ctx->symbol_softfail, 1); | |||
register_virtual_symbol (&cfg->cache, spf_module_ctx->symbol_allow, 1); | |||
return res; | |||
} |
@@ -240,6 +240,42 @@ surbl_module_init (struct config_file *cfg, struct module_ctx **ctx) | |||
return 0; | |||
} | |||
/* | |||
* Register virtual symbols for suffixes with bit wildcard | |||
*/ | |||
static void | |||
register_bit_symbols (struct config_file *cfg) | |||
{ | |||
gchar *c, *symbol; | |||
GList *symit, *cur; | |||
struct surbl_bit_item *bit; | |||
struct suffix_item *suffix; | |||
gint len; | |||
symit = surbl_module_ctx->suffixes; | |||
while (symit) { | |||
suffix = symit->data; | |||
if ((c = strchr (suffix->symbol, '%')) != NULL && *(c + 1) == 'b') { | |||
cur = g_list_first (surbl_module_ctx->bits); | |||
while (cur) { | |||
bit = (struct surbl_bit_item *)cur->data; | |||
len = strlen (suffix->symbol) - 2 + strlen (bit->symbol) + 1; | |||
*c = '\0'; | |||
symbol = memory_pool_alloc (cfg->cfg_pool, len); | |||
rspamd_snprintf (symbol, len, "%s%s%s", suffix->symbol, bit->symbol, c + 2); | |||
*c = '%'; | |||
register_virtual_symbol (&cfg->cache, symbol, 1); | |||
cur = g_list_next (cur); | |||
} | |||
} | |||
else { | |||
register_virtual_symbol (&cfg->cache, suffix->symbol, 1); | |||
} | |||
symit = g_list_next (symit); | |||
} | |||
} | |||
gint | |||
surbl_module_config (struct config_file *cfg) | |||
{ | |||
@@ -339,7 +375,7 @@ surbl_module_config (struct config_file *cfg) | |||
msg_debug ("add new surbl suffix: %s with symbol: %s", new_suffix->suffix, new_suffix->symbol); | |||
*str = '_'; | |||
surbl_module_ctx->suffixes = g_list_prepend (surbl_module_ctx->suffixes, new_suffix); | |||
register_symbol (&cfg->cache, new_suffix->symbol, 1, surbl_test_url, new_suffix); | |||
register_callback_symbol (&cfg->cache, new_suffix->symbol, 1, surbl_test_url, new_suffix); | |||
} | |||
} | |||
if (!g_strncasecmp (cur->param, "bit", sizeof ("bit") - 1)) { | |||
@@ -366,6 +402,8 @@ surbl_module_config (struct config_file *cfg) | |||
register_symbol (&cfg->cache, new_suffix->symbol, 1, surbl_test_url, new_suffix); | |||
} | |||
register_bit_symbols (cfg); | |||
return TRUE; | |||
} | |||
@@ -243,8 +243,15 @@ create_cache_file (struct symbols_cache *cache, const gchar *filename, gint fd, | |||
return mmap_cache_file (cache, fd, pool); | |||
} | |||
void | |||
register_symbol (struct symbols_cache **cache, const gchar *name, double weight, symbol_func_t func, gpointer user_data) | |||
enum rspamd_symbol_type { | |||
SYMBOL_TYPE_NORMAL, | |||
SYMBOL_TYPE_VIRTUAL, | |||
SYMBOL_TYPE_CALLBACK | |||
}; | |||
static void | |||
register_symbol_common (struct symbols_cache **cache, const gchar *name, double weight, | |||
symbol_func_t func, gpointer user_data, enum rspamd_symbol_type type) | |||
{ | |||
struct cache_item *item = NULL; | |||
struct symbols_cache *pcache = *cache; | |||
@@ -271,6 +278,17 @@ register_symbol (struct symbols_cache **cache, const gchar *name, double weight, | |||
item->func = func; | |||
item->user_data = user_data; | |||
switch (type) { | |||
case SYMBOL_TYPE_NORMAL: | |||
break; | |||
case SYMBOL_TYPE_VIRTUAL: | |||
item->is_virtual = TRUE; | |||
break; | |||
case SYMBOL_TYPE_CALLBACK: | |||
item->is_callback = TRUE; | |||
break; | |||
} | |||
/* Handle weight using default metric */ | |||
if (pcache->cfg && pcache->cfg->default_metric && (w = g_hash_table_lookup (pcache->cfg->default_metric->symbols, name)) != NULL) { | |||
item->s->weight = weight * (*w); | |||
@@ -285,6 +303,26 @@ register_symbol (struct symbols_cache **cache, const gchar *name, double weight, | |||
*target = g_list_prepend (*target, item); | |||
} | |||
void | |||
register_symbol (struct symbols_cache **cache, const gchar *name, double weight, | |||
symbol_func_t func, gpointer user_data) | |||
{ | |||
register_symbol_common (cache, name, weight, func, user_data, SYMBOL_TYPE_NORMAL); | |||
} | |||
void | |||
register_virtual_symbol (struct symbols_cache **cache, const gchar *name, double weight) | |||
{ | |||
register_symbol_common (cache, name, weight, NULL, NULL, SYMBOL_TYPE_VIRTUAL); | |||
} | |||
void | |||
register_callback_symbol (struct symbols_cache **cache, const gchar *name, double weight, | |||
symbol_func_t func, gpointer user_data) | |||
{ | |||
register_symbol_common (cache, name, weight, func, user_data, SYMBOL_TYPE_CALLBACK); | |||
} | |||
void | |||
register_dynamic_symbol (memory_pool_t *dynamic_pool, struct symbols_cache **cache, | |||
const gchar *name, double weight, symbol_func_t func, | |||
@@ -501,6 +539,17 @@ init_symbols_cache (memory_pool_t * pool, struct symbols_cache *cache, struct co | |||
g_checksum_get_digest (cksum, mem_sum, &cklen); | |||
/* Now try to read file sum */ | |||
if (lseek (fd, -(cklen), SEEK_END) == -1) { | |||
if (errno == EINVAL) { | |||
/* Try to create file */ | |||
msg_info ("recreate cache file"); | |||
if ((fd = open (filename, O_RDWR | O_TRUNC | O_CREAT, S_IWUSR | S_IRUSR)) == -1) { | |||
msg_info ("cannot create file %s, error %d, %s", filename, errno, strerror (errno)); | |||
return FALSE; | |||
} | |||
else { | |||
return create_cache_file (cache, filename, fd, pool); | |||
} | |||
} | |||
close (fd); | |||
g_free (mem_sum); | |||
g_checksum_free (cksum); | |||
@@ -598,6 +647,89 @@ check_debug_symbol (struct config_file *cfg, const gchar *symbol) | |||
return FALSE; | |||
} | |||
gboolean | |||
validate_cache (struct symbols_cache *cache, struct config_file *cfg, gboolean strict) | |||
{ | |||
struct cache_item *item; | |||
GList *cur, *p, *metric_symbols; | |||
gboolean res; | |||
if (cache == NULL) { | |||
msg_err ("empty cache is invalid"); | |||
return FALSE; | |||
} | |||
/* Check each symbol in a cache and find its weight definition */ | |||
cur = cache->negative_items; | |||
while (cur) { | |||
item = cur->data; | |||
if (!item->is_callback) { | |||
if (g_hash_table_lookup (cfg->metrics_symbols, item->s->symbol) == NULL) { | |||
if (strict) { | |||
msg_warn ("no weight registered for symbol %s", item->s->symbol); | |||
return FALSE; | |||
} | |||
else { | |||
msg_info ("no weight registered for symbol %s", item->s->symbol); | |||
} | |||
} | |||
} | |||
cur = g_list_next (cur); | |||
} | |||
cur = cache->static_items; | |||
while (cur) { | |||
item = cur->data; | |||
if (!item->is_callback) { | |||
if (g_hash_table_lookup (cfg->metrics_symbols, item->s->symbol) == NULL) { | |||
if (strict) { | |||
msg_warn ("no weight registered for symbol %s", item->s->symbol); | |||
return FALSE; | |||
} | |||
else { | |||
msg_info ("no weight registered for symbol %s", item->s->symbol); | |||
} | |||
} | |||
} | |||
cur = g_list_next (cur); | |||
} | |||
/* Now check each metric item and find corresponding symbol in a cache */ | |||
metric_symbols = g_hash_table_get_keys (cfg->metrics_symbols); | |||
cur = metric_symbols; | |||
while (cur) { | |||
res = FALSE; | |||
p = cache->negative_items; | |||
while (p) { | |||
item = p->data; | |||
if (strcmp (item->s->symbol, cur->data) == 0) { | |||
res = TRUE; | |||
break; | |||
} | |||
p = g_list_next (p); | |||
} | |||
if (!res) { | |||
p = cache->static_items; | |||
while (p) { | |||
item = p->data; | |||
if (strcmp (item->s->symbol, cur->data) == 0) { | |||
res = TRUE; | |||
break; | |||
} | |||
p = g_list_next (p); | |||
} | |||
} | |||
if (!res) { | |||
msg_warn ("symbol '%s' is registered in metric but not found in cache", cur->data); | |||
if (strict) { | |||
return FALSE; | |||
} | |||
} | |||
cur = g_list_next (cur); | |||
} | |||
return TRUE; | |||
} | |||
struct symbol_callback_data { | |||
enum { | |||
CACHE_STATE_NEGATIVE, | |||
@@ -772,7 +904,7 @@ call_symbol_callback (struct worker_task * task, struct symbols_cache * cache, g | |||
if (!item) { | |||
return FALSE; | |||
} | |||
if (check_view (task->cfg->views, item->s->symbol, task)) { | |||
if (!item->is_virtual && check_view (task->cfg->views, item->s->symbol, task)) { | |||
#ifdef HAVE_CLOCK_GETTIME | |||
# ifdef HAVE_CLOCK_PROCESS_CPUTIME_ID | |||
clock_gettime (CLOCK_PROCESS_CPUTIME_ID, &ts1); |
@@ -36,6 +36,10 @@ struct cache_item { | |||
/* Callback data */ | |||
symbol_func_t func; | |||
gpointer user_data; | |||
/* Flags of virtual symbols */ | |||
gboolean is_virtual; | |||
gboolean is_callback; | |||
}; | |||
@@ -76,6 +80,20 @@ gboolean init_symbols_cache (memory_pool_t *pool, struct symbols_cache *cache, s | |||
*/ | |||
void register_symbol (struct symbols_cache **cache, const gchar *name, double weight, symbol_func_t func, gpointer user_data); | |||
/** | |||
* Register virtual symbol | |||
* @param name name of symbol | |||
*/ | |||
void register_virtual_symbol (struct symbols_cache **cache, const gchar *name, double weight); | |||
/** | |||
* Register callback function for symbols parsing | |||
* @param name name of symbol | |||
* @param func pointer to handler | |||
* @param user_data pointer to user_data | |||
*/ | |||
void register_callback_symbol (struct symbols_cache **cache, const gchar *name, double weight, symbol_func_t func, gpointer user_data); | |||
/** | |||
* Register function for dynamic symbols parsing | |||
* @param name name of symbol | |||
@@ -100,5 +118,13 @@ gboolean call_symbol_callback (struct worker_task *task, struct symbols_cache *c | |||
*/ | |||
void remove_dynamic_rules (struct symbols_cache *cache); | |||
/** | |||
* Validate cache items agains theirs weights defined in metrics | |||
* @param cache symbols cache | |||
* @param cfg configuration | |||
* @param strict do strict checks - symbols MUST be described in metrics | |||
*/ | |||
gboolean validate_cache (struct symbols_cache *cache, struct config_file *cfg, gboolean strict); | |||
#endif |