]> source.dussan.org Git - rspamd.git/commitdiff
* Add support of strict_domains.
authorVsevolod Stakhov <vsevolod@rambler-co.ru>
Tue, 29 May 2012 18:08:54 +0000 (22:08 +0400)
committerVsevolod Stakhov <vsevolod@rambler-co.ru>
Tue, 29 May 2012 18:08:54 +0000 (22:08 +0400)
Several fixes in dkim code.
Make initial support of body relaxed canonization.

src/dkim.c
src/html.c
src/plugins/dkim_check.c

index 20a52b0c6fbb8f23e51051be951a66f25ca8ad3a..87959e6f4d9ad5df9bd459a8485c1e8a3b831b1f 100644 (file)
@@ -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 */
@@ -726,31 +727,89 @@ rspamd_get_dkim_key (rspamd_dkim_context_t *ctx, struct rspamd_dns_resolver *res
        return make_dns_request (resolver, s, ctx->pool, rspamd_dkim_dns_cb, cbdata, DNS_REQUEST_TXT, ctx->dns_key);
 }
 
+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);
index dac09bf0eca0555d82fd2525349208885581ba5c..41dd1df7ddbdcd8cd35f6e8813e641207a71c5ab 100644 (file)
@@ -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;
index db93b3da1290df85790042d250b5ebef1c94dee3..338c81aae9f22a4a74dc5ab272b6e133bd3a85eb 100644 (file)
  */
 
 
-/***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);
                                }
                        }