Browse Source

[Project] Rework DKIM checks results

tags/1.8.3
Vsevolod Stakhov 5 years ago
parent
commit
b42c97d562
4 changed files with 133 additions and 51 deletions
  1. 62
    16
      src/libserver/dkim.c
  2. 28
    8
      src/libserver/dkim.h
  3. 1
    0
      src/libserver/mempool_vars_internal.h
  4. 42
    27
      src/plugins/dkim_check.c

+ 62
- 16
src/libserver/dkim.c View 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)
{

+ 28
- 8
src/libserver/dkim.h View 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);

+ 1
- 0
src/libserver/mempool_vars_internal.h View 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"

+ 42
- 27
src/plugins/dkim_check.c View 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;

Loading…
Cancel
Save