summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorVsevolod Stakhov <vsevolod@rambler-co.ru>2012-05-29 22:08:54 +0400
committerVsevolod Stakhov <vsevolod@rambler-co.ru>2012-05-29 22:08:54 +0400
commitda1b50cb159a91092a6e6b689e4ea34197ce72f2 (patch)
treee15cb4f3b33fef99cf3e7d1169c9a0b0d3035b2b /src
parent61b06ca0377dadfdc6e1a3241cb1cfb966e525f2 (diff)
downloadrspamd-da1b50cb159a91092a6e6b689e4ea34197ce72f2.tar.gz
rspamd-da1b50cb159a91092a6e6b689e4ea34197ce72f2.zip
* Add support of strict_domains.
Several fixes in dkim code. Make initial support of body relaxed canonization.
Diffstat (limited to 'src')
-rw-r--r--src/dkim.c98
-rw-r--r--src/html.c2
-rw-r--r--src/plugins/dkim_check.c35
3 files changed, 111 insertions, 24 deletions
diff --git a/src/dkim.c b/src/dkim.c
index 20a52b0c6..87959e6f4 100644
--- a/src/dkim.c
+++ b/src/dkim.c
@@ -648,7 +648,7 @@ rspamd_dkim_parse_key (const gchar *txt, gsize *keylen, GError **err)
case 1:
/* State when we got p= and looking for some public key */
if ((*p == ';' || p == end) && p > c) {
- len = (p == end) ? p - c : p - c - 1;
+ len = p - c;
return rspamd_dkim_make_key (c, len, err);
}
else {
@@ -692,6 +692,7 @@ rspamd_dkim_dns_cb (struct rspamd_dns_reply *reply, gpointer arg)
if (key) {
break;
}
+ cur = g_list_next (cur);
}
if (key != NULL && err != NULL) {
/* Free error as it is insignificant */
@@ -727,30 +728,88 @@ rspamd_get_dkim_key (rspamd_dkim_context_t *ctx, struct rspamd_dns_resolver *res
}
static gboolean
+rspamd_dkim_relaxed_body_step (GChecksum *ck, const gchar **start, guint remain)
+{
+ const gchar *h;
+ static gchar buf[BUFSIZ];
+ gchar *t;
+ guint len, inlen;
+ gboolean got_sp, finished = FALSE;
+
+ if (remain > sizeof (buf)) {
+ len = sizeof (buf);
+ }
+ else {
+ len = remain;
+ finished = TRUE;
+ }
+ len = MIN (sizeof (buf), remain);
+ inlen = len;
+ h = *start;
+ t = &buf[0];
+ got_sp = FALSE;
+
+ while (len && inlen) {
+ if ((*h == '\r' || *h == '\n') && got_sp) {
+ /* Ignore spaces at the end of line */
+ got_sp = FALSE;
+ t --;
+ len --;
+ }
+ else if (g_ascii_isspace (*h)) {
+ if (got_sp) {
+ /* Ignore multiply spaces */
+ h ++;
+ inlen --;
+ continue;
+ }
+ else {
+ got_sp = TRUE;
+ }
+ }
+ else {
+ got_sp = FALSE;
+ }
+ *t++ = *h++;
+ inlen --;
+ len --;
+ }
+
+ *start = h;
+
+ g_checksum_update (ck, buf, t - buf);
+
+ return finished;
+}
+
+static gboolean
rspamd_dkim_canonize_body (rspamd_dkim_context_t *ctx, const gchar *start, const gchar *end)
{
- if (ctx->body_canon_type == DKIM_CANON_SIMPLE) {
- /* Perform simple canonization */
- if (start == NULL) {
+ if (start == NULL) {
+ /* Empty body */
+ g_checksum_update (ctx->body_hash, CRLF, sizeof (CRLF) - 2);
+ }
+ else {
+ end --;
+ while (end > start + 2) {
+ if (*end == '\n' && *(end - 1) == '\r' && *(end - 2) == '\n') {
+ end -= 2;
+ }
+ else {
+ break;
+ }
+ }
+ if (end == start || end == start + 2) {
/* Empty body */
g_checksum_update (ctx->body_hash, CRLF, sizeof (CRLF) - 2);
}
else {
- end --;
- while (end > start + 2) {
- if (*end == '\n' && *(end - 1) == '\r' && *(end - 2) == '\n') {
- end -= 2;
- }
- else {
- break;
- }
- }
- if (end == start || end == start + 2) {
- /* Empty body */
- g_checksum_update (ctx->body_hash, CRLF, sizeof (CRLF) - 2);
+ if (ctx->body_canon_type == DKIM_CANON_SIMPLE) {
+ /* Simple canonization */
+ g_checksum_update (ctx->body_hash, start, end - start + 1);
}
else {
- g_checksum_update (ctx->body_hash, start, end - start + 1);
+ while (rspamd_dkim_relaxed_body_step (ctx->body_hash, &start, end - start + 1));
}
}
return TRUE;
@@ -826,6 +885,10 @@ rspamd_dkim_canonize_header_simple (rspamd_dkim_context_t *ctx, const gchar *hea
/* Get value */
state = 2;
}
+ else {
+ /* Skip the whole header */
+ state = 1;
+ }
}
else {
/* Skip the whole header */
@@ -981,6 +1044,7 @@ rspamd_dkim_check (rspamd_dkim_context_t *ctx, rspamd_dkim_key_t *key, struct wo
cur = ctx->hlist;
while (cur) {
if (!rspamd_dkim_canonize_header (ctx, task, cur->data, FALSE)) {
+ msg_debug ("cannot find header %s for canonization", cur->data);
return DKIM_RECORD_ERROR;
}
cur = g_list_next (cur);
diff --git a/src/html.c b/src/html.c
index dac09bf0e..41dd1df7d 100644
--- a/src/html.c
+++ b/src/html.c
@@ -900,7 +900,7 @@ add_html_node (struct worker_task *task, memory_pool_t * pool, struct mime_text_
else {
new = construct_html_node (pool, tag_text, tag_len);
if (new == NULL) {
- debug_task ("cannot construct HTML node for text '%s'", tag_text);
+ debug_task ("cannot construct HTML node for text '%*s'", tag_len, tag_text);
return FALSE;
}
data = new->data;
diff --git a/src/plugins/dkim_check.c b/src/plugins/dkim_check.c
index db93b3da1..338c81aae 100644
--- a/src/plugins/dkim_check.c
+++ b/src/plugins/dkim_check.c
@@ -22,14 +22,17 @@
*/
-/***MODULE:spf
- * rspamd module that checks spf records of incoming email
+/***MODULE:dkim
+ * rspamd module that checks dkim records of incoming email
*
* Allowed options:
- * - symbol_allow (string): symbol to insert (default: 'R_SPF_ALLOW')
- * - symbol_fail (string): symbol to insert (default: 'R_SPF_FAIL')
- * - symbol_softfail (string): symbol to insert (default: 'R_SPF_SOFTFAIL')
+ * - symbol_allow (string): symbol to insert in case of allow (default: 'R_DKIM_ALLOW')
+ * - symbol_reject (string): symbol to insert (default: 'R_DKIM_REJECT')
+ * - symbol_rempfail (string): symbol to insert in case of temporary fail (default: 'R_DKIM_TEMPFAIL')
* - whitelist (map): map of whitelisted networks
+ * - domains (map): map of domains to check (if absent all domains are checked)
+ * - strict_domains (map): map of domains that requires strict score for dkim
+ * - strict_multiplier (number): multiplier for strict domains
*/
#include "config.h"
@@ -59,6 +62,8 @@ struct dkim_ctx {
memory_pool_t *dkim_pool;
radix_tree_t *whitelist_ip;
GHashTable *dkim_domains;
+ GHashTable *strict_domains;
+ guint strict_multiplier;
rspamd_lru_hash_t *dkim_hash;
};
@@ -93,6 +98,8 @@ dkim_module_init (struct config_file *cfg, struct module_ctx **ctx)
register_module_opt ("dkim", "dkim_cache_expire", MODULE_OPT_TYPE_TIME);
register_module_opt ("dkim", "whitelist", MODULE_OPT_TYPE_MAP);
register_module_opt ("dkim", "domains", MODULE_OPT_TYPE_MAP);
+ register_module_opt ("dkim", "strict_domains", MODULE_OPT_TYPE_MAP);
+ register_module_opt ("dkim", "strict_multiplier", MODULE_OPT_TYPE_UINT);
return 0;
}
@@ -146,6 +153,11 @@ dkim_module_config (struct config_file *cfg)
msg_warn ("cannot load domains list from %s", value);
}
}
+ if ((value = get_module_opt (cfg, "dkim", "strict_domains")) != NULL) {
+ if (! add_map (value, read_host_list, fin_host_list, (void **)&dkim_module_ctx->strict_domains)) {
+ msg_warn ("cannot load strict domains list from %s", value);
+ }
+ }
register_symbol (&cfg->cache, dkim_module_ctx->symbol_reject, 1, dkim_symbol_callback, NULL);
register_virtual_symbol (&cfg->cache, dkim_module_ctx->symbol_tempfail, 1);
@@ -173,11 +185,18 @@ dkim_module_reconfig (struct config_file *cfg)
static void
dkim_module_check (struct worker_task *task, rspamd_dkim_context_t *ctx, rspamd_dkim_key_t *key)
{
- gint res;
+ gint res, score = 1;
msg_debug ("check dkim signature for %s domain", ctx->dns_key);
res = rspamd_dkim_check (ctx, key, task);
+ if (dkim_module_ctx->strict_domains != NULL && dkim_module_ctx->strict_multiplier > 0) {
+ /* Perform strict check */
+ if (g_hash_table_lookup (dkim_module_ctx->strict_domains, ctx->dns_key) != NULL) {
+ score *= dkim_module_ctx->strict_multiplier;
+ }
+ }
+
if (res == DKIM_REJECT) {
insert_result (task, dkim_module_ctx->symbol_reject, 1, NULL);
}
@@ -202,6 +221,7 @@ dkim_module_key_handler (rspamd_dkim_key_t *key, gsize keylen, rspamd_dkim_conte
}
else {
/* Insert tempfail symbol */
+ msg_info ("cannot get key for domain %s", ctx->dns_key);
insert_result (task, dkim_module_ctx->symbol_tempfail, 1, NULL);
}
}
@@ -236,9 +256,12 @@ dkim_symbol_callback (struct worker_task *task, void *unused)
/* Get key */
key = rspamd_lru_hash_lookup (dkim_module_ctx->dkim_hash, ctx->dns_key, task->tv.tv_sec);
if (key != NULL) {
+ debug_task ("found key for %s in cache", ctx->dns_key);
dkim_module_check (task, ctx, key);
}
else {
+ debug_task ("request key for %s from DNS", ctx->dns_key);
+ task->dns_requests ++;
rspamd_get_dkim_key (ctx, task->resolver, task->s, dkim_module_key_handler, task);
}
}