From b0e378af1d574d2745e676acdb2cf180a7338886 Mon Sep 17 00:00:00 2001 From: Andrew Lewis Date: Mon, 19 Sep 2016 16:56:16 +0200 Subject: [PATCH] [Feature] Add R_DKIM_PERMFAIL symbol --- conf/composites.conf | 5 ++ conf/metrics.conf | 1 + src/libserver/dkim.c | 9 +++- src/libserver/dkim.h | 3 +- src/plugins/dkim_check.c | 106 +++++++++++++++++++++++---------------- 5 files changed, 79 insertions(+), 45 deletions(-) diff --git a/conf/composites.conf b/conf/composites.conf index b64201494..40b495918 100644 --- a/conf/composites.conf +++ b/conf/composites.conf @@ -47,6 +47,11 @@ composite "AUTH_NA" { score = 1.0; policy = "remove_weight"; } +composite { + name = "DKIM_MIXED"; + expression = "-R_DKIM_ALLOW & (R_DKIM_DNSFAIL | R_DKIM_PERMFAIL | R_DKIM_REJECT)" + policy = "remove_weight"; +} .include(try=true; priority=1; duplicate=merge) "$LOCAL_CONFDIR/local.d/composites.conf" .include(try=true; priority=10) "$LOCAL_CONFDIR/override.d/composites.conf" diff --git a/conf/metrics.conf b/conf/metrics.conf index 7ece1c542..8d228a5ba 100644 --- a/conf/metrics.conf +++ b/conf/metrics.conf @@ -327,6 +327,7 @@ metric { symbol "R_DKIM_REJECT" { weight = 1.0; description = "DKIM verification failed"; + one_shot = true; } symbol "R_DKIM_TEMPFAIL" { weight = 0.0; diff --git a/src/libserver/dkim.c b/src/libserver/dkim.c index 3c4d7ed36..33ac2cb96 100644 --- a/src/libserver/dkim.c +++ b/src/libserver/dkim.c @@ -1111,9 +1111,16 @@ rspamd_dkim_dns_cb (struct rdns_reply *reply, gpointer arg) gsize keylen = 0; if (reply->code != RDNS_RC_NOERROR) { + gint err_code = DKIM_SIGERROR_NOKEY; + if (reply->code == RDNS_RC_NOREC) { + err_code = DKIM_SIGERROR_NOREC; + } + else if (reply->code == RDNS_RC_NXDOMAIN) { + err_code = DKIM_SIGERROR_NOREC; + } g_set_error (&err, DKIM_ERROR, - DKIM_SIGERROR_NOKEY, + err_code, "dns request to %s failed: %s", cbdata->ctx->dns_key, rdns_strerror (reply->code)); diff --git a/src/libserver/dkim.h b/src/libserver/dkim.h index 35f298807..b2ff151ad 100644 --- a/src/libserver/dkim.h +++ b/src/libserver/dkim.h @@ -36,7 +36,7 @@ #define DKIM_SIGERROR_EXPIRED 3 /* signature expired */ #define DKIM_SIGERROR_FUTURE 4 /* signature in the future */ #define DKIM_SIGERROR_TIMESTAMPS 5 /* x= < t= */ -#define DKIM_SIGERROR_UNUSED 6 /* OBSOLETE */ +#define DKIM_SIGERROR_NOREC 6 /* No record */ #define DKIM_SIGERROR_INVALID_HC 7 /* c= invalid (header) */ #define DKIM_SIGERROR_INVALID_BC 8 /* c= invalid (body) */ #define DKIM_SIGERROR_MISSING_A 9 /* a= missing */ @@ -83,6 +83,7 @@ #define DKIM_TRYAGAIN 2 /* try again later */ #define DKIM_NOTFOUND 3 /* requested record not found */ #define DKIM_RECORD_ERROR 4 /* error requesting record */ +#define DKIM_PERM_ERROR 5 /* permanent error */ #define DKIM_CANON_SIMPLE 0 /* as specified in DKIM spec */ #define DKIM_CANON_RELAXED 1 /* as specified in DKIM spec */ diff --git a/src/plugins/dkim_check.c b/src/plugins/dkim_check.c index 58ae6486f..9911a8291 100644 --- a/src/plugins/dkim_check.c +++ b/src/plugins/dkim_check.c @@ -20,6 +20,7 @@ * - 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_tempfail (string): symbol to insert in case of temporary fail (default: 'R_DKIM_TEMPFAIL') + * - symbol_permfail (string): symbol to insert in case of permanent failure (default: 'R_DKIM_PERMFAIL') * - symbol_na (string): symbol to insert in case of no signing (default: 'R_DKIM_NA') * - whitelist (map): map of whitelisted networks * - domains (map): map of domains to check @@ -42,6 +43,7 @@ #define DEFAULT_SYMBOL_TEMPFAIL "R_DKIM_TEMPFAIL" #define DEFAULT_SYMBOL_ALLOW "R_DKIM_ALLOW" #define DEFAULT_SYMBOL_NA "R_DKIM_NA" +#define DEFAULT_SYMBOL_PERMFAIL "R_DKIM_PERMFAIL" #define DEFAULT_CACHE_SIZE 2048 #define DEFAULT_CACHE_MAXAGE 86400 #define DEFAULT_TIME_JITTER 60 @@ -53,6 +55,7 @@ struct dkim_ctx { const gchar *symbol_tempfail; const gchar *symbol_allow; const gchar *symbol_na; + const gchar *symbol_permfail; rspamd_mempool_t *dkim_pool; radix_compressed_t *whitelist_ip; @@ -175,6 +178,15 @@ dkim_module_init (struct rspamd_config *cfg, struct module_ctx **ctx) 0, NULL, 0); + rspamd_rcl_add_doc_by_path (cfg, + "dkim", + "Symbol that is added if permanent failure encountered", + "symbol_permfail", + UCL_STRING, + NULL, + 0, + NULL, + 0); rspamd_rcl_add_doc_by_path (cfg, "dkim", "Size of DKIM keys cache", @@ -303,6 +315,13 @@ dkim_module_config (struct rspamd_config *cfg) else { dkim_module_ctx->symbol_na = DEFAULT_SYMBOL_NA; } + if ((value = + rspamd_config_get_module_opt (cfg, "dkim", "symbol_permfail")) != NULL) { + dkim_module_ctx->symbol_permfail = ucl_obj_tostring (value); + } + else { + dkim_module_ctx->symbol_permfail = DEFAULT_SYMBOL_PERMFAIL; + } if ((value = rspamd_config_get_module_opt (cfg, "dkim", "dkim_cache_size")) != NULL) { @@ -401,6 +420,12 @@ dkim_module_config (struct rspamd_config *cfg) NULL, NULL, SYMBOL_TYPE_VIRTUAL|SYMBOL_TYPE_FINE, cb_id); + rspamd_symbols_cache_add_symbol (cfg->cache, + dkim_module_ctx->symbol_permfail, + 0, + NULL, NULL, + SYMBOL_TYPE_VIRTUAL|SYMBOL_TYPE_FINE, + cb_id); rspamd_symbols_cache_add_symbol (cfg->cache, dkim_module_ctx->symbol_tempfail, 0, @@ -533,9 +558,9 @@ dkim_module_parse_strict (const gchar *value, gint *allow, gint *deny) static void dkim_module_check (struct dkim_check_result *res) { - gboolean all_done = TRUE, got_allow = FALSE; + gboolean all_done = TRUE; const gchar *strict_value; - struct dkim_check_result *first, *cur, *sel = NULL; + struct dkim_check_result *first, *cur = NULL; first = res->first; @@ -560,8 +585,13 @@ dkim_module_check (struct dkim_check_result *res) } } } + } - if (cur->res == -1 || cur->key == NULL) { + DL_FOREACH (first, cur) { + if (cur->ctx == NULL) { + continue; + } + if (cur->res == -1) { /* Still need a key */ all_done = FALSE; } @@ -569,51 +599,36 @@ dkim_module_check (struct dkim_check_result *res) if (all_done) { DL_FOREACH (first, cur) { + const gchar *symbol = NULL; + GList *messages = NULL; + int symbol_weight = 1; if (cur->ctx == NULL) { continue; } - - if (cur->res == DKIM_CONTINUE) { - rspamd_task_insert_result (cur->task, - dkim_module_ctx->symbol_allow, - cur->mult_allow * 1.0, - g_list_prepend (NULL, - rspamd_mempool_strdup (cur->task->task_pool, - rspamd_dkim_get_domain (cur->ctx)))); - got_allow = TRUE; - sel = NULL; + if (cur->res == DKIM_REJECT) { + symbol = dkim_module_ctx->symbol_reject; + symbol_weight = cur->mult_deny * 1.0; } - else if (!got_allow) { - if (sel == NULL) { - sel = cur; - } - else if (sel->res == DKIM_TRYAGAIN && cur->res != DKIM_TRYAGAIN) { - sel = cur; - } + else if (cur->res == DKIM_CONTINUE) { + symbol = dkim_module_ctx->symbol_allow; + symbol_weight = cur->mult_allow * 1.0; + } + else if (cur->res == DKIM_PERM_ERROR) { + symbol = dkim_module_ctx->symbol_permfail; + } + else if (cur->res == DKIM_TRYAGAIN) { + symbol = dkim_module_ctx->symbol_tempfail; + } + if (symbol != NULL) { + messages = g_list_prepend (messages, + rspamd_mempool_strdup (cur->task->task_pool, + rspamd_dkim_get_domain (cur->ctx))); + rspamd_task_insert_result (cur->task, + symbol, + 1.0, + messages); } } - } - - if (sel != NULL) { - if (sel->res == DKIM_REJECT) { - rspamd_task_insert_result (sel->task, - dkim_module_ctx->symbol_reject, - sel->mult_deny * 1.0, - g_list_prepend (NULL, - rspamd_mempool_strdup (sel->task->task_pool, - rspamd_dkim_get_domain (sel->ctx)))); - } - else { - rspamd_task_insert_result (sel->task, - dkim_module_ctx->symbol_tempfail, - 1.0, - g_list_prepend (NULL, - rspamd_mempool_strdup (sel->task->task_pool, - rspamd_dkim_get_domain (sel->ctx)))); - } - } - - if (all_done) { rspamd_session_watcher_pop (res->task->s, res->w); } } @@ -650,7 +665,12 @@ dkim_module_key_handler (rspamd_dkim_key_t *key, rspamd_dkim_get_dns_key (ctx), err); if (err != NULL) { - res->res = DKIM_TRYAGAIN; + if (err->code == DKIM_SIGERROR_NOKEY) { + res->res = DKIM_TRYAGAIN; + } + else { + res->res = DKIM_PERM_ERROR; + } } } -- 2.39.5