]> git.ipfire.org Git - thirdparty/rspamd.git/commitdiff
[Project] Rework DKIM checks results
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Sat, 1 Dec 2018 12:55:51 +0000 (12:55 +0000)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Sat, 1 Dec 2018 12:55:51 +0000 (12:55 +0000)
src/libserver/dkim.c
src/libserver/dkim.h
src/libserver/mempool_vars_internal.h
src/plugins/dkim_check.c

index 1b78ee84e76e2ec1ddaeeea1c0120a862b2e6cce..e952ccb225d70df94bc2b912515764d4584cab26 100644 (file)
@@ -2255,7 +2255,7 @@ rspamd_dkim_check_bh_cached (struct rspamd_dkim_common_ctx *ctx,
  * @param task task to check
  * @return
  */
-enum rspamd_dkim_check_result
+struct rspamd_dkim_check_result *
 rspamd_dkim_check (rspamd_dkim_context_t *ctx,
        rspamd_dkim_key_t *key,
        struct rspamd_task *task)
@@ -2265,21 +2265,31 @@ rspamd_dkim_check (rspamd_dkim_context_t *ctx,
        struct rspamd_dkim_cached_hash *cached_bh = NULL;
        EVP_MD_CTX *cpy_ctx = NULL;
        gsize dlen = 0;
-       enum rspamd_dkim_check_result res = DKIM_CONTINUE;
+       struct rspamd_dkim_check_result *res;
        guint i;
        struct rspamd_dkim_header *dh;
        gint nid;
 
-       g_return_val_if_fail (ctx != NULL,               DKIM_ERROR);
-       g_return_val_if_fail (key != NULL,               DKIM_ERROR);
-       g_return_val_if_fail (task->msg.len > 0, DKIM_ERROR);
+       g_return_val_if_fail (ctx != NULL,               NULL);
+       g_return_val_if_fail (key != NULL,               NULL);
+       g_return_val_if_fail (task->msg.len > 0, NULL);
 
        /* First of all find place of body */
        body_end = task->msg.begin + task->msg.len;
        body_start = task->raw_headers_content.body_start;
 
+       res = rspamd_mempool_alloc0 (task->task_pool, sizeof (*res));
+       res->ctx = ctx;
+       res->selector = ctx->selector;
+       res->domain = ctx->domain;
+       res->fail_reason = NULL;
+       res->short_b = rspamd_encode_base64 (ctx->b, 4, 0, NULL);
+       res->rcode = DKIM_CONTINUE;
+       rspamd_mempool_add_destructor (task->task_pool, g_free, (gpointer)res->short_b);
+
        if (!body_start) {
-               return DKIM_RECORD_ERROR;
+               res->rcode = DKIM_ERROR;
+               return res;
        }
 
        if (ctx->common.type != RSPAMD_DKIM_ARC_SEAL) {
@@ -2291,7 +2301,8 @@ rspamd_dkim_check (rspamd_dkim_context_t *ctx,
                        /* Start canonization of body part */
                        if (!rspamd_dkim_canonize_body (&ctx->common, body_start, body_end,
                                        FALSE)) {
-                               return DKIM_RECORD_ERROR;
+                               res->rcode = DKIM_RECORD_ERROR;
+                               return res;
                        }
                }
        }
@@ -2380,8 +2391,11 @@ rspamd_dkim_check (rspamd_dkim_context_t *ctx,
 #else
                                                EVP_MD_CTX_reset (cpy_ctx);
 #endif
+                                               res->fail_reason = "body hash did not verify";
+                                               res->rcode = DKIM_REJECT;
                                                EVP_MD_CTX_destroy (cpy_ctx);
-                                               return DKIM_REJECT;
+
+                                               return res;
                                        }
                                }
                        }
@@ -2398,11 +2412,18 @@ rspamd_dkim_check (rspamd_dkim_context_t *ctx,
                                                                        dlen, ctx->bh,
                                                                        dlen, cached_bh->digest_cr);
 
