diff options
-rw-r--r-- | src/libmime/scan_result.c | 5 | ||||
-rw-r--r-- | src/libmime/scan_result.h | 2 | ||||
-rw-r--r-- | src/libserver/composites.c | 173 | ||||
-rw-r--r-- | src/libserver/dkim.c | 47 | ||||
-rw-r--r-- | src/libserver/task.c | 10 | ||||
-rw-r--r-- | test/lua/unit/rspamd_resolver.lua | 31 |
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) |