aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/libmime/scan_result.c5
-rw-r--r--src/libmime/scan_result.h2
-rw-r--r--src/libserver/composites.c173
-rw-r--r--src/libserver/dkim.c47
-rw-r--r--src/libserver/task.c10
-rw-r--r--test/lua/unit/rspamd_resolver.lua31
6 files changed, 182 insertions, 86 deletions
diff --git a/src/libmime/scan_result.c b/src/libmime/scan_result.c
index 7b92510ca..1a2d96d83 100644
--- a/src/libmime/scan_result.c
+++ b/src/libmime/scan_result.c
@@ -158,6 +158,8 @@ rspamd_add_passthrough_result (struct rspamd_task *task, struct rspamd_action *a
flags & RSPAMD_PASSTHROUGH_LEAST ? "*least " : "",
message, module, priority);
}
+
+ scan_result->nresults ++;
}
static inline gdouble
@@ -474,6 +476,7 @@ insert_metric_result (struct rspamd_task *task,
symbol,
s->score,
final_score);
+ metric_res->nresults ++;
return s;
}
@@ -730,6 +733,8 @@ rspamd_task_add_result_option (struct rspamd_task *task,
ret = TRUE;
}
+ task->result->nresults ++;
+
return ret;
}
diff --git a/src/libmime/scan_result.h b/src/libmime/scan_result.h
index d82699a91..c2b1088da 100644
--- a/src/libmime/scan_result.h
+++ b/src/libmime/scan_result.h
@@ -89,6 +89,8 @@ struct rspamd_scan_result {
guint nactions;
guint npositive;
guint nnegative;
+ guint nresults; /**< all results: positive, negative, passthrough etc */
+ guint nresults_postfilters; /**< how many results are there before postfilters stage */
struct rspamd_scan_result *prev, *next; /**< double linked list of results */
};
diff --git a/src/libserver/composites.c b/src/libserver/composites.c
index 3ec770439..926d3fd2c 100644
--- a/src/libserver/composites.c
+++ b/src/libserver/composites.c
@@ -66,6 +66,13 @@ struct rspamd_composite_option_match {
struct rspamd_composite_atom {
gchar *symbol;
+ enum {
+ ATOM_UNKNOWN,
+ ATOM_COMPOSITE,
+ ATOM_PLAIN
+ } comp_type;
+
+ struct rspamd_composite *ncomp; /* underlying composite */
struct rspamd_composite_option_match *opts;
};
@@ -217,6 +224,7 @@ rspamd_composite_expr_parse (const gchar *line, gsize len,
state = comp_state_read_symbol;
atom = rspamd_mempool_alloc0 (pool, sizeof (*atom));
+ atom->comp_type = ATOM_UNKNOWN;
res = rspamd_mempool_alloc0 (pool, sizeof (*res));
res->len = clen;
res->str = line;
@@ -383,20 +391,31 @@ rspamd_composite_process_single_symbol (struct composites_data *cd,
{
struct rspamd_symbol_result *ms = NULL;
gdouble rc = 0;
- struct rspamd_composite *ncomp;
struct rspamd_task *task = cd->task;
if ((ms = rspamd_task_find_symbol_result (cd->task, sym, cd->metric_res)) == NULL) {
msg_debug_composites ("not found symbol %s in composite %s", sym,
cd->composite->sym);
- if ((ncomp =
- g_hash_table_lookup (cd->task->cfg->composite_symbols,
- sym)) != NULL) {
+ if (atom->comp_type == ATOM_UNKNOWN) {
+ struct rspamd_composite *ncomp;
+
+ if ((ncomp =
+ g_hash_table_lookup (cd->task->cfg->composite_symbols,
+ sym)) != NULL) {
+ atom->comp_type = ATOM_COMPOSITE;
+ atom->ncomp = ncomp;
+ }
+ else {
+ atom->comp_type = ATOM_PLAIN;
+ }
+ }
+
+ if (atom->comp_type == ATOM_COMPOSITE) {
msg_debug_composites ("symbol %s for composite %s is another composite",
sym, cd->composite->sym);
- if (isclr (cd->checked, ncomp->id * 2)) {
+ if (isclr (cd->checked, atom->ncomp->id * 2)) {
struct rspamd_composite *saved;
msg_debug_composites ("composite dependency %s for %s is not checked",
@@ -404,7 +423,7 @@ rspamd_composite_process_single_symbol (struct composites_data *cd,
/* Set checked for this symbol to avoid cyclic references */
setbit (cd->checked, cd->composite->id * 2);
saved = cd->composite; /* Save the current composite */
- composites_foreach_callback ((gpointer)ncomp->sym, ncomp, cd);
+ composites_foreach_callback ((gpointer)atom->ncomp->sym, atom->ncomp, cd);
/* Restore state */
cd->composite = saved;
@@ -417,7 +436,7 @@ rspamd_composite_process_single_symbol (struct composites_data *cd,
/*
* XXX: in case of cyclic references this would return 0
*/
- if (isset (cd->checked, ncomp->id * 2 + 1)) {
+ if (isset (cd->checked, atom->ncomp->id * 2 + 1)) {
ms = rspamd_task_find_symbol_result (cd->task, sym,
cd->metric_res);
}
@@ -611,51 +630,23 @@ rspamd_composite_expr_process (void *ud,
}
sym = comp_atom->symbol;
+ guint slen = strlen (sym);
while (*sym != '\0' && !g_ascii_isalnum (*sym)) {
sym ++;
+ slen --;
}
- if (strncmp (sym, "g:", 2) == 0) {
- gr = g_hash_table_lookup (cd->task->cfg->groups, sym + 2);
-
- if (gr != NULL) {
- g_hash_table_iter_init (&it, gr->symbols);
+ if (slen > 2) {
+ if (G_UNLIKELY (memcmp (sym, "g:", 2) == 0)) {
+ gr = g_hash_table_lookup (cd->task->cfg->groups, sym + 2);
- while (g_hash_table_iter_next (&it, &k, &v)) {
- sdef = v;
- rc = rspamd_composite_process_single_symbol (cd, sdef->name, &ms,
- comp_atom);
+ if (gr != NULL) {
+ g_hash_table_iter_init (&it, gr->symbols);
- if (rc) {
- rspamd_composite_process_symbol_removal (atom,
- cd,
- ms,
- comp_atom->symbol);
-
- if (fabs (rc) > max) {
- max = fabs (rc);
- }
- }
- }
- }
-
- rc = max;
- }
- else if (strncmp (sym, "g+:", 3) == 0) {
- /* Group, positive symbols only */
- gr = g_hash_table_lookup (cd->task->cfg->groups, sym + 3);
-
- if (gr != NULL) {
- g_hash_table_iter_init (&it, gr->symbols);
-
- while (g_hash_table_iter_next (&it, &k, &v)) {
- sdef = v;
-
- if (sdef->score > 0) {
- rc = rspamd_composite_process_single_symbol (cd,
- sdef->name,
- &ms,
+ while (g_hash_table_iter_next (&it, &k, &v)) {
+ sdef = v;
+ rc = rspamd_composite_process_single_symbol (cd, sdef->name, &ms,
comp_atom);
if (rc) {
@@ -673,37 +664,79 @@ rspamd_composite_expr_process (void *ud,
rc = max;
}
- }
- else if (strncmp (sym, "g-:", 3) == 0) {
- /* Group, negative symbols only */
- gr = g_hash_table_lookup (cd->task->cfg->groups, sym + 3);
-
- if (gr != NULL) {
- g_hash_table_iter_init (&it, gr->symbols);
-
- while (g_hash_table_iter_next (&it, &k, &v)) {
- sdef = v;
-
- if (sdef->score < 0) {
- rc = rspamd_composite_process_single_symbol (cd,
- sdef->name,
- &ms,
- comp_atom);
-
- if (rc) {
- rspamd_composite_process_symbol_removal (atom,
- cd,
- ms,
- comp_atom->symbol);
+ else if (G_UNLIKELY (memcmp (sym, "g+:", 3) == 0)) {
+ /* Group, positive symbols only */
+ gr = g_hash_table_lookup (cd->task->cfg->groups, sym + 3);
+
+ if (gr != NULL) {
+ g_hash_table_iter_init (&it, gr->symbols);
+
+ while (g_hash_table_iter_next (&it, &k, &v)) {
+ sdef = v;
+
+ if (sdef->score > 0) {
+ rc = rspamd_composite_process_single_symbol (cd,
+ sdef->name,
+ &ms,
+ comp_atom);
+
+ if (rc) {
+ rspamd_composite_process_symbol_removal (atom,
+ cd,
+ ms,
+ comp_atom->symbol);
+
+ if (fabs (rc) > max) {
+ max = fabs (rc);
+ }
+ }
+ }
+ }
- if (fabs (rc) > max) {
- max = fabs (rc);
+ rc = max;
+ }
+ }
+ else if (G_UNLIKELY (memcmp (sym, "g-:", 3) == 0)) {
+ /* Group, negative symbols only */
+ gr = g_hash_table_lookup (cd->task->cfg->groups, sym + 3);
+
+ if (gr != NULL) {
+ g_hash_table_iter_init (&it, gr->symbols);
+
+ while (g_hash_table_iter_next (&it, &k, &v)) {
+ sdef = v;
+
+ if (sdef->score < 0) {
+ rc = rspamd_composite_process_single_symbol (cd,
+ sdef->name,
+ &ms,
+ comp_atom);
+
+ if (rc) {
+ rspamd_composite_process_symbol_removal (atom,
+ cd,
+ ms,
+ comp_atom->symbol);
+
+ if (fabs (rc) > max) {
+ max = fabs (rc);
+ }
}
}
}
+
+ rc = max;
}
+ }
+ else {
+ rc = rspamd_composite_process_single_symbol (cd, sym, &ms, comp_atom);
- rc = max;
+ if (rc) {
+ rspamd_composite_process_symbol_removal (atom,
+ cd,
+ ms,
+ comp_atom->symbol);
+ }
}
}
else {
diff --git a/src/libserver/dkim.c b/src/libserver/dkim.c
index bad423c19..f6274a3d6 100644
--- a/src/libserver/dkim.c
+++ b/src/libserver/dkim.c
@@ -1693,11 +1693,11 @@ rspamd_dkim_relaxed_body_step (struct rspamd_dkim_common_ctx *ctx, EVP_MD_CTX *c
gssize *remain)
{
const gchar *h;
- static gchar buf[BUFSIZ];
gchar *t;
guint len, inlen;
gssize octets_remain;
gboolean got_sp;
+ gchar buf[1024];
len = size;
inlen = sizeof (buf) - 1;
@@ -1707,6 +1707,7 @@ rspamd_dkim_relaxed_body_step (struct rspamd_dkim_common_ctx *ctx, EVP_MD_CTX *c
octets_remain = *remain;
while (len > 0 && inlen > 0 && (octets_remain != 0)) {
+
if (*h == '\r' || *h == '\n') {
if (got_sp) {
/* Ignore spaces at the end of line */
@@ -1768,8 +1769,8 @@ rspamd_dkim_relaxed_body_step (struct rspamd_dkim_common_ctx *ctx, EVP_MD_CTX *c
EVP_DigestUpdate (ck, buf, cklen);
ctx->body_canonicalised += cklen;
msg_debug_dkim ("relaxed update signature with body buffer "
- "(%z size, %z -> %z remain); %*s",
- cklen, *remain, octets_remain, (int)cklen, buf);
+ "(%z size, %z -> %z remain)",
+ cklen, *remain, octets_remain);
*remain = octets_remain;
}
@@ -1783,49 +1784,67 @@ rspamd_dkim_simple_body_step (struct rspamd_dkim_common_ctx *ctx,
gssize *remain)
{
const gchar *h;
- static gchar buf[BUFSIZ];
gchar *t;
- guint len, inlen, added = 0;
+ guint len, inlen;
+ gssize octets_remain;
+ gchar buf[1024];
len = size;
inlen = sizeof (buf) - 1;
h = *start;
t = &buf[0];
+ octets_remain = *remain;
- while (len && inlen) {
+ while (len > 0 && inlen > 0 && (octets_remain != 0)) {
if (*h == '\r' || *h == '\n') {
*t++ = '\r';
*t++ = '\n';
+
if (len > 1 && (*h == '\r' && h[1] == '\n')) {
h += 2;
len -= 2;
+
+ if (octets_remain >= 2) {
+ octets_remain -= 2; /* Input has just \n or \r so we actually add more octets */
+ }
+ else {
+ octets_remain --;
+ }
}
else {
h ++;
len --;
- added ++;
+
+ if (octets_remain >= 2) {
+ octets_remain -= 2; /* Input has just \n or \r so we actually add more octets */
+ }
+ else {
+ octets_remain --;
+ }
}
break;
}
+
*t++ = *h++;
+ octets_remain --;
inlen--;
len--;
}
*start = h;
- if (*remain != 0) {
- gsize cklen = MIN(t - buf, *remain + added);
+ if (t - buf > 0) {
+ gsize cklen = t - buf;
EVP_DigestUpdate (ck, buf, cklen);
ctx->body_canonicalised += cklen;
- *remain = *remain - (cklen - added);
- msg_debug_dkim ("update signature with body buffer "
- "(%z size, %z remain, %ud added)",
- cklen, *remain, added);
+ msg_debug_dkim ("simple update signature with body buffer "
+ "(%z size, %z -> %z remain)",
+ cklen, *remain, octets_remain);
+ *remain = octets_remain;
}
- return (len != 0);
+ return ((len != 0) && (octets_remain != 0));
}
static const gchar *
diff --git a/src/libserver/task.c b/src/libserver/task.c
index 80216537f..096933803 100644
--- a/src/libserver/task.c
+++ b/src/libserver/task.c
@@ -756,6 +756,7 @@ rspamd_task_process (struct rspamd_task *task, guint stages)
case RSPAMD_TASK_STAGE_COMPOSITES:
rspamd_composites_process_task (task);
+ task->result->nresults_postfilters = task->result->nresults;
break;
case RSPAMD_TASK_STAGE_POST_FILTERS:
@@ -813,8 +814,13 @@ rspamd_task_process (struct rspamd_task *task, guint stages)
}
break;
case RSPAMD_TASK_STAGE_COMPOSITES_POST:
- /* Second run of composites processing before idempotent filters */
- rspamd_composites_process_task (task);
+ /* Second run of composites processing before idempotent filters (if needed) */
+ if (task->result->nresults_postfilters != task->result->nresults) {
+ rspamd_composites_process_task (task);
+ }
+ else {
+ msg_debug_task ("skip second run of composites as the result has not been changed");
+ }
break;
case RSPAMD_TASK_STAGE_IDEMPOTENT:
diff --git a/test/lua/unit/rspamd_resolver.lua b/test/lua/unit/rspamd_resolver.lua
new file mode 100644
index 000000000..e987ff00b
--- /dev/null
+++ b/test/lua/unit/rspamd_resolver.lua
@@ -0,0 +1,31 @@
+-- Rspamd resolver Lua tests
+
+context("Check punycoding UTF-8 URL", function()
+ local rspamd_resolver = require "rspamd_resolver"
+ local rspamd_util = require "rspamd_util"
+
+ local resolver = rspamd_resolver.init(rspamd_util.create_event_base(), rspamd_config)
+
+ local cases = {
+ -- https://unicode.org/reports/tr46/#Deviations
+ ['faß.de'] = 'fass.de', -- IDNA2008 result: xn--fa-hia.de
+ ['βόλος.com'] = 'xn--nxasmq6b.com', -- IDNA2008 result: xn--nxasmm1c.com
+ ['نامه‌ای.com'] = 'xn--mgba3gch31f.com', -- IDNA2008 result: xn--mgba3gch31f060k.com
+ ['ශ්‍රී.com'] = 'xn--10cl1a0b.com', -- IDNA2008 result: xn--10cl1a0b660p.com
+
+ -- https://unicode.org/reports/tr46/#Table_Example_Processing
+ ['日本語。JP'] = 'xn--wgv71a119e.jp', -- Fullwidth characters are remapped, including 。
+ --['u¨.com'] = 'xn--tda.com', -- Normalize changes u + umlaut to ü
+ ['☕.us'] = 'xn--53h.us', -- Post-Unicode 3.2 characters are allowed
+
+ -- Other
+ ['example.рф'] = 'example.xn--p1ai',
+ }
+
+ for k, v in pairs(cases) do
+ test(string.format("punycode %s -> %s", k, v), function()
+ local res = resolver:idna_convert_utf8(k)
+ assert_equal(res, v)
+ end)
+ end
+end)