-                                                       return DKIM_REJECT;
+                                                       res->fail_reason = "body hash did not verify";
+                                                       res->rcode = DKIM_REJECT;
+
+                                                       return res;
                                                }
                                        }
                                        else {
-                                               return DKIM_REJECT;
+
+                                               res->fail_reason = "body hash did not verify";
+                                               res->rcode = DKIM_REJECT;
+
+                                               return res;
                                        }
                                }
                        }
@@ -2411,8 +2432,10 @@ rspamd_dkim_check (rspamd_dkim_context_t *ctx,
                                                "bh value mismatch: %*xs versus %*xs",
                                                dlen, ctx->bh,
                                                dlen, cached_bh->digest_normal);
+                               res->fail_reason = "body hash did not verify";
+                               res->rcode = DKIM_REJECT;
 
-                               return DKIM_REJECT;
+                               return res;
                        }
                }
 
@@ -2452,21 +2475,24 @@ rspamd_dkim_check (rspamd_dkim_context_t *ctx,
                if (RSA_verify (nid, raw_digest, dlen, ctx->b, ctx->blen,
                                key->key.key_rsa) != 1) {
                        msg_debug_dkim ("rsa verify failed");
-                       res = DKIM_REJECT;
+                       res->rcode = DKIM_REJECT;
+                       res->fail_reason = "rsa verify failed";
                }
                break;
        case RSPAMD_DKIM_KEY_ECDSA:
                if (ECDSA_verify (nid, raw_digest, dlen, ctx->b, ctx->blen,
                                key->key.key_ecdsa) != 1) {
                        msg_debug_dkim ("ecdsa verify failed");
-                       res = DKIM_REJECT;
+                       res->rcode = DKIM_REJECT;
+                       res->fail_reason = "ecdsa verify failed";
                }
                break;
        case RSPAMD_DKIM_KEY_EDDSA:
                if (!rspamd_cryptobox_verify (ctx->b, ctx->blen, raw_digest, dlen,
                                key->key.key_eddsa, RSPAMD_CRYPTOBOX_MODE_25519)) {
                        msg_debug_dkim ("eddsa verify failed");
-                       res = DKIM_REJECT;
+                       res->rcode = DKIM_REJECT;
+                       res->fail_reason = "eddsa verify failed";
                }
                break;
        }
@@ -2476,11 +2502,13 @@ rspamd_dkim_check (rspamd_dkim_context_t *ctx,
                switch (ctx->cv) {
                case RSPAMD_ARC_INVALID:
                        msg_info_dkim ("arc seal is invalid i=%d", ctx->common.idx);
-                       res = DKIM_PERM_ERROR;
+                       res->rcode = DKIM_PERM_ERROR;
+                       res->fail_reason = "arc seal is invalid";
                        break;
                case RSPAMD_ARC_FAIL:
                        msg_info_dkim ("arc seal failed i=%d", ctx->common.idx);
-                       res = DKIM_REJECT;
+                       res->rcode = DKIM_REJECT;
+                       res->fail_reason = "arc seal failed";
                        break;
                default:
                        break;
@@ -2490,6 +2518,24 @@ rspamd_dkim_check (rspamd_dkim_context_t *ctx,
        return res;
 }
 
+struct rspamd_dkim_check_result *
+rspamd_dkim_create_result (rspamd_dkim_context_t *ctx,
+                                                  enum rspamd_dkim_check_rcode rcode,
+                                                  struct rspamd_task *task)
+{
+       struct rspamd_dkim_check_result *res;
+
+       res = rspamd_mempool_alloc0 (task->task_pool, sizeof (*res));
+       res->ctx = ctx;
+       res->selector = ctx->selector;
+       res->domain = ctx->domain;
+       res->fail_reason = NULL;
+       res->short_b = rspamd_encode_base64 (ctx->b, 4, 0, NULL);
+       rspamd_mempool_add_destructor (task->task_pool, g_free, (gpointer)res->short_b);
+
+       return res;
+}
+
 rspamd_dkim_key_t *
 rspamd_dkim_key_ref (rspamd_dkim_key_t *k)
 {
index 61580e426a4a0825323d4e3ac64910ca62b629ba..46953a21ccfaff61b0b8d450b0f2a3c7fbfd83ba 100644 (file)
@@ -81,7 +81,7 @@
 #define DKIM_SIGERROR_EMPTY_V       45  /* v= tag empty */
 
 /* Check results */
-enum rspamd_dkim_check_result {
+enum rspamd_dkim_check_rcode {
        DKIM_CONTINUE = 0,
        DKIM_REJECT,
        DKIM_TRYAGAIN,
@@ -137,6 +137,16 @@ enum rspamd_dkim_key_type {
        RSPAMD_DKIM_KEY_EDDSA
 };
 
+struct rspamd_dkim_check_result {
+       enum rspamd_dkim_check_rcode rcode;
+       rspamd_dkim_context_t *ctx;
+       /* Processed parts */
+       const gchar *selector;
+       const gchar *domain;
+       const gchar *short_b;
+       const gchar *fail_reason;
+};
+
 
 /* Err MUST be freed if it is not NULL, key is allocated by slice allocator */
 typedef void (*dkim_key_handler_f)(rspamd_dkim_key_t *key, gsize keylen,
@@ -209,13 +219,23 @@ gboolean rspamd_get_dkim_key (rspamd_dkim_context_t *ctx,
  * @param task task to check
  * @return
  */
-enum rspamd_dkim_check_result rspamd_dkim_check (rspamd_dkim_context_t *ctx,
-       rspamd_dkim_key_t *key,
-       struct rspamd_task *task);
-
-GString *rspamd_dkim_sign (struct rspamd_task *task, const gchar *selector,
-               const gchar *domain, time_t expire, gsize len, guint idx,
-               const gchar *arc_cv, rspamd_dkim_sign_context_t *ctx);
+struct rspamd_dkim_check_result * rspamd_dkim_check (rspamd_dkim_context_t *ctx,
+                                                                                                        rspamd_dkim_key_t *key,
+                                                                                                        struct rspamd_task *task);
+
+struct rspamd_dkim_check_result *
+rspamd_dkim_create_result (rspamd_dkim_context_t *ctx,
+                                                  enum rspamd_dkim_check_rcode rcode,
+                                                  struct rspamd_task *task);
+
+GString *rspamd_dkim_sign (struct rspamd_task *task,
+                                                  const gchar *selector,
+                                                  const gchar *domain,
+                                                  time_t expire,
+                                                  gsize len,
+                                                  guint idx,
+                                                  const gchar *arc_cv,
+                                                  rspamd_dkim_sign_context_t *ctx);
 
 rspamd_dkim_key_t * rspamd_dkim_key_ref (rspamd_dkim_key_t *k);
 void rspamd_dkim_key_unref (rspamd_dkim_key_t *k);
index a5195d32560cdad825ef405fb29359045f5b41a7..ad2958ab4e2745c4d451540a6cf6d882e7eeccbf 100644 (file)
@@ -32,6 +32,7 @@
 #define RSPAMD_MEMPOOL_DKIM_SIGNATURE "dkim-signature"
 #define RSPAMD_MEMPOOL_DMARC_CHECKS "dmarc_checks"
 #define RSPAMD_MEMPOOL_DKIM_BH_CACHE "dkim_bh_cache"
+#define RSPAMD_MEMPOOL_DKIM_CHECK_RESULTS "dkim_results"
 #define RSPAMD_MEMPOOL_DKIM_SIGN_KEY "dkim_key"
 #define RSPAMD_MEMPOOL_DKIM_SIGN_SELECTOR "dkim_selector"
 #define RSPAMD_MEMPOOL_ARC_SIGN_KEY "arc_key"
index f1a587e4ab1d5e1debf553c1978755c2a447e344..1549a2add1a7d1d67766fa0a36bb57d34408482a 100644 (file)
@@ -85,7 +85,7 @@ struct dkim_check_result {
        rspamd_dkim_context_t *ctx;
        rspamd_dkim_key_t *key;
        struct rspamd_task *task;
-       gint res;
+       struct rspamd_dkim_check_result *res;
        gdouble mult_allow;
        gdouble mult_deny;
        struct rspamd_symcache_item *item;
@@ -822,7 +822,7 @@ lua_dkim_sign_handler (lua_State *L)
        if (pubkey != NULL) {
                /* Also check if private and public keys match */
                rspamd_dkim_key_t *pk;
-               gsize keylen = strlen (pubkey);
+               keylen = strlen (pubkey);
 
                pk = rspamd_dkim_parse_key (pubkey, &keylen, NULL);
 
@@ -956,7 +956,7 @@ dkim_module_check (struct dkim_check_result *res)
                        continue;
                }
 
-               if (cur->key != NULL && cur->res == -1) {
+               if (cur->key != NULL && cur->res == NULL) {
                        cur->res = rspamd_dkim_check (cur->ctx, cur->key, cur->task);
 
                        if (dkim_module_ctx->dkim_domains != NULL) {
@@ -978,7 +978,7 @@ dkim_module_check (struct dkim_check_result *res)
                if (cur->ctx == NULL) {
                        continue;
                }
-               if (cur->res == -1) {
+               if (cur->res == NULL) {
                        /* Still need a key */
                        all_done = FALSE;
                }
@@ -989,24 +989,25 @@ dkim_module_check (struct dkim_check_result *res)
                        const gchar *symbol = NULL, *trace = NULL;
                        gdouble symbol_weight = 1.0;
 
-                       if (cur->ctx == NULL) {
+                       if (cur->ctx == NULL || cur->res == NULL) {
                                continue;
                        }
-                       if (cur->res == DKIM_REJECT) {
+
+                       if (cur->res->rcode == DKIM_REJECT) {
                                symbol = dkim_module_ctx->symbol_reject;
                                trace = "-";
                                symbol_weight = cur->mult_deny * 1.0;
                        }
-                       else if (cur->res == DKIM_CONTINUE) {
+                       else if (cur->res->rcode == DKIM_CONTINUE) {
                                symbol = dkim_module_ctx->symbol_allow;
                                trace = "+";
                                symbol_weight = cur->mult_allow * 1.0;
                        }
-                       else if (cur->res == DKIM_PERM_ERROR) {
+                       else if (cur->res->rcode == DKIM_PERM_ERROR) {
                                trace = "~";
                                symbol = dkim_module_ctx->symbol_permfail;
                        }
-                       else if (cur->res == DKIM_TRYAGAIN) {
+                       else if (cur->res->rcode == DKIM_TRYAGAIN) {
                                trace = "?";
                                symbol = dkim_module_ctx->symbol_tempfail;
                        }
@@ -1072,10 +1073,12 @@ dkim_module_key_handler (rspamd_dkim_key_t *key,
 
                if (err != NULL) {
                        if (err->code == DKIM_SIGERROR_NOKEY) {
-                               res->res = DKIM_TRYAGAIN;
+                               res->res = rspamd_dkim_create_result (ctx, DKIM_TRYAGAIN, task);
+                               res->res->fail_reason = "DNS error when getting key";
                        }
                        else {
-                               res->res = DKIM_PERM_ERROR;
+                               res->res = rspamd_dkim_create_result (ctx, DKIM_PERM_ERROR, task);
+                               res->res->fail_reason = "invalid DKIM record";
                        }
                }
        }
@@ -1153,7 +1156,7 @@ dkim_symbol_callback (struct rspamd_task *task,
 
                        cur = rspamd_mempool_alloc0 (task->task_pool, sizeof (*cur));
                        cur->first = res;
-                       cur->res = -1;
+                       cur->res = NULL;
                        cur->task = task;
                        cur->mult_allow = 1.0;
                        cur->mult_deny = 1.0;
@@ -1492,7 +1495,7 @@ struct rspamd_dkim_lua_verify_cbdata {
 
 static void
 dkim_module_lua_push_verify_result (struct rspamd_dkim_lua_verify_cbdata *cbd,
-               gint code, GError *err)
+               struct rspamd_dkim_check_result *res, GError *err)
 {
        struct rspamd_task **ptask, *task;
        const gchar *error_str = "unknown error";
@@ -1500,7 +1503,7 @@ dkim_module_lua_push_verify_result (struct rspamd_dkim_lua_verify_cbdata *cbd,
 
        task = cbd->task;
 
-       switch (code) {
+       switch (res->rcode) {
        case DKIM_CONTINUE:
                error_str = NULL;
                success = TRUE;
@@ -1556,13 +1559,19 @@ dkim_module_lua_push_verify_result (struct rspamd_dkim_lua_verify_cbdata *cbd,
        lua_pushstring (cbd->L, error_str);
 
        if (cbd->ctx) {
-               lua_pushstring (cbd->L, rspamd_dkim_get_domain (cbd->ctx));
+               lua_pushstring (cbd->L, res->domain);
+               lua_pushstring (cbd->L, res->selector);
+               lua_pushstring (cbd->L, res->short_b);
+               lua_pushstring (cbd->L, res->fail_reason);
        }
        else {
                lua_pushnil (cbd->L);
+               lua_pushnil (cbd->L);
+               lua_pushnil (cbd->L);
+               lua_pushnil (cbd->L);
        }
 
-       if (lua_pcall (cbd->L, 4, 0, 0) != 0) {
+       if (lua_pcall (cbd->L, 7, 0, 0) != 0) {
                msg_err_task ("call to verify callback failed: %s",
                                lua_tostring (cbd->L, -1));
                lua_pop (cbd->L, 1);
@@ -1573,14 +1582,14 @@ dkim_module_lua_push_verify_result (struct rspamd_dkim_lua_verify_cbdata *cbd,
 
 static void
 dkim_module_lua_on_key (rspamd_dkim_key_t *key,
-               gsize keylen,
-               rspamd_dkim_context_t *ctx,
-               gpointer ud,
-               GError *err)
+                                               gsize keylen,
+                                               rspamd_dkim_context_t *ctx,
+                                               gpointer ud,
+                                               GError *err)
 {
        struct rspamd_dkim_lua_verify_cbdata *cbd = ud;
        struct rspamd_task *task;
-       gint ret;
+       struct rspamd_dkim_check_result *res;
        struct dkim_ctx *dkim_module_ctx;
 
        task = cbd->task;
@@ -1607,16 +1616,22 @@ dkim_module_lua_on_key (rspamd_dkim_key_t *key,
 
                if (err != NULL) {
                        if (err->code == DKIM_SIGERROR_NOKEY) {
-                               dkim_module_lua_push_verify_result (cbd, DKIM_TRYAGAIN, err);
+                               res = rspamd_dkim_create_result (ctx, DKIM_TRYAGAIN, task);
+                               res->fail_reason = "DNS error when getting key";
+
                        }
                        else {
-                               dkim_module_lua_push_verify_result (cbd, DKIM_PERM_ERROR, err);
+                               res = rspamd_dkim_create_result (ctx, DKIM_PERM_ERROR, task);
+                               res->fail_reason = "invalid DKIM record";
                        }
                }
                else {
-                       dkim_module_lua_push_verify_result (cbd, DKIM_TRYAGAIN, NULL);
+                       res = rspamd_dkim_create_result (ctx, DKIM_TRYAGAIN, task);
+                       res->fail_reason = "DNS error when getting key";
                }
 
+               dkim_module_lua_push_verify_result (cbd, res, err);
+
                if (err) {
                        g_error_free (err);
                }
@@ -1624,8 +1639,8 @@ dkim_module_lua_on_key (rspamd_dkim_key_t *key,
                return;
        }
 
-       ret = rspamd_dkim_check (cbd->ctx, cbd->key, cbd->task);
-       dkim_module_lua_push_verify_result (cbd, ret, NULL);
+       res = rspamd_dkim_check (cbd->ctx, cbd->key, cbd->task);
+       dkim_module_lua_push_verify_result (cbd, res, NULL);
 }
 
 static gint
@@ -1636,7 +1651,7 @@ lua_dkim_verify_handler (lua_State *L)
        rspamd_dkim_context_t *ctx;
        struct rspamd_dkim_lua_verify_cbdata *cbd;
        rspamd_dkim_key_t *key;
-       gint ret;
+       struct rspamd_dkim_check_result *ret;
        GError *err = NULL;
        const gchar *type_str = NULL;
        enum rspamd_dkim_type type = RSPAMD_DKIM_NORMAL;