From b42c97d562d0ada85e80562677c9f686a8c87cbd Mon Sep 17 00:00:00 2001 From: Vsevolod Stakhov Date: Sat, 1 Dec 2018 12:55:51 +0000 Subject: [PATCH] [Project] Rework DKIM checks results --- src/libserver/dkim.c | 78 +++++++++++++++++++++------ src/libserver/dkim.h | 36 ++++++++++--- src/libserver/mempool_vars_internal.h | 1 + src/plugins/dkim_check.c | 69 ++++++++++++++---------- 4 files changed, 133 insertions(+), 51 deletions(-) diff --git a/src/libserver/dkim.c b/src/libserver/dkim.c index 1b78ee84e..e952ccb22 100644 --- a/src/libserver/dkim.c +++ b/src/libserver/dkim.c @@ -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) { diff --git a/src/libserver/dkim.h b/src/libserver/dkim.h index 61580e426..46953a21c 100644 --- a/src/libserver/dkim.h +++ b/src/libserver/dkim.h @@ -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); diff --git a/src/libserver/mempool_vars_internal.h b/src/libserver/mempool_vars_internal.h index a5195d325..ad2958ab4 100644 --- a/src/libserver/mempool_vars_internal.h +++ b/src/libserver/mempool_vars_internal.h @@ -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" diff --git a/src/plugins/dkim_check.c b/src/plugins/dkim_check.c index f1a587e4a..1549a2add 100644 --- a/src/plugins/dkim_check.c +++ b/src/plugins/dkim_check.c @@ -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; -- 2.39.5