cfg.options.upstream = cfg.options.upstreams
end
+ -- fuzzy_check: max_score -> hits_limit rename with backward compatibility
+ -- If max_score is specified (e.g., from local.d overrides), it should override hits_limit
+ if cfg.fuzzy_check then
+ try_transform('fuzzy_check', function()
+ local dominated_options = function(rule)
+ -- max_score overrides hits_limit for backward compatibility
+ -- This ensures local.d overrides using legacy max_score still work
+ if rule.max_score then
+ rule.hits_limit = rule.max_score
+ rule.max_score = nil
+ end
+ -- Also transform fuzzy_map entries
+ if rule.fuzzy_map then
+ for _, map_entry in pairs(rule.fuzzy_map) do
+ if type(map_entry) == 'table' and map_entry.max_score then
+ map_entry.hits_limit = map_entry.max_score
+ map_entry.max_score = nil
+ end
+ end
+ end
+ end
+
+ if cfg.fuzzy_check.rule then
+ for _, rule in pairs(cfg.fuzzy_check.rule) do
+ if type(rule) == 'table' then
+ dominated_options(rule)
+ end
+ end
+ end
+ -- Handle case where fuzzy_check itself has these options (single rule syntax)
+ dominated_options(cfg.fuzzy_check)
+ end)
+ end
+
return ret, cfg
end
*
* Allowed options:
* - symbol (string): symbol to insert (default: 'R_FUZZY')
- * - max_score (double): maximum score to that weights of hashes would be normalized (default: 0 - no normalization)
+ * - hits_limit (double): number of fuzzy hash hits at which the normalized score reaches ~1.0 (default: 0 - no normalization)
+ * The score is calculated as tanh(e * hits / hits_limit). Legacy name: max_score
*
* - fuzzy_map (string): a string that contains map in format { fuzzy_key => [ symbol, weight ] } where fuzzy_key is number of
* fuzzy list. This string itself should be in format 1:R_FUZZY_SAMPLE1:10,2:R_FUZZY_SAMPLE2:1 etc, where first number is fuzzy
struct rspamd_cryptobox_pubkey *read_peer_key;
struct rspamd_cryptobox_keypair *write_local_key;
struct rspamd_cryptobox_pubkey *write_peer_key;
- double max_score;
+ double hits_limit;
double weight_threshold;
double html_weight; /* Weight multiplier for HTML hashes (default 1.0) */
enum fuzzy_rule_mode mode;
if (elt != NULL) {
map->fuzzy_flag = ucl_obj_toint(elt);
- elt = ucl_object_lookup(val, "max_score");
+ elt = ucl_object_lookup(val, "hits_limit");
+ if (elt == NULL) {
+ elt = ucl_object_lookup(val, "max_score");
+ }
if (elt != NULL) {
map->weight = ucl_obj_todouble(elt);
}
else {
- map->weight = rule->max_score;
+ map->weight = rule->hits_limit;
}
/* Add flag to hash table */
g_hash_table_insert(rule->mappings,
}
- if ((value = ucl_object_lookup(obj, "max_score")) != NULL) {
- rule->max_score = ucl_obj_todouble(value);
+ /* hits_limit: number of fuzzy hits at which normalized score reaches ~1.0
+ * Legacy name: max_score (supported for backward compatibility) */
+ if ((value = ucl_object_lookup(obj, "hits_limit")) != NULL) {
+ rule->hits_limit = ucl_obj_todouble(value);
+ }
+ else if ((value = ucl_object_lookup(obj, "max_score")) != NULL) {
+ rule->hits_limit = ucl_obj_todouble(value);
}
if ((value = ucl_object_lookup(obj, "retransmits")) != NULL) {
0);
rspamd_rcl_add_doc_by_path(cfg,
"fuzzy_check.rule",
- "Maximum value for fuzzy hash when weight of symbol is exactly 1.0 (if value is higher then score is still 1.0)",
- "max_score",
+ "Number of fuzzy hash hits at which the normalized score reaches ~1.0. "
+ "Score is calculated as tanh(e * hits / hits_limit). "
+ "Legacy name: max_score",
+ "hits_limit",
UCL_INT,
NULL,
0,
/* Fuzzy map doc strings */
rspamd_rcl_add_doc_by_path(cfg,
"fuzzy_check.rule.fuzzy_map",
- "Maximum score for this flag",
- "max_score",
+ "Number of fuzzy hash hits at which the normalized score reaches ~1.0 for this flag. "
+ "Legacy name: max_score",
+ "hits_limit",
UCL_INT,
NULL,
0,
GINT_TO_POINTER(rep->v1.flag))) == NULL) {
/* Default symbol and default weight */
symbol = session->rule->symbol;
- weight = session->rule->max_score;
+ weight = session->rule->hits_limit;
}
else {
/* Get symbol and weight from map